Add Shared License bit to key control block
Merge from widevine of http://go/wvgerrit/23184 This adds the shared license bit to the key control block for the reference code and the unit tests. b/31458046 Change-Id: I4e360ea5dd2e6cee145663d4ab4f384b65cac427
This commit is contained in:
@@ -433,6 +433,10 @@ OEMCryptoResult SessionContext::LoadKeys(
|
||||
|
||||
StartTimer();
|
||||
|
||||
// If there are already keys installed in this session, then we can load
|
||||
// a shared license.
|
||||
bool second_license = (session_keys_.size() > 0);
|
||||
|
||||
// Decrypt and install keys in key object
|
||||
// Each key will have a key control block. They will all have the same nonce.
|
||||
OEMCryptoResult status = OEMCrypto_SUCCESS;
|
||||
@@ -459,7 +463,7 @@ OEMCryptoResult SessionContext::LoadKeys(
|
||||
|
||||
OEMCryptoResult result = InstallKey(
|
||||
key_id, enc_key_data, key_data_iv, key_control, key_control_iv,
|
||||
key_array[i].cipher_mode == OEMCrypto_CipherMode_CTR);
|
||||
key_array[i].cipher_mode == OEMCrypto_CipherMode_CTR, second_license);
|
||||
if (result != OEMCrypto_SUCCESS) {
|
||||
status = result;
|
||||
break;
|
||||
@@ -505,7 +509,7 @@ OEMCryptoResult SessionContext::LoadKeys(
|
||||
return OEMCrypto_ERROR_WRONG_PST;
|
||||
}
|
||||
if (!usage_entry_->VerifyMacKeys(mac_key_server_, mac_key_client_)) {
|
||||
LOGE("LoadKeys: Usage table entry does not match.\n");
|
||||
LOGE("LoadKeys: Usage table entry mac keys do not match.\n");
|
||||
return OEMCrypto_ERROR_WRONG_KEYS;
|
||||
}
|
||||
if (usage_entry_->Inactive()) return OEMCrypto_ERROR_LICENSE_INACTIVE;
|
||||
@@ -519,7 +523,8 @@ OEMCryptoResult SessionContext::InstallKey(
|
||||
const KeyId& key_id, const std::vector<uint8_t>& key_data,
|
||||
const std::vector<uint8_t>& key_data_iv,
|
||||
const std::vector<uint8_t>& key_control,
|
||||
const std::vector<uint8_t>& key_control_iv, bool ctr_mode) {
|
||||
const std::vector<uint8_t>& key_control_iv, bool ctr_mode,
|
||||
bool second_license) {
|
||||
// Decrypt encrypted key_data using derived encryption key and offered iv
|
||||
std::vector<uint8_t> content_key;
|
||||
std::vector<uint8_t> key_control_str;
|
||||
@@ -579,6 +584,13 @@ OEMCryptoResult SessionContext::InstallKey(
|
||||
return result;
|
||||
}
|
||||
|
||||
if (key_control_block.control_bits() & kSharedLicense) {
|
||||
if (!second_license) {
|
||||
LOGE("LoadKeys: Shared License, but no keys previously loaded.");
|
||||
return OEMCrypto_ERROR_MISSING_MASTER;
|
||||
}
|
||||
}
|
||||
|
||||
Key key(content_key, key_control_block, ctr_mode);
|
||||
session_keys_.Insert(key_id, key);
|
||||
return OEMCrypto_SUCCESS;
|
||||
|
||||
@@ -44,6 +44,7 @@ class SessionKeyTable {
|
||||
Key* Find(const KeyId key_id);
|
||||
void Remove(const KeyId key_id);
|
||||
void UpdateDuration(const KeyControlBlock& control);
|
||||
size_t size() const { return keys_.size(); }
|
||||
|
||||
private:
|
||||
KeyMap keys_;
|
||||
@@ -144,7 +145,7 @@ class SessionContext {
|
||||
const std::vector<uint8_t>& key_data_iv,
|
||||
const std::vector<uint8_t>& key_control,
|
||||
const std::vector<uint8_t>& key_control_iv,
|
||||
bool ctr_mode);
|
||||
bool ctr_mode, bool second_license);
|
||||
bool InstallRSAEncryptedKey(const uint8_t* encrypted_message_key,
|
||||
size_t encrypted_message_key_length);
|
||||
bool DecryptRSAKey(const uint8_t* enc_rsa_key, size_t enc_rsa_key_length,
|
||||
|
||||
@@ -59,6 +59,8 @@ KeyControlBlock::KeyControlBlock(
|
||||
LOGD(" nonce: %08X", nonce());
|
||||
LOGD(" magic: %08X", verification());
|
||||
LOGD(" bits: %08X", control_bits());
|
||||
LOGD(" bit kSharedLicense %s.",
|
||||
(control_bits() & kSharedLicense) ? "set" : "unset");
|
||||
LOGD(" bit kControlSRMVersionRequired %s.",
|
||||
(control_bits() & kControlSRMVersionRequired) ? "set" : "unset");
|
||||
LOGD(" bit kControlDisableAnalogOutput %s.",
|
||||
|
||||
@@ -15,6 +15,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 kSharedLicense = (1<<23);
|
||||
const uint32_t kControlSRMVersionRequired = (1<<22);
|
||||
const uint32_t kControlDisableAnalogOutput = (1<<21);
|
||||
const uint32_t kControlSecurityPatchLevelShift = 15;
|
||||
|
||||
@@ -5244,14 +5244,37 @@ TEST_F(UsageTableTest, VerifyUsageTimes) {
|
||||
// This is a special case where a collection of licenses can be shared with
|
||||
// multiple devices. In order for this to work, a single session must first
|
||||
// load a device specific license, and then a shared content license.
|
||||
#if 0 // TODO(fredgc,jfore): fix this in http://go/wvgerrit/23184/
|
||||
TEST_F(UsageTableTest, LoadSharedLicense) {
|
||||
// session_.generatersasignature.
|
||||
// session_.GenerateNonce
|
||||
// DeriveKeysFromSessionKey - (specify enc/mac keys.
|
||||
// LoadKeys replay control = 2. loads new mac keys.
|
||||
// LoadKeys replay control = 0. uses same mac key.
|
||||
// check second loadkeys without first fails.
|
||||
std::string pst = "my_pst";
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(LoadOfflineLicense(s, pst));
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
|
||||
// We will reuse the encrypted and signed message, so we don't call
|
||||
// FillSimpleMessage again.
|
||||
ASSERT_NO_FATAL_FAILURE(s.ReloadUsageEntry());
|
||||
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys(pst, true));
|
||||
|
||||
// The second set of keys are in the shared license. They will have the
|
||||
// same mac keys as the original license, so we leave that alone.
|
||||
// We given them different key ids so we can test that they were loaded.
|
||||
// For this test, we leave the key content the same -- in real life it
|
||||
// will be different.
|
||||
for (unsigned int i = 0; i < s.num_keys(); i++) {
|
||||
memset(s.license().keys[i].key_id, 'A' + i,
|
||||
s.license().keys[i].key_id_length);
|
||||
s.license().keys[i].control.nonce = 0;
|
||||
s.license().keys[i].control.control_bits =
|
||||
htonl(wvoec_mock::kSharedLicense);
|
||||
}
|
||||
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
|
||||
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys(pst, false));
|
||||
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(s.close());
|
||||
}
|
||||
|
||||
TEST_F(UsageTableTest, LoadSharedLicenseWithNoMaster) {
|
||||
std::string pst = "my_pst";
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(LoadOfflineLicense(s, pst));
|
||||
@@ -5259,21 +5282,32 @@ TEST_F(UsageTableTest, LoadSharedLicense) {
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
|
||||
ASSERT_NO_FATAL_FAILURE(s.ReloadUsageEntry());
|
||||
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys(pst, true));
|
||||
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0));
|
||||
// This time, we do NOT load the master license. This should
|
||||
// generate an error below.
|
||||
// ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys(pst, true));
|
||||
|
||||
// The second set of keys are in the shared license.
|
||||
// We given them different key ids so we can test that they were loaded.
|
||||
// For this test, we leave the key content the same -- in real life it
|
||||
// will be different.
|
||||
for (unsigned int i = 0; i < s.num_keys(); i++) {
|
||||
memset(s.license().keys[i].key_id, 'A' + i,
|
||||
s.license().keys[i].key_id_length);
|
||||
s.license().keys[i].control.nonce = 0;
|
||||
s.license().keys[i].control.control_bits =
|
||||
htonl(wvoec_mock::kSharedLicense);
|
||||
}
|
||||
// TODO(fredgc,jfore): Decide if first set of keys need to stay loaded, or if
|
||||
// they are replaced.
|
||||
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
|
||||
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys(pst, false));
|
||||
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR());
|
||||
uint8_t* pst_ptr = s.encrypted_license().pst;
|
||||
ASSERT_EQ(OEMCrypto_ERROR_MISSING_MASTER,
|
||||
OEMCrypto_LoadKeys(
|
||||
s.session_id(), s.message_ptr(), s.message_size(),
|
||||
&s.signature()[0], s.signature().size(),
|
||||
s.encrypted_license().mac_key_iv,
|
||||
s.encrypted_license().mac_keys,
|
||||
s.num_keys(), s.key_array(), pst_ptr, pst.length(), NULL));
|
||||
ASSERT_NO_FATAL_FAILURE(s.close());
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_F(UsageTableTest, PSTLargeBuffer) {
|
||||
std::string pst(kMaxPSTLength, 'a'); // A large PST.
|
||||
|
||||
Reference in New Issue
Block a user