Unit Test Updates for v13

Merge from widevine of http://go/wvgerrit/23042

This updates unit tests to account for key control block changes for
OEMCrypto v13.  There are two new bits, restricting SRM version and
restricting analog output.  The verification string is also updated.

Part of this is to include some simple unit tests for the SRM
functions.

b/33815454
b/28955520

Change-Id: I7cc2ce508688fded2b67fc2a4379c7a8d59d8d22
This commit is contained in:
Fred Gylys-Colwell
2017-01-23 20:34:13 -08:00
parent 65a2c240de
commit 2afe783ce0
7 changed files with 133 additions and 118 deletions

View File

@@ -697,6 +697,63 @@ bool SessionContext::LoadRSAKey(const uint8_t* pkcs8_rsa_key,
return rsa_key_.LoadPkcs8RsaKey(pkcs8_rsa_key, rsa_key_length);
}
OEMCryptoResult SessionContext::AllowKeyUse(const std::string& log_string,
uint32_t use_type,
OEMCryptoBufferType buffer_type) {
const KeyControlBlock& control = current_content_key()->control();
if (use_type && (!(control.control_bits() & use_type))) {
LOGE("[%s(): control bit says not allowed.", log_string.c_str());
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (control.control_bits() & kControlDataPathSecure) {
if (!ce_->config_closed_platform() &&
buffer_type == OEMCrypto_BufferType_Clear) {
LOGE("[%s(): Secure key with insecure buffer]", log_string.c_str());
return OEMCrypto_ERROR_DECRYPT_FAILED;
}
}
if (control.control_bits() & kControlReplayMask) {
if (!IsUsageEntryValid()) {
LOGE("[%s(): usage entry not valid]", log_string.c_str());
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
}
if (control.duration() > 0) {
if (control.duration() < CurrentTimer()) {
LOGE("[%s(): key expired.", log_string.c_str());
return OEMCrypto_ERROR_KEY_EXPIRED;
}
}
if (!ce_->config_local_display_only()) {
// Only look at HDCP and Analog restrictions if the display is non-local.
if (control.control_bits() & kControlHDCPRequired) {
uint8_t required_hdcp =
(control.control_bits() & kControlHDCPVersionMask) >>
kControlHDCPVersionShift;
// For reference implementation, we pretend we can handle the current
// HDCP version.
if (required_hdcp > ce_->config_current_hdcp_capability() ||
ce_->config_current_hdcp_capability() == 0) {
return OEMCrypto_ERROR_INSUFFICIENT_HDCP;
}
}
if (control.control_bits() & kControlSRMVersionRequired) {
LOGE("[%s(): control bit says SRM version required.",
log_string.c_str());
return OEMCrypto_ERROR_INSUFFICIENT_HDCP;
}
}
if (!ce_->config_local_display_only()
|| buffer_type == OEMCrypto_BufferType_Clear) {
if (control.control_bits() & kControlDisableAnalogOutput) {
LOGE("[%s(): control bit says disable analog.",
log_string.c_str());
return OEMCrypto_ERROR_ANALOG_OUTPUT;
}
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult SessionContext::Generic_Encrypt(const uint8_t* in_buffer,
size_t buffer_length,
const uint8_t* iv,
@@ -708,28 +765,14 @@ OEMCryptoResult SessionContext::Generic_Encrypt(const uint8_t* in_buffer,
return OEMCrypto_ERROR_NO_CONTENT_KEY;
}
const std::vector<uint8_t>& key = current_content_key()->value();
const KeyControlBlock& control = current_content_key()->control();
// Set the AES key.
if (static_cast<int>(key.size()) != AES_BLOCK_SIZE) {
LOGE("[Generic_Encrypt(): CONTENT_KEY has wrong size: %d", key.size());
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!(control.control_bits() & kControlAllowEncrypt)) {
LOGE("[Generic_Encrypt(): control bit says not allowed.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (control.duration() > 0) {
if (control.duration() < CurrentTimer()) {
LOGE("[Generic_Encrypt(): key expired.");
return OEMCrypto_ERROR_KEY_EXPIRED;
}
}
if (control.control_bits() & kControlReplayMask) {
if (!IsUsageEntryValid()) {
LOGE("[Generic_Encrypt(): usage entry not valid]");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
}
OEMCryptoResult result = AllowKeyUse("Generic_Encrypt", kControlAllowEncrypt,
OEMCrypto_BufferType_Clear);
if (result != OEMCrypto_SUCCESS) return result;
if (algorithm != OEMCrypto_AES_CBC_128_NO_PADDING) {
LOGE("[Generic_Encrypt(): algorithm bad.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
@@ -762,34 +805,15 @@ OEMCryptoResult SessionContext::Generic_Decrypt(const uint8_t* in_buffer,
return OEMCrypto_ERROR_NO_CONTENT_KEY;
}
const std::vector<uint8_t>& key = current_content_key()->value();
const KeyControlBlock& control = current_content_key()->control();
// Set the AES key.
if (static_cast<int>(key.size()) != AES_BLOCK_SIZE) {
LOGE("[Generic_Decrypt(): CONTENT_KEY has wrong size.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!(control.control_bits() & kControlAllowDecrypt)) {
LOGE("[Generic_Decrypt(): control bit says not allowed.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (control.control_bits() & kControlDataPathSecure) {
if (!ce_->config_closed_platform()) {
LOGE("[Generic_Decrypt(): control bit says secure path only.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
}
if (control.duration() > 0) {
if (control.duration() < CurrentTimer()) {
LOGE("[Generic_Decrypt(): key expired.");
return OEMCrypto_ERROR_KEY_EXPIRED;
}
}
if (control.control_bits() & kControlReplayMask) {
if (!IsUsageEntryValid()) {
LOGE("[Generic_Decrypt(): usage entry not valid]");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
}
OEMCryptoResult result = AllowKeyUse("Generic_Decrypt", kControlAllowDecrypt,
OEMCrypto_BufferType_Clear);
if (result != OEMCrypto_SUCCESS) return result;
if (algorithm != OEMCrypto_AES_CBC_128_NO_PADDING) {
LOGE("[Generic_Decrypt(): bad algorithm.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
@@ -827,27 +851,13 @@ OEMCryptoResult SessionContext::Generic_Sign(const uint8_t* in_buffer,
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
const std::vector<uint8_t>& key = current_content_key()->value();
const KeyControlBlock& control = current_content_key()->control();
if (static_cast<int>(key.size()) != SHA256_DIGEST_LENGTH) {
LOGE("[Generic_Sign(): CONTENT_KEY has wrong size; %d", key.size());
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!(control.control_bits() & kControlAllowSign)) {
LOGE("[Generic_Sign(): control bit says not allowed.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (control.duration() > 0) {
if (control.duration() < CurrentTimer()) {
LOGE("[Generic_Sign(): key expired.");
return OEMCrypto_ERROR_KEY_EXPIRED;
}
}
if (control.control_bits() & kControlReplayMask) {
if (!IsUsageEntryValid()) {
LOGE("[Generic_Sign(): usage entry not valid]");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
}
OEMCryptoResult result = AllowKeyUse("Generic_Sign", kControlAllowSign,
OEMCrypto_BufferType_Clear);
if (result != OEMCrypto_SUCCESS) return result;
if (algorithm != OEMCrypto_HMAC_SHA256) {
LOGE("[Generic_Sign(): bad algorithm.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
@@ -877,27 +887,13 @@ OEMCryptoResult SessionContext::Generic_Verify(const uint8_t* in_buffer,
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
const std::vector<uint8_t>& key = current_content_key()->value();
const KeyControlBlock& control = current_content_key()->control();
if (static_cast<int>(key.size()) != SHA256_DIGEST_LENGTH) {
LOGE("[Generic_Verify(): CONTENT_KEY has wrong size: %d", key.size());
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!(control.control_bits() & kControlAllowVerify)) {
LOGE("[Generic_Verify(): control bit says not allowed.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (control.duration() > 0) {
if (control.duration() < CurrentTimer()) {
LOGE("[Generic_Verify(): key expired.");
return OEMCrypto_ERROR_KEY_EXPIRED;
}
}
if (control.control_bits() & kControlReplayMask) {
if (!IsUsageEntryValid()) {
LOGE("[Generic_Verify(): usage entry not valid]");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
}
OEMCryptoResult result = AllowKeyUse("Generic_Verify", kControlAllowVerify,
OEMCrypto_BufferType_Clear);
if (result != OEMCrypto_SUCCESS) return result;
if (algorithm != OEMCrypto_HMAC_SHA256) {
LOGE("[Generic_Verify(): bad algorithm.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
@@ -1083,40 +1079,10 @@ OEMCryptoResult SessionContext::DecryptCENC(
LOGE("[DecryptCTR(): OEMCrypto_ERROR_NO_CONTENT_KEY]");
return OEMCrypto_ERROR_DECRYPT_FAILED;
}
const KeyControlBlock& control = current_content_key()->control();
if (control.control_bits() & kControlDataPathSecure) {
if (!ce_->config_closed_platform() &&
buffer_type == OEMCrypto_BufferType_Clear) {
LOGE("[DecryptCTR(): Secure key with insecure buffer]");
return OEMCrypto_ERROR_DECRYPT_FAILED;
}
}
if (control.duration() > 0) {
if (control.duration() < CurrentTimer()) {
LOGE("[DecryptCTR(): KEY_EXPIRED]");
return OEMCrypto_ERROR_KEY_EXPIRED;
}
}
if (control.control_bits() & kControlReplayMask) {
if (!IsUsageEntryValid()) {
LOGE("[DecryptCTR(): usage entry not valid]");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
}
if (!ce_->config_local_display_only()) {
// Only look at HDCP if the display is non-local.
if (control.control_bits() & kControlHDCPRequired) {
uint8_t required_hdcp =
(control.control_bits() & kControlHDCPVersionMask) >>
kControlHDCPVersionShift;
// For reference implementation, we pretend we can handle the current
// HDCP version.
if (required_hdcp > ce_->config_current_hdcp_capability() ||
ce_->config_current_hdcp_capability() == 0) {
return OEMCrypto_ERROR_INSUFFICIENT_HDCP;
}
}
}
OEMCryptoResult result = AllowKeyUse("DecryptCENC", 0, buffer_type);
if (result != OEMCrypto_SUCCESS) return result;
const std::vector<uint8_t>& content_key = current_content_key()->value();
// Set the AES key.

View File

@@ -212,7 +212,8 @@ class SessionContext {
OEMCryptoResult DecryptCTR(const uint8_t* key_u8, const uint8_t* iv,
size_t block_offset, const uint8_t* cipher_data,
size_t cipher_data_length, uint8_t* clear_data);
OEMCryptoResult AllowKeyUse(const std::string& log_string, uint32_t use_type,
OEMCryptoBufferType buffer_type);
RSA* rsa_key() { return rsa_key_.get(); }
bool valid_;

View File

@@ -59,6 +59,13 @@ KeyControlBlock::KeyControlBlock(
LOGD(" nonce: %08X", nonce());
LOGD(" magic: %08X", verification());
LOGD(" bits: %08X", control_bits());
LOGD(" bit kControlSRMVersionRequired %s.",
(control_bits() & kControlSRMVersionRequired) ? "set" : "unset");
LOGD(" bit kControlDisableAnalogOutput %s.",
(control_bits() & kControlDisableAnalogOutput) ? "set" : "unset");
LOGD(" bits kControlSecurityPatchLevel 0x%02x.",
(control_bits() & kControlSecurityPatchLevelMask)
>> kControlSecurityPatchLevelShift);
switch (control_bits() & kControlReplayMask) {
case kControlNonceRequired:
LOGD(" bits kControlReplay kControlNonceRequired.");
@@ -70,12 +77,9 @@ KeyControlBlock::KeyControlBlock(
LOGD(" bits kControlReplay unset.");
break;
}
LOGD(" bits kControlKDCPVersion 0x%02x.",
LOGD(" bits kControlHDCPVersion 0x%02x.",
(control_bits() & kControlHDCPVersionMask)
>> kControlHDCPVersionShift);
LOGD(" bits kControlSecurityPatchLevel 0x%02x.",
(control_bits() & kControlSecurityPatchLevelMask)
>> kControlSecurityPatchLevelShift);
LOGD(" bit kControlAllowEncrypt %s.",
(control_bits() & kControlAllowEncrypt) ? "set" : "unset");
LOGD(" bit kControlAllowDecrypt %s.",

View File

@@ -15,6 +15,8 @@ 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 kControlSRMVersionRequired = (1<<22);
const uint32_t kControlDisableAnalogOutput = (1<<21);
const uint32_t kControlSecurityPatchLevelShift = 15;
const uint32_t kControlSecurityPatchLevelMask =
(0x3F<<kControlSecurityPatchLevelShift);

View File

@@ -123,6 +123,7 @@ std::string DeviceFeatures::RestrictFilter(const std::string& initial_filter) {
if (api_version < 10) FilterOut(&filter, "*API10*");
if (api_version < 11) FilterOut(&filter, "*API11*");
if (api_version < 12) FilterOut(&filter, "*API12*");
if (api_version < 13) FilterOut(&filter, "*API13*");
// Performance tests take a long time. Filter them out if they are not
// specifically requested.
if (filter.find("Performance") == std::string::npos) {

View File

@@ -309,8 +309,11 @@ void Session::FillSimpleMessage(uint32_t duration, uint32_t control,
sizeof(license_.keys[i].key_iv)));
EXPECT_EQ(1, RAND_pseudo_bytes(license_.keys[i].control_iv,
sizeof(license_.keys[i].control_iv)));
// For version 12, we require OEMCrypto to handle kc12 for all licenses.
if (global_features.api_version == 12) {
if (global_features.api_version == 13) {
// For version 13, we require OEMCrypto to handle kc13 for all licenses.
memcpy(license_.keys[i].control.verification, "kc13", 4);
} else if (global_features.api_version == 12) {
// For version 12, we require OEMCrypto to handle kc12 for all licenses.
memcpy(license_.keys[i].control.verification, "kc12", 4);
} else if (control & wvoec_mock::kControlSecurityPatchLevelMask) {
// For versions before 12, we require the special key control block only
@@ -338,7 +341,10 @@ void Session::FillRefreshMessage(size_t key_count, uint32_t control_bits,
encrypted_license().keys[i].key_id_length = license_.keys[i].key_id_length;
memcpy(encrypted_license().keys[i].key_id, license_.keys[i].key_id,
encrypted_license().keys[i].key_id_length);
if (global_features.api_version == 12) {
if (global_features.api_version == 13) {
// For version 13, we require OEMCrypto to handle kc13 for all licenses.
memcpy(encrypted_license().keys[i].control.verification, "kc13", 4);
} else if (global_features.api_version == 12) {
// For version 12, we require OEMCrypto to handle kc12 for all licenses.
memcpy(encrypted_license().keys[i].control.verification, "kc12", 4);
} else {
@@ -538,6 +544,10 @@ void Session::TestDecryptCTR(bool select_key_first,
// Report HDCP errors.
ASSERT_EQ(OEMCrypto_ERROR_INSUFFICIENT_HDCP, sts);
ASSERT_NE(unencryptedData, outputBuffer);
} else if (expected_result == OEMCrypto_ERROR_ANALOG_OUTPUT) {
// Report analog errors.
ASSERT_EQ(OEMCrypto_ERROR_ANALOG_OUTPUT, sts);
ASSERT_NE(unencryptedData, outputBuffer);
} else {
// OEM's can fine tune other error codes for debugging.
ASSERT_NE(OEMCrypto_SUCCESS, sts);

View File

@@ -131,6 +131,24 @@ TEST_F(OEMCryptoClientTest, CheckHDCPCapability) {
HDCPCapabilityAsString(maximum));
}
TEST_F(OEMCryptoClientTest, CheckSRMCapabilityV13) {
// This just tests some trivial functionality of the SRM update functions.
bool supported = OEMCrypto_IsSRMUpdateSupported();
printf(" Update SRM Supported: %s.\n",
supported ? "true" : "false");
uint16_t version = 0;
OEMCryptoResult current_result = OEMCrypto_GetCurrentSRMVersion(&version);
if (current_result == OEMCrypto_SUCCESS) {
printf(" Current SRM Version: %d.\n", version);
EXPECT_NE(OEMCrypto_SUCCESS, OEMCrypto_GetCurrentSRMVersion(NULL));
} else {
EXPECT_EQ(OEMCrypto_ERROR_NOT_IMPLEMENTED, current_result);
}
vector<uint8_t> bad_srm(42);
RAND_pseudo_bytes(&bad_srm[0], bad_srm.size());
EXPECT_NE(OEMCrypto_SUCCESS, OEMCrypto_LoadSRM(&bad_srm[0], bad_srm.size()));
}
TEST_F(OEMCryptoClientTest, CheckMaxNumberOfSessionsAPI10) {
size_t sessions_count;
ASSERT_EQ(OEMCrypto_SUCCESS,
@@ -1153,7 +1171,8 @@ TEST_P(SessionTestAlternateVerification, LoadKeys) {
ASSERT_NE(OEMCrypto_SUCCESS, sts);
} else {
// Otherwise, LoadKeys should succeed.
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
ASSERT_EQ(OEMCrypto_SUCCESS, sts)
<< "LoadKeys failed for key control block kc" << target_api_;
}
}
@@ -1161,7 +1180,7 @@ TEST_P(SessionTestAlternateVerification, LoadKeys) {
// the current API + 2. We use +2 because we want to test at least 1
// future API, and the ::testing::Range is not inclusive.
INSTANTIATE_TEST_CASE_P(TestAll, SessionTestAlternateVerification,
Range(8, 12 + 2));
Range(8, 13 + 2));
TEST_F(OEMCryptoSessionTests, LoadKeysBadSignature) {
Session s;
@@ -2104,6 +2123,18 @@ TEST_F(OEMCryptoSessionTests, DecryptSecureToClear) {
s.TestDecryptCTR(true, OEMCrypto_ERROR_UNKNOWN_FAILURE));
}
TEST_F(OEMCryptoSessionTests, DecryptNoAnalogToClear) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
kDuration, wvoec_mock::kControlDisableAnalogOutput, 0));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys());
ASSERT_NO_FATAL_FAILURE(
s.TestDecryptCTR(true, OEMCrypto_ERROR_ANALOG_OUTPUT));
}
TEST_F(OEMCryptoSessionTests, KeyDuration) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());