Full decrypt path testing
Merge from master branch of Widevine repo of http://go/wvgerrit/66080 Merge from oemcrypto-v15 branch of Widevine repo of http://go/wvgerrit/64002 This CL updates OEMCrypto reference code and unit tests to support full decrypt path testing. Test: unit tests Test: tested as part of http://go/ag/5501993 Bug: 34078913 Change-Id: Ia67374599d6619698a336f41513068ad04294e7f
This commit is contained in:
@@ -55,6 +55,7 @@ OEMCryptoResult OEMCrypto_CreateOldUsageEntry(SecurityLevel level,
|
||||
uint32_t OEMCrypto_GetAnalogOutputFlags(SecurityLevel level);
|
||||
const char* OEMCrypto_BuildInformation(SecurityLevel level);
|
||||
uint32_t OEMCrypto_ResourceRatingTier(SecurityLevel level);
|
||||
uint32_t OEMCrypto_SupportsDecryptHash(SecurityLevel level);
|
||||
} // namespace wvcdm
|
||||
|
||||
/* The following functions are deprecated in OEMCrypto v13. They are defined
|
||||
|
||||
@@ -277,6 +277,15 @@ typedef OEMCryptoResult (*L1_CreateOldUsageEntry_t)(
|
||||
typedef uint32_t (*L1_GetAnalogOutputFlags_t)(void);
|
||||
typedef const char* (*L1_BuildInformation_t)(void);
|
||||
typedef uint32_t (*L1_ResourceRatingTier_t)(void);
|
||||
typedef uint32_t (*L1_SupportsDecryptHash_t)(void);
|
||||
typedef OEMCryptoResult (*L1_InitializeDecryptHash_t)(
|
||||
OEMCrypto_SESSION session);
|
||||
typedef OEMCryptoResult (*L1_SetDecryptHash_t)(OEMCrypto_SESSION session,
|
||||
uint32_t frame_number,
|
||||
const uint8_t* hash,
|
||||
size_t hash_length);
|
||||
typedef OEMCryptoResult (*L1_GetHashErrorCode_t)(OEMCrypto_SESSION session,
|
||||
uint32_t* failed_frame_number);
|
||||
|
||||
struct FunctionPointers {
|
||||
uint32_t version;
|
||||
@@ -347,6 +356,10 @@ struct FunctionPointers {
|
||||
L1_GetAnalogOutputFlags_t GetAnalogOutputFlags;
|
||||
L1_BuildInformation_t BuildInformation;
|
||||
L1_ResourceRatingTier_t ResourceRatingTier;
|
||||
L1_SupportsDecryptHash_t SupportsDecryptHash;
|
||||
L1_InitializeDecryptHash_t InitializeDecryptHash;
|
||||
L1_SetDecryptHash_t SetDecryptHash;
|
||||
L1_GetHashErrorCode_t GetHashErrorCode;
|
||||
|
||||
L1_LoadKeys_V8_t LoadKeys_V8;
|
||||
L1_GenerateRSASignature_V8_t GenerateRSASignature_V8;
|
||||
@@ -766,6 +779,10 @@ class Adapter {
|
||||
LOOKUP_ALL(13, UpdateUsageEntry, OEMCrypto_UpdateUsageEntry);
|
||||
LOOKUP( 9, 12, UpdateUsageTable, OEMCrypto_UpdateUsageTable);
|
||||
LOOKUP_ALL( 8, WrapKeybox, OEMCrypto_WrapKeybox);
|
||||
LOOKUP_ALL(15, SupportsDecryptHash, OEMCrypto_SupportsDecryptHash);
|
||||
LOOKUP_ALL(15, InitializeDecryptHash, OEMCrypto_InitializeDecryptHash);
|
||||
LOOKUP_ALL(15, SetDecryptHash, OEMCrypto_SetDecryptHash);
|
||||
LOOKUP_ALL(15, GetHashErrorCode, OEMCrypto_GetHashErrorCode);
|
||||
// clang-format on
|
||||
|
||||
// If the keybox or oem certificate is valid, we are done.
|
||||
@@ -902,6 +919,10 @@ class Adapter {
|
||||
level3_.MoveEntry = Level3_MoveEntry;
|
||||
level3_.CopyOldUsageEntry = Level3_CopyOldUsageEntry;
|
||||
level3_.CreateOldUsageEntry = Level3_CreateOldUsageEntry;
|
||||
// TODO(srujzs) level3_.SupportsDecryptHash = Level3_SupportsDecryptHash;
|
||||
// TODO(srujzs) level3_.InitializeDecryptHash = Level3_InitializeDecryptHash;
|
||||
// TODO(srujzs) level3_.SetDecryptHash = Level3_SetDecryptHash;
|
||||
// TODO(srujzs) level3_.GetHashErrorCode = Level3_GetHashErrorCode;
|
||||
// clang-format on
|
||||
|
||||
level3_.version = Level3_APIVersion();
|
||||
@@ -1128,6 +1149,15 @@ uint32_t OEMCrypto_ResourceRatingTier(SecurityLevel level) {
|
||||
return fcn->ResourceRatingTier();
|
||||
}
|
||||
|
||||
uint32_t OEMCrypto_SupportsDecryptHash(SecurityLevel level) {
|
||||
if (!gAdapter.get()) return OEMCrypto_Hash_Not_Supported;
|
||||
const FunctionPointers* fcn = gAdapter->GetFunctionPointers(level);
|
||||
if (!fcn) return OEMCrypto_Hash_Not_Supported;
|
||||
if (fcn->version < 14) return OEMCrypto_Hash_Not_Supported;
|
||||
if (fcn->BuildInformation == NULL) return OEMCrypto_Hash_Not_Supported;
|
||||
return fcn->SupportsDecryptHash();
|
||||
}
|
||||
|
||||
bool OEMCrypto_SupportsUsageTable(SecurityLevel level) {
|
||||
if (!gAdapter.get()) return false;
|
||||
const FunctionPointers* fcn = gAdapter->GetFunctionPointers(level);
|
||||
@@ -2307,3 +2337,42 @@ extern "C" OEMCryptoResult OEMCrypto_CreateOldUsageEntry(
|
||||
time_since_last_decrypt, status, server_mac_key, client_mac_key, pst,
|
||||
pst_length);
|
||||
}
|
||||
|
||||
extern "C" uint32_t OEMCrypto_SupportsDecryptHash(){
|
||||
return OEMCrypto_SupportsDecryptHash(kLevelDefault);
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_InitializeDecryptHash(
|
||||
OEMCrypto_SESSION session) {
|
||||
if (!gAdapter.get()) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
LevelSession pair = gAdapter->GetSession(session);
|
||||
if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
if (pair.fcn->InitializeDecryptHash == NULL) {
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
return pair.fcn->InitializeDecryptHash(pair.session);
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_SetDecryptHash(OEMCrypto_SESSION session,
|
||||
uint32_t frame_number,
|
||||
const uint8_t* hash,
|
||||
size_t hash_length) {
|
||||
if (!gAdapter.get()) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
LevelSession pair = gAdapter->GetSession(session);
|
||||
if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
if (pair.fcn->SetDecryptHash == NULL) {
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
return pair.fcn->SetDecryptHash(pair.session, frame_number, hash, hash_length);
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_GetHashErrorCode(OEMCrypto_SESSION session,
|
||||
uint32_t* failed_frame_number) {
|
||||
if (!gAdapter.get()) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
LevelSession pair = gAdapter->GetSession(session);
|
||||
if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
if (pair.fcn->GetHashErrorCode == NULL) {
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
return pair.fcn->GetHashErrorCode(pair.session, failed_frame_number);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ const uint32_t kControlObserveDataPath = (1<<31);
|
||||
const uint32_t kControlObserveHDCP = (1<<30);
|
||||
const uint32_t kControlObserveCGMS = (1<<29);
|
||||
const uint32_t kControlRequireAntiRollbackHardware = (1<<28);
|
||||
const uint32_t kControlAllowHashVerification = (1<<24);
|
||||
const uint32_t kSharedLicense = (1<<23);
|
||||
const uint32_t kControlSRMVersionRequired = (1<<22);
|
||||
const uint32_t kControlDisableAnalogOutput = (1<<21);
|
||||
|
||||
@@ -1617,4 +1617,52 @@ extern "C" OEMCryptoResult OEMCrypto_CreateOldUsageEntry(
|
||||
pst_length);
|
||||
}
|
||||
|
||||
extern "C" uint32_t OEMCrypto_SupportsDecryptHash() {
|
||||
return OEMCrypto_CRC_Clear_Buffer;
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_InitializeDecryptHash(
|
||||
OEMCrypto_SESSION session) {
|
||||
if (!crypto_engine) {
|
||||
LOGE("OEMCrypto_InitializeDecryptHash: OEMCrypto Not Initialized.");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||
if (!session_ctx || !session_ctx->isValid()) {
|
||||
LOGE("[OEMCrypto_InitializeDecryptHash(): ERROR_INVALID_SESSION]");
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
return session_ctx->InitializeDecryptHash();
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_SetDecryptHash(OEMCrypto_SESSION session,
|
||||
uint32_t frame_number,
|
||||
const uint8_t* hash,
|
||||
size_t hash_length) {
|
||||
if (!crypto_engine) {
|
||||
LOGE("OEMCrypto_SetDecryptHash: OEMCrypto Not Initialized.");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||
if (!session_ctx || !session_ctx->isValid()) {
|
||||
LOGE("[OEMCrypto_SetDecryptHash(): ERROR_INVALID_SESSION]");
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
return session_ctx->SetDecryptHash(frame_number, hash, hash_length);
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_GetHashErrorCode(
|
||||
OEMCrypto_SESSION session, uint32_t* failed_frame_number) {
|
||||
if (!crypto_engine) {
|
||||
LOGE("OEMCrypto_GetHashErrorCode: OEMCrypto Not Initialized.");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||
if (!session_ctx || !session_ctx->isValid()) {
|
||||
LOGE("[OEMCrypto_GetHashErrorCode(): ERROR_INVALID_SESSION]");
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
return session_ctx->GetHashErrorCode(failed_frame_number);
|
||||
}
|
||||
|
||||
} // namespace wvoec_ref
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "oemcrypto_types.h"
|
||||
#include "disallow_copy_and_assign.h"
|
||||
#include "string_conversions.h"
|
||||
#include "wvcrc32.h"
|
||||
|
||||
static const int kPssSaltLength = 20;
|
||||
|
||||
@@ -1167,6 +1168,7 @@ OEMCryptoResult SessionContext::SelectContentKey(
|
||||
LOGE("No key matches key id");
|
||||
return OEMCrypto_ERROR_NO_CONTENT_KEY;
|
||||
}
|
||||
compute_hash_ = false;
|
||||
content_key->set_ctr_mode(cipher_mode == OEMCrypto_CipherMode_CTR);
|
||||
current_content_key_ = content_key;
|
||||
const KeyControlBlock& control = current_content_key()->control();
|
||||
@@ -1284,6 +1286,29 @@ OEMCryptoResult SessionContext::DecryptCENC(
|
||||
const OEMCrypto_CENCEncryptPatternDesc* pattern, const uint8_t* cipher_data,
|
||||
size_t cipher_data_length, bool is_encrypted, uint8_t* clear_data,
|
||||
OEMCryptoBufferType buffer_type) {
|
||||
OEMCryptoResult result =
|
||||
ChooseDecrypt(iv, block_offset, pattern, cipher_data, cipher_data_length,
|
||||
is_encrypted, clear_data, buffer_type);
|
||||
if (compute_hash_) {
|
||||
if (current_content_key() == NULL ||
|
||||
(current_content_key()->control().control_bits() &
|
||||
wvoec::kControlAllowHashVerification) == 0) {
|
||||
// This should not happen: this check should already have occured in
|
||||
// InitializeDecryptHash or the hash should have been discarded in
|
||||
// SelectContentKey. But it doesn't hurt to double check.
|
||||
LOGE("[DecryptCENC(): OEMCrypto_ERROR_UNKNOWN_FAILURE]");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
current_hash_ = wvcrc32Cont(clear_data, cipher_data_length, current_hash_);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
OEMCryptoResult SessionContext::ChooseDecrypt(
|
||||
const uint8_t* iv, size_t block_offset,
|
||||
const OEMCrypto_CENCEncryptPatternDesc* pattern, const uint8_t* cipher_data,
|
||||
size_t cipher_data_length, bool is_encrypted, uint8_t* clear_data,
|
||||
OEMCryptoBufferType buffer_type) {
|
||||
// If the data is clear, we do not need a current key selected.
|
||||
if (!is_encrypted) {
|
||||
if (buffer_type != OEMCrypto_BufferType_Direct) {
|
||||
@@ -1501,4 +1526,62 @@ OEMCryptoResult SessionContext::DecryptCTR(const uint8_t* key_u8,
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
OEMCryptoResult SessionContext::InitializeDecryptHash() {
|
||||
// Check there is a content key, and it is allowed.
|
||||
if (current_content_key() == NULL ||
|
||||
(current_content_key()->control().control_bits() &
|
||||
wvoec::kControlAllowHashVerification) == 0) {
|
||||
LOGE("[InitializeDecryptHash(): OEMCrypto_ERROR_UNKNOWN_FAILURE]");
|
||||
compute_hash_ = false;
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
compute_hash_ = true;
|
||||
current_hash_ = wvcrc32Init();
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
OEMCryptoResult SessionContext::SetDecryptHash(uint32_t frame_number,
|
||||
const uint8_t* hash,
|
||||
size_t hash_length) {
|
||||
// Check there is a content key, and it is allowed.
|
||||
if (current_content_key() == NULL ||
|
||||
(current_content_key()->control().control_bits() &
|
||||
wvoec::kControlAllowHashVerification) == 0) {
|
||||
LOGE("[SetDecryptHash(): OEMCrypto_ERROR_UNKNOWN_FAILURE]");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
if (!compute_hash_) {
|
||||
// This would happen if somebody computes the hash, and then changes keys.
|
||||
LOGE("[SetDecryptHash(): OEMCrypto_ERROR_UNKNOWN_FAILURE]");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
compute_hash_ = false;
|
||||
if (hash_length < sizeof(uint32_t)) {
|
||||
LOGE("[SetDecryptHash(): short buffer]");
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
if (hash_length > sizeof(uint32_t)) {
|
||||
LOGE("[SetDecryptHash(): long buffer]");
|
||||
return OEMCrypto_ERROR_BUFFER_TOO_LARGE;
|
||||
}
|
||||
uint32_t given_hash = *reinterpret_cast<const uint32_t*>(hash);
|
||||
if (current_hash_ != given_hash) {
|
||||
LOGE("CRC for frame %d is %08x, should be %08x\n", frame_number,
|
||||
current_hash_, given_hash);
|
||||
// Update bad_frame_number_ only if this is the first bad frame.
|
||||
if (hash_error_ == OEMCrypto_SUCCESS) bad_frame_number_ = frame_number;
|
||||
hash_error_ = OEMCrypto_ERROR_BAD_HASH;
|
||||
}
|
||||
// Return success if the hash was compared, even if there was an error.
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
OEMCryptoResult SessionContext::GetHashErrorCode(
|
||||
uint32_t* failed_frame_number) {
|
||||
if (failed_frame_number == NULL) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
if (hash_error_ != OEMCrypto_SUCCESS)
|
||||
*failed_frame_number = bad_frame_number_;
|
||||
return hash_error_;
|
||||
}
|
||||
|
||||
} // namespace wvoec_ref
|
||||
|
||||
@@ -73,7 +73,11 @@ class SessionContext {
|
||||
allowed_schemes_(kSign_RSASSA_PSS),
|
||||
usage_entry_(NULL),
|
||||
srm_requirements_status_(NoSRMVersion),
|
||||
usage_entry_status_(kNoUsageEntry) {}
|
||||
usage_entry_status_(kNoUsageEntry),
|
||||
compute_hash_(false),
|
||||
current_hash_(0),
|
||||
bad_frame_number_(0),
|
||||
hash_error_(OEMCrypto_SUCCESS) {}
|
||||
virtual ~SessionContext();
|
||||
|
||||
bool isValid() { return valid_; }
|
||||
@@ -148,6 +152,11 @@ class SessionContext {
|
||||
virtual bool QueryKeyControlBlock(const KeyId& key_id, uint32_t* data);
|
||||
virtual OEMCryptoResult SelectContentKey(const KeyId& key_id,
|
||||
OEMCryptoCipherMode cipher_mode);
|
||||
virtual OEMCryptoResult InitializeDecryptHash();
|
||||
virtual OEMCryptoResult SetDecryptHash(uint32_t frame_number,
|
||||
const uint8_t* hash,
|
||||
size_t hash_length);
|
||||
virtual OEMCryptoResult GetHashErrorCode(uint32_t* failed_frame_number);
|
||||
const Key* current_content_key(void) { return current_content_key_; }
|
||||
void set_mac_key_server(const std::vector<uint8_t>& mac_key_server) {
|
||||
mac_key_server_ = mac_key_server;
|
||||
@@ -200,6 +209,12 @@ class SessionContext {
|
||||
OEMCryptoResult CheckStatusOnline(uint32_t nonce, uint32_t control);
|
||||
// Check that the usage entry status is valid for offline use.
|
||||
OEMCryptoResult CheckStatusOffline(uint32_t nonce, uint32_t control);
|
||||
OEMCryptoResult ChooseDecrypt(const uint8_t* iv, size_t block_offset,
|
||||
const OEMCrypto_CENCEncryptPatternDesc* pattern,
|
||||
const uint8_t* cipher_data,
|
||||
size_t cipher_data_length, bool is_encrypted,
|
||||
uint8_t* clear_data,
|
||||
OEMCryptoBufferType buffer_type);
|
||||
OEMCryptoResult DecryptCBC(const uint8_t* key, const uint8_t* iv,
|
||||
const OEMCrypto_CENCEncryptPatternDesc* pattern,
|
||||
const uint8_t* cipher_data,
|
||||
@@ -239,6 +254,13 @@ class SessionContext {
|
||||
kUsageEntryLoaded, // After loading entry or loading keys.
|
||||
};
|
||||
UsageEntryStatus usage_entry_status_;
|
||||
|
||||
// These are used when doing full decrypt path testing.
|
||||
bool compute_hash_; // True if the current frame needs a hash.
|
||||
uint32_t current_hash_; // Running CRC hash of frame.
|
||||
uint32_t bad_frame_number_; // Frame number with bad hash.
|
||||
OEMCryptoResult hash_error_; // Error code for first bad frame.
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(SessionContext);
|
||||
};
|
||||
|
||||
|
||||
@@ -91,6 +91,14 @@ uint32_t wvcrc32(const uint8_t* p_begin, int i_count) {
|
||||
return(wvrunningcrc32(p_begin, i_count, INIT_CRC32));
|
||||
}
|
||||
|
||||
uint32_t wvcrc32Init() {
|
||||
return INIT_CRC32;
|
||||
}
|
||||
|
||||
uint32_t wvcrc32Cont(const uint8_t* p_begin, int i_count, uint32_t prev_crc) {
|
||||
return(wvrunningcrc32(p_begin, i_count, prev_crc));
|
||||
}
|
||||
|
||||
uint32_t wvcrc32n(const uint8_t* p_begin, int i_count) {
|
||||
return htonl(wvrunningcrc32(p_begin, i_count, INIT_CRC32));
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <stdint.h>
|
||||
|
||||
uint32_t wvcrc32(const uint8_t* p_begin, int i_count);
|
||||
uint32_t wvcrc32Init();
|
||||
uint32_t wvcrc32Cont(const uint8_t* p_begin, int i_count, uint32_t prev_crc);
|
||||
|
||||
// Convert to network byte order
|
||||
uint32_t wvcrc32n(const uint8_t* p_begin, int i_count);
|
||||
|
||||
@@ -12,10 +12,11 @@ LOCAL_SRC_FILES:= \
|
||||
oemcrypto_test.cpp \
|
||||
oemcrypto_test_android.cpp \
|
||||
oemcrypto_test_main.cpp \
|
||||
../ref/src/wvcrc.cpp \
|
||||
|
||||
LOCAL_C_INCLUDES += \
|
||||
$(LOCAL_PATH)/../include \
|
||||
$(LOCAL_PATH)/../mock/src \
|
||||
$(LOCAL_PATH)/../ref/src \
|
||||
vendor/widevine/libwvdrmengine/cdm/core/include \
|
||||
vendor/widevine/libwvdrmengine/cdm/util/include \
|
||||
|
||||
|
||||
@@ -98,6 +98,16 @@ void DeviceFeatures::Initialize(bool is_cast_receiver,
|
||||
resource_rating = OEMCrypto_ResourceRatingTier();
|
||||
printf("resource_rating = %d, security leve %s.\n", resource_rating,
|
||||
OEMCrypto_SecurityLevel());
|
||||
uint32_t decrypt_hash_type = OEMCrypto_SupportsDecryptHash();
|
||||
supports_crc = (decrypt_hash_type == OEMCrypto_CRC_Clear_Buffer);
|
||||
if (supports_crc) {
|
||||
printf("Decrypt hashes will be tested.\n");
|
||||
} else {
|
||||
printf("Decrypt hashes will not be tested -- %s.\n",
|
||||
decrypt_hash_type == OEMCrypto_Hash_Not_Supported
|
||||
? "not supported"
|
||||
: "partner defined hash");
|
||||
}
|
||||
switch (derive_key_method) {
|
||||
case NO_METHOD:
|
||||
printf("NO_METHOD: Cannot derive known session keys.\n");
|
||||
|
||||
@@ -28,6 +28,7 @@ class DeviceFeatures {
|
||||
bool supports_rsa_3072; // Device supports 3072 bit RSA keys.
|
||||
bool supports_level_1; // Device supports Level 1 security.
|
||||
uint32_t resource_rating; // Device's resource rating tier.
|
||||
bool supports_crc; // Supported decrypt hash type CRC.
|
||||
uint32_t api_version;
|
||||
OEMCrypto_ProvisioningMethod provisioning_method;
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "oemcrypto_session_tests_helper.h"
|
||||
#include "oemcrypto_types.h"
|
||||
#include "string_conversions.h"
|
||||
#include "wvcrc32.h"
|
||||
|
||||
using ::testing::Bool;
|
||||
using ::testing::Combine;
|
||||
@@ -1658,7 +1659,7 @@ TEST_P(SessionTestRefreshKeyTest, RefreshWithNoSelectKey) {
|
||||
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR(false));
|
||||
}
|
||||
|
||||
// Of only one key control block in the refesh, we update all the keys.
|
||||
// If only one key control block in the refesh, we update all the keys.
|
||||
INSTANTIATE_TEST_CASE_P(TestRefreshAllKeys, SessionTestRefreshKeyTest,
|
||||
Values(std::make_pair(true, 1),
|
||||
std::make_pair(false, 1)));
|
||||
@@ -1668,6 +1669,25 @@ INSTANTIATE_TEST_CASE_P(TestRefreshEachKeys, SessionTestRefreshKeyTest,
|
||||
Values(std::make_pair(true, 4),
|
||||
std::make_pair(false, 4)));
|
||||
|
||||
// If the license does not allow a hash, then we should not compute one.
|
||||
TEST_F(OEMCryptoSessionTests, HashForbiddenAPI15) {
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
|
||||
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(kDuration, 0, 0));
|
||||
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
|
||||
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys());
|
||||
// Either failure, or not supported is allowed.
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, OEMCrypto_InitializeDecryptHash(s.session_id()));
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
OEMCrypto_SelectKey(s.session_id(), s.license().keys[0].key_id,
|
||||
s.license().keys[0].key_id_length,
|
||||
OEMCrypto_CipherMode_CTR));
|
||||
// Still not allowed.
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, OEMCrypto_InitializeDecryptHash(s.session_id()));
|
||||
}
|
||||
|
||||
//
|
||||
// Decrypt Tests
|
||||
//
|
||||
@@ -1868,7 +1888,8 @@ class OEMCryptoSessionTestsDecryptTests
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
|
||||
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(kDuration, 0, 0));
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
s.FillSimpleMessage(kDuration, kControlAllowHashVerification, 0));
|
||||
memcpy(s.license().keys[0].key_data, &key[0], key.size());
|
||||
s.license().keys[0].cipher_mode = cipher_mode_;
|
||||
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
|
||||
@@ -1877,7 +1898,10 @@ class OEMCryptoSessionTestsDecryptTests
|
||||
s.license().keys[0].key_id_length,
|
||||
cipher_mode_);
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
|
||||
if (global_features.supports_crc) {
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
OEMCrypto_InitializeDecryptHash(s.session_id()));
|
||||
}
|
||||
// We decrypt each subsample.
|
||||
vector<uint8_t> output_buffer(total_size_ + 16, 0xaa);
|
||||
const uint8_t *input_buffer = NULL;
|
||||
@@ -1946,6 +1970,18 @@ class OEMCryptoSessionTestsDecryptTests
|
||||
EXPECT_EQ(0xaa, output_buffer[total_size_]) << "Buffer overrun.";
|
||||
output_buffer.resize(total_size_);
|
||||
EXPECT_EQ(unencryptedData, output_buffer);
|
||||
if (global_features.supports_crc) {
|
||||
uint32_t hash =
|
||||
wvcrc32(&unencryptedData[0], unencryptedData.size());
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
OEMCrypto_SetDecryptHash(
|
||||
s.session_id(), 1, reinterpret_cast<const uint8_t*>(&hash),
|
||||
sizeof(hash)));
|
||||
uint32_t frame;
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
OEMCrypto_GetHashErrorCode(s.session_id(), &frame));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
OEMCrypto_CENCEncryptPatternDesc pattern_;
|
||||
|
||||
Reference in New Issue
Block a user