Clear Content Copy

Copy from Widevine repository of http://go/wvgerrit/13841

This CL adds a nonblocking CopyBuffer to OEMCrypto, its unit tests,
and plumbs it up to the cdm CryptoSession and CdmEngine.

b/19543782

Change-Id: I4c88bd2f8d7f67ecccb549c1934b7c0da15a8429
This commit is contained in:
Fred Gylys-Colwell
2015-03-31 09:15:38 -07:00
parent 582eb32661
commit a7d2f57bfb
7 changed files with 150 additions and 64 deletions

View File

@@ -13,6 +13,9 @@ enum SecurityLevel { kLevelDefault, kLevel3 };
If one level is not available, the other will be used instead. */
OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session,
SecurityLevel level);
OEMCryptoResult OEMCrypto_CopyBuffer(
SecurityLevel level, const uint8_t* data_addr, size_t data_length,
OEMCrypto_DestBufferDesc* out_buffer, uint8_t subsample_flags);
OEMCryptoResult OEMCrypto_InstallKeybox(const uint8_t* keybox,
size_t keyBoxLength,
SecurityLevel level);

View File

@@ -637,18 +637,6 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) {
if (!SetDestinationBufferType()) return UNKNOWN_ERROR;
}
AutoLock auto_lock(crypto_lock_);
// Check if key needs to be selected
if (params.is_encrypted) {
if (key_id_ != *params.key_id) {
if (SelectKey(*params.key_id)) {
key_id_ = *params.key_id;
} else {
return NEED_KEY;
}
}
}
OEMCrypto_DestBufferDesc buffer_descriptor;
buffer_descriptor.type =
params.is_secure ? destination_buffer_type_ : OEMCrypto_BufferType_Clear;
@@ -672,10 +660,26 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) {
break;
}
OEMCryptoResult sts = OEMCrypto_DecryptCTR(
oec_session_id_, params.encrypt_buffer, params.encrypt_length,
params.is_encrypted, &(*params.iv).front(), params.block_offset,
&buffer_descriptor, params.subsample_flags);
OEMCryptoResult sts;
if (params.is_encrypted) {
AutoLock auto_lock(crypto_lock_);
// Check if key needs to be selected
if (key_id_ != *params.key_id) {
if (SelectKey(*params.key_id)) {
key_id_ = *params.key_id;
} else {
return NEED_KEY;
}
}
sts = OEMCrypto_DecryptCTR(
oec_session_id_, params.encrypt_buffer, params.encrypt_length,
params.is_encrypted, &(*params.iv).front(), params.block_offset,
&buffer_descriptor, params.subsample_flags);
} else {
sts = OEMCrypto_CopyBuffer(requested_security_level_,
params.encrypt_buffer, params.encrypt_length,
&buffer_descriptor, params.subsample_flags);
}
switch (sts) {
case OEMCrypto_SUCCESS:

View File

@@ -322,6 +322,7 @@ class Adapter {
LOOKUP(GetHDCPCapability_V9, OEMCrypto_GetHDCPCapability_V9);
} else {
LOOKUP(QueryKeyControl, OEMCrypto_QueryKeyControl);
LOOKUP(CopyBuffer, OEMCrypto_CopyBuffer);
LOOKUP(GetHDCPCapability, OEMCrypto_GetHDCPCapability);
LOOKUP(IsAntiRollbackHwPresent, OEMCrypto_IsAntiRollbackHwPresent);
LOOKUP(GetNumberOfOpenSessions, OEMCrypto_GetNumberOfOpenSessions);
@@ -488,6 +489,16 @@ OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session,
return kAdapter->OpenSession(session, level);
}
OEMCryptoResult OEMCrypto_CopyBuffer(
SecurityLevel level, const uint8_t* data_addr, size_t data_length,
OEMCrypto_DestBufferDesc* out_buffer, uint8_t subsample_flags) {
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
const FunctionPointers* fcn = kAdapter->get(level);
if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION;
if (fcn->version < 10) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
return fcn->CopyBuffer(data_addr, data_length, out_buffer, subsample_flags);
}
OEMCryptoResult OEMCrypto_InstallKeybox(const uint8_t* keybox,
size_t keyBoxLength,
SecurityLevel level) {
@@ -587,7 +598,6 @@ OEMCryptoResult OEMCrypto_GetMaxNumberOfSessions(SecurityLevel level,
if (fcn->version < 10) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
return fcn->GetMaxNumberOfSessions(maximum);
}
} // namespace wvcdm
extern "C" OEMCryptoResult OEMCrypto_Initialize(void) {
@@ -710,6 +720,13 @@ extern "C" OEMCryptoResult OEMCrypto_DecryptCTR(
subsample_flags);
}
extern "C" OEMCryptoResult OEMCrypto_CopyBuffer(
const uint8_t* data_addr, size_t data_length,
OEMCrypto_DestBufferDesc* out_buffer, uint8_t subsample_flags) {
return OEMCrypto_CopyBuffer(kLevelDefault, data_addr, data_length, out_buffer,
subsample_flags);
}
extern "C" OEMCryptoResult OEMCrypto_WrapKeybox(const uint8_t* keybox,
size_t keyBoxLength,
uint8_t* wrappedKeybox,

View File

@@ -1065,15 +1065,13 @@ bool SessionContext::DecryptMessage(const std::vector<uint8_t>& key,
OEMCryptoResult SessionContext::DecryptCTR(
const uint8_t* iv, size_t block_offset, const uint8_t* cipher_data,
size_t cipher_data_length, bool is_encrypted, uint8_t* clear_data,
BufferType buffer_type) {
OEMCryptoBufferType buffer_type) {
// If the data is clear, we do not need a current key selected.
if (!is_encrypted) {
if (buffer_type != kBufferTypeDirect) {
memcpy(reinterpret_cast<uint8_t*>(clear_data), cipher_data,
cipher_data_length);
return OEMCrypto_SUCCESS;
}
// For reference implementation, we quietly drop the clear direct video.
if (buffer_type == OEMCrypto_BufferType_Direct)
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
memcpy(reinterpret_cast<uint8_t*>(clear_data), cipher_data,
cipher_data_length);
return OEMCrypto_SUCCESS;
}
@@ -1084,7 +1082,7 @@ OEMCryptoResult SessionContext::DecryptCTR(
}
const KeyControlBlock& control = current_content_key()->control();
if (control.control_bits() & kControlDataPathSecure) {
if (!ce_->closed_platform() && buffer_type == kBufferTypeClear) {
if (!ce_->closed_platform() && buffer_type == OEMCrypto_BufferType_Clear) {
LOGE("[DecryptCTR(): Secure key with insecure buffer]");
return OEMCrypto_ERROR_DECRYPT_FAILED;
}
@@ -1129,12 +1127,12 @@ OEMCryptoResult SessionContext::DecryptCTR(
return OEMCrypto_ERROR_DECRYPT_FAILED;
}
if (buffer_type == kBufferTypeDirect) {
if (buffer_type == OEMCrypto_BufferType_Direct) {
// For reference implementation, we quietly drop the decrypted direct video.
return OEMCrypto_SUCCESS;
}
if (buffer_type == kBufferTypeSecure) {
if (buffer_type == OEMCrypto_BufferType_Secure) {
// For reference implementation, we also quietly drop secure data.
return OEMCrypto_SUCCESS;
}

View File

@@ -20,12 +20,6 @@
namespace wvoec_mock {
enum BufferType {
kBufferTypeClear,
kBufferTypeSecure,
kBufferTypeDirect
};
class SessionContext;
class CryptoEngine;
class UsageTable;
@@ -117,7 +111,8 @@ class SessionContext {
OEMCryptoResult DecryptCTR(const uint8_t* iv, size_t block_offset,
const uint8_t* cipher_data,
size_t cipher_data_length, bool is_encrypted,
uint8_t* clear_data, BufferType buffer_type);
uint8_t* clear_data,
OEMCryptoBufferType buffer_type);
OEMCryptoResult Generic_Encrypt(const uint8_t* in_buffer,
size_t buffer_length, const uint8_t* iv,

View File

@@ -522,6 +522,40 @@ OEMCryptoResult OEMCrypto_SelectKey(const OEMCrypto_SESSION session,
return OEMCrypto_SUCCESS;
}
OEMCryptoResult SetDestination(OEMCrypto_DestBufferDesc* out_buffer,
size_t data_length, uint8_t** destination,
size_t* max_length) {
switch (out_buffer->type) {
case OEMCrypto_BufferType_Clear:
*destination = out_buffer->buffer.clear.address;
*max_length = out_buffer->buffer.clear.max_length;
break;
case OEMCrypto_BufferType_Secure:
*destination =
reinterpret_cast<uint8_t*>(out_buffer->buffer.secure.handle)
+ out_buffer->buffer.secure.offset;
*max_length = out_buffer->buffer.secure.max_length;
break;
default:
case OEMCrypto_BufferType_Direct:
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
break;
}
if (out_buffer->type != OEMCrypto_BufferType_Direct
&& *max_length < data_length) {
LOGE("[SetDestination(): OEMCrypto_ERROR_SHORT_BUFFER]");
return OEMCrypto_ERROR_SHORT_BUFFER;
}
if ((out_buffer->type != OEMCrypto_BufferType_Direct)
&& (*destination == NULL)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
return OEMCrypto_SUCCESS;
}
extern "C"
OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
const uint8_t* data_addr,
@@ -535,33 +569,16 @@ OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
LOGI("-- OEMCryptoResult OEMCrypto_DecryptCTR"
"(OEMCrypto_SESSION session,\n");
}
wvoec_mock::BufferType buffer_type = kBufferTypeDirect;
if (data_addr == NULL || data_length == 0 ||
iv == NULL || out_buffer == NULL) {
LOGE("[OEMCrypto_DecryptCTR(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
uint8_t* destination = NULL;
size_t max_length = 0;
switch (out_buffer->type) {
case OEMCrypto_BufferType_Clear:
buffer_type = kBufferTypeClear;
destination = out_buffer->buffer.clear.address;
max_length = out_buffer->buffer.clear.max_length;
break;
case OEMCrypto_BufferType_Secure:
buffer_type = kBufferTypeSecure;
destination =
reinterpret_cast<uint8_t*>(out_buffer->buffer.secure.handle)
+ out_buffer->buffer.secure.offset;
max_length = out_buffer->buffer.secure.max_length;
break;
default:
case OEMCrypto_BufferType_Direct:
buffer_type = kBufferTypeDirect;
destination = NULL;
break;
}
if (buffer_type != kBufferTypeDirect && max_length < data_length) {
LOGE("[OEMCrypto_DecryptCTR(): OEMCrypto_ERROR_SHORT_BUFFER]");
return OEMCrypto_ERROR_SHORT_BUFFER;
}
OEMCryptoResult sts = SetDestination(out_buffer, data_length, &destination,
&max_length);
if (sts != OEMCrypto_SUCCESS) return sts;
#ifndef NDEBUG
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
@@ -576,14 +593,31 @@ OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
return OEMCrypto_ERROR_INVALID_SESSION;
}
if (data_addr == NULL || data_length == 0 ||
iv == NULL || out_buffer == NULL) {
LOGE("[OEMCrypto_DecryptCTR(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return session_ctx->DecryptCTR(iv, block_offset, data_addr, data_length,
is_encrypted, destination,
out_buffer->type);
}
extern "C"
OEMCryptoResult OEMCrypto_CopyBuffer(const uint8_t *data_addr,
size_t data_length,
OEMCrypto_DestBufferDesc* out_buffer,
uint8_t subsample_flags) {
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
LOGI("-- OEMCryptoResult OEMCrypto_CopyBuffer(..)\n");
}
if (data_addr == NULL || out_buffer == NULL) {
LOGE("[OEMCrypto_CopyBuffer(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
uint8_t* destination = NULL;
size_t max_length = 0;
OEMCryptoResult sts = SetDestination(out_buffer, data_length, &destination,
&max_length);
if (sts != OEMCrypto_SUCCESS) return sts;
return session_ctx->DecryptCTR(iv, block_offset, data_addr, data_length,
is_encrypted, destination, buffer_type);
memcpy(destination, data_addr, data_length);
return OEMCrypto_SUCCESS;
}
extern "C"

View File

@@ -1928,6 +1928,41 @@ TEST_F(OEMCryptoClientTest, GenerateDerivedKeys) {
s.GenerateDerivedKeys();
}
TEST_F(OEMCryptoClientTest, ClearCopyTest) {
const int kDataSize = 256;
uint8_t input_buffer[kDataSize];
OEMCrypto_GetRandom(input_buffer, sizeof(input_buffer));
uint8_t output_buffer[kDataSize];
OEMCrypto_DestBufferDesc dest_buffer;
dest_buffer.type = OEMCrypto_BufferType_Clear;
dest_buffer.buffer.clear.address = output_buffer;
dest_buffer.buffer.clear.max_length = sizeof(output_buffer);
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_CopyBuffer(input_buffer, sizeof(input_buffer),
&dest_buffer, OEMCrypto_FirstSubsample
| OEMCrypto_LastSubsample));
ASSERT_EQ(0, memcmp(input_buffer, output_buffer, sizeof(input_buffer)));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
OEMCrypto_CopyBuffer(NULL, sizeof(input_buffer),
&dest_buffer, OEMCrypto_FirstSubsample
| OEMCrypto_LastSubsample));
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
OEMCrypto_CopyBuffer(input_buffer, sizeof(input_buffer),
NULL, OEMCrypto_FirstSubsample
| OEMCrypto_LastSubsample));
dest_buffer.buffer.clear.address = NULL;
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
OEMCrypto_CopyBuffer(input_buffer, sizeof(input_buffer),
&dest_buffer, OEMCrypto_FirstSubsample
| OEMCrypto_LastSubsample));
dest_buffer.buffer.clear.address = output_buffer;
dest_buffer.buffer.clear.max_length = sizeof(output_buffer) - 1;
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
OEMCrypto_CopyBuffer(input_buffer, sizeof(input_buffer),
&dest_buffer, OEMCrypto_FirstSubsample
| OEMCrypto_LastSubsample));
}
//
// AddKey Tests
//