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:
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user