OEMCrypto Query Key Control Block

Merge from Widevine repo http://go/wvgerrit/13818

This CL adds the ability to query OEMCrypto about the key control
block and duration of a key that has been loaded.  There are unit
tests and implementation in the level 3 and reference implementation.

b/18503541

Change-Id: I8e40d90a3c64c1ce030af6fef9e98c8eac0df1a5
This commit is contained in:
Fred Gylys-Colwell
2015-03-30 15:38:52 -07:00
parent 10cc0a5ddb
commit 582eb32661
5 changed files with 115 additions and 0 deletions

View File

@@ -321,6 +321,7 @@ class Adapter {
if (level1_.version == 9) {
LOOKUP(GetHDCPCapability_V9, OEMCrypto_GetHDCPCapability_V9);
} else {
LOOKUP(QueryKeyControl, OEMCrypto_QueryKeyControl);
LOOKUP(GetHDCPCapability, OEMCrypto_GetHDCPCapability);
LOOKUP(IsAntiRollbackHwPresent, OEMCrypto_IsAntiRollbackHwPresent);
LOOKUP(GetNumberOfOpenSessions, OEMCrypto_GetNumberOfOpenSessions);
@@ -677,6 +678,17 @@ extern "C" OEMCryptoResult OEMCrypto_RefreshKeys(
signature_length, num_keys, key_array);
}
extern "C" OEMCryptoResult OEMCrypto_QueryKeyControl(
OEMCrypto_SESSION session, const uint8_t* key_id, size_t key_id_length,
uint8_t* key_control_block, size_t* key_control_block_length) {
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
LevelSession pair = kAdapter->get(session);
if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION;
if (pair.fcn->version < 10) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
return pair.fcn->QueryKeyControl(pair.session, key_id, key_id_length,
key_control_block, key_control_block_length);
}
extern "C" OEMCryptoResult OEMCrypto_SelectKey(const OEMCrypto_SESSION session,
const uint8_t* key_id,
size_t key_id_length) {

View File

@@ -941,6 +941,25 @@ bool SessionContext::UpdateMacKeys(const std::vector<uint8_t>& enc_mac_keys,
return true;
}
bool SessionContext::QueryKeyControlBlock(const KeyId& key_id, uint32_t* data) {
const Key* content_key = session_keys_.Find(key_id);
if (LogCategoryEnabled(kLoggingTraceDecryption)){
LOGI(( "Select Key: key_id = " +
wvcdm::b2a_hex(key_id) ).c_str());
LOGI(( "Select Key: key = " +
wvcdm::b2a_hex(content_key->value()) ).c_str());
}
if (NULL == content_key) {
LOGE("[QueryKeyControlBlock(): No key matches key id]");
return false;
}
data[0] = 0; // verification optional.
data[1] = htonl(content_key->control().duration());
data[2] = 0; // nonce optional.
data[3] = htonl(content_key->control().control_bits());
return true;
}
bool SessionContext::SelectContentKey(const KeyId& key_id) {
const Key* content_key = session_keys_.Find(key_id);

View File

@@ -167,6 +167,7 @@ class SessionContext {
const std::vector<uint8_t>& key_control_iv);
bool UpdateMacKeys(const std::vector<uint8_t>& mac_keys,
const std::vector<uint8_t>& iv);
bool QueryKeyControlBlock(const KeyId& key_id, uint32_t* data);
bool SelectContentKey(const KeyId& key_id);
const Key* current_content_key(void) {return current_content_key_;}
void set_mac_key_server(const std::vector<uint8_t>& mac_key_server) {

View File

@@ -451,6 +451,43 @@ OEMCryptoResult OEMCrypto_RefreshKeys(
return OEMCrypto_SUCCESS;
}
extern "C" OEMCryptoResult OEMCrypto_QueryKeyControl(
OEMCrypto_SESSION session, const uint8_t* key_id, size_t key_id_length,
uint8_t* key_control_block, size_t* key_control_block_length) {
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
LOGI("-- OEMCryptoResult OEMCrypto_QueryKeyControl"
"(const OEMCrypto_SESSION session)\n");
if (wvcdm::g_cutoff >= wvcdm::LOG_VERBOSE) {
dump_hex("key_id", key_id, key_id_length);
}
}
uint32_t* block = reinterpret_cast<uint32_t*>(key_control_block);
if ((key_control_block_length == NULL)
|| (*key_control_block_length < wvcdm::KEY_CONTROL_SIZE)) {
LOGE("[OEMCrypto_QueryKeyControl(): OEMCrypto_ERROR_SHORT_BUFFER]");
return OEMCrypto_ERROR_SHORT_BUFFER;
}
*key_control_block_length = wvcdm::KEY_CONTROL_SIZE;
if (key_id == NULL) {
LOGE("[OEMCrypto_QueryKeyControl(): key_id null. "
"OEMCrypto_ERROR_UNKNOWN_FAILURE]");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (!session_ctx || !session_ctx->isValid()) {
LOGE("[OEMCrypto_QueryKeyControl(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
const std::vector<uint8_t> key_id_str =
std::vector<uint8_t>(key_id, key_id + key_id_length);
if (!session_ctx->QueryKeyControlBlock(key_id_str, block)) {
LOGE("[OEMCrypto_QueryKeyControl(): FAIL]");
return OEMCrypto_ERROR_NO_CONTENT_KEY;
}
return OEMCrypto_SUCCESS;
}
extern "C"
OEMCryptoResult OEMCrypto_SelectKey(const OEMCrypto_SESSION session,
const uint8_t* key_id,

View File

@@ -1012,6 +1012,26 @@ class Session {
&signature_[0], signature_.size(), NULL, NULL,
kNumKeys, key_array_, pst_ptr, pst.length()));
}
VerifyTestKeys();
}
void VerifyTestKeys() {
for (unsigned int i = 0; i < kNumKeys; i++) {
KeyControlBlock block;
size_t size = sizeof(block);
OEMCryptoResult sts = OEMCrypto_QueryKeyControl(
session_id(), license_.keys[i].key_id,
sizeof(license_.keys[i].key_id),
reinterpret_cast<uint8_t*>(&block), &size);
if (sts != OEMCrypto_ERROR_NOT_IMPLEMENTED) {
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
ASSERT_EQ(sizeof(block), size);
ASSERT_EQ(license_.keys[i].control.duration,
block.duration) << "For key " << i;
ASSERT_EQ(license_.keys[i].control.control_bits,
block.control_bits) << "For key " << i;
}
}
}
void RefreshTestKeys(const size_t key_count, uint32_t control_bits,
@@ -2331,6 +2351,32 @@ TEST_F(DISABLED_TestKeybox, LoadKeysWithNoDerivedKeys) {
ASSERT_NE(OEMCrypto_SUCCESS, sts);
}
TEST_F(DISABLED_TestKeybox, QueryKeyControl) {
Session s;
s.open();
s.GenerateDerivedKeys();
s.FillSimpleMessage(0, wvoec_mock::kControlNonceEnabled, s.get_nonce());
s.EncryptAndSign();
s.LoadTestKeys();
// Note: successful cases are tested in VerifyTestKeys.
KeyControlBlock block;
size_t size = sizeof(block) - 1;
OEMCryptoResult sts = OEMCrypto_QueryKeyControl(
s.session_id(), s.license().keys[0].key_id,
sizeof(s.license().keys[0].key_id), reinterpret_cast<uint8_t*>(&block),
&size);
if (sts == OEMCrypto_ERROR_NOT_IMPLEMENTED) {
return;
}
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
const char *key_id = "no_key";
size = sizeof(block);
ASSERT_EQ(OEMCrypto_ERROR_NO_CONTENT_KEY,
OEMCrypto_QueryKeyControl(
s.session_id(), reinterpret_cast<const uint8_t*>(key_id),
strlen(key_id), reinterpret_cast<uint8_t*>(&block), &size));
}
TEST_F(DISABLED_TestKeybox, AntiRollbackHardwareRequired) {
Session s;
s.open();