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) {
|
if (level1_.version == 9) {
|
||||||
LOOKUP(GetHDCPCapability_V9, OEMCrypto_GetHDCPCapability_V9);
|
LOOKUP(GetHDCPCapability_V9, OEMCrypto_GetHDCPCapability_V9);
|
||||||
} else {
|
} else {
|
||||||
|
LOOKUP(QueryKeyControl, OEMCrypto_QueryKeyControl);
|
||||||
LOOKUP(GetHDCPCapability, OEMCrypto_GetHDCPCapability);
|
LOOKUP(GetHDCPCapability, OEMCrypto_GetHDCPCapability);
|
||||||
LOOKUP(IsAntiRollbackHwPresent, OEMCrypto_IsAntiRollbackHwPresent);
|
LOOKUP(IsAntiRollbackHwPresent, OEMCrypto_IsAntiRollbackHwPresent);
|
||||||
LOOKUP(GetNumberOfOpenSessions, OEMCrypto_GetNumberOfOpenSessions);
|
LOOKUP(GetNumberOfOpenSessions, OEMCrypto_GetNumberOfOpenSessions);
|
||||||
@@ -677,6 +678,17 @@ extern "C" OEMCryptoResult OEMCrypto_RefreshKeys(
|
|||||||
signature_length, num_keys, key_array);
|
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,
|
extern "C" OEMCryptoResult OEMCrypto_SelectKey(const OEMCrypto_SESSION session,
|
||||||
const uint8_t* key_id,
|
const uint8_t* key_id,
|
||||||
size_t key_id_length) {
|
size_t key_id_length) {
|
||||||
|
|||||||
@@ -941,6 +941,25 @@ bool SessionContext::UpdateMacKeys(const std::vector<uint8_t>& enc_mac_keys,
|
|||||||
return true;
|
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) {
|
bool SessionContext::SelectContentKey(const KeyId& key_id) {
|
||||||
const Key* content_key = session_keys_.Find(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);
|
const std::vector<uint8_t>& key_control_iv);
|
||||||
bool UpdateMacKeys(const std::vector<uint8_t>& mac_keys,
|
bool UpdateMacKeys(const std::vector<uint8_t>& mac_keys,
|
||||||
const std::vector<uint8_t>& iv);
|
const std::vector<uint8_t>& iv);
|
||||||
|
bool QueryKeyControlBlock(const KeyId& key_id, uint32_t* data);
|
||||||
bool SelectContentKey(const KeyId& key_id);
|
bool SelectContentKey(const KeyId& key_id);
|
||||||
const Key* current_content_key(void) {return current_content_key_;}
|
const Key* current_content_key(void) {return current_content_key_;}
|
||||||
void set_mac_key_server(const std::vector<uint8_t>& mac_key_server) {
|
void set_mac_key_server(const std::vector<uint8_t>& mac_key_server) {
|
||||||
|
|||||||
@@ -451,6 +451,43 @@ OEMCryptoResult OEMCrypto_RefreshKeys(
|
|||||||
return OEMCrypto_SUCCESS;
|
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"
|
extern "C"
|
||||||
OEMCryptoResult OEMCrypto_SelectKey(const OEMCrypto_SESSION session,
|
OEMCryptoResult OEMCrypto_SelectKey(const OEMCrypto_SESSION session,
|
||||||
const uint8_t* key_id,
|
const uint8_t* key_id,
|
||||||
|
|||||||
@@ -1012,6 +1012,26 @@ class Session {
|
|||||||
&signature_[0], signature_.size(), NULL, NULL,
|
&signature_[0], signature_.size(), NULL, NULL,
|
||||||
kNumKeys, key_array_, pst_ptr, pst.length()));
|
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,
|
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);
|
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) {
|
TEST_F(DISABLED_TestKeybox, AntiRollbackHardwareRequired) {
|
||||||
Session s;
|
Session s;
|
||||||
s.open();
|
s.open();
|
||||||
|
|||||||
Reference in New Issue
Block a user