am eb4b7cdc: Merge "Catch null pst in OEMCrypto" into lmp-dev
* commit 'eb4b7cdc473ef8fe00f246c4e56f5ab8af0f2f1b': Catch null pst in OEMCrypto
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -344,6 +344,13 @@ bool SessionContext::CheckNonceOrEntry(const KeyControlBlock& key_control_block,
|
||||
switch (key_control_block.control_bits() & kControlReplayMask) {
|
||||
case kControlNonceRequired: // Online license. Nonce always required.
|
||||
if (!CheckNonce(key_control_block.nonce())) return false;
|
||||
if (pst.size() == 0) {
|
||||
LOGE("KCB: PST null for kControlNonceRequired.");
|
||||
return false;
|
||||
}
|
||||
if (!(key_control_block.control_bits() & kControlNonceEnabled)) {
|
||||
LOGE("KCB: Server provided Nonce_Required but Nonce_Enabled = 0.");
|
||||
}
|
||||
if (!usage_entry_) {
|
||||
if (ce_->usage_table()->FindEntry(pst)) {
|
||||
LOGE("KCB: Cannot create duplicate entries in usage table.");
|
||||
@@ -353,6 +360,13 @@ bool SessionContext::CheckNonceOrEntry(const KeyControlBlock& key_control_block,
|
||||
}
|
||||
break; // Offline license. Nonce required on first use.
|
||||
case kControlNonceOrEntry:
|
||||
if (key_control_block.control_bits() & kControlNonceEnabled) {
|
||||
LOGE("KCB: Server provided NonceOrEntry but Nonce_Enabled = 1.");
|
||||
}
|
||||
if (pst.size() == 0) {
|
||||
LOGE("KCB: PST null for kControlNonceOrEntry.");
|
||||
return false;
|
||||
}
|
||||
if (!usage_entry_) {
|
||||
usage_entry_ = ce_->usage_table()->FindEntry(pst);
|
||||
if (usage_entry_) {
|
||||
@@ -405,7 +419,8 @@ OEMCryptoResult SessionContext::LoadKeys(
|
||||
std::vector<uint8_t> key_data_iv;
|
||||
std::vector<uint8_t> key_control;
|
||||
std::vector<uint8_t> key_control_iv;
|
||||
std::vector<uint8_t> pstv(pst, pst + pst_length);
|
||||
std::vector<uint8_t> pstv;
|
||||
if (pst_length > 0) pstv.assign(pst, pst + pst_length);
|
||||
for (unsigned int i = 0; i < num_keys; i++) {
|
||||
key_id.assign(key_array[i].key_id,
|
||||
key_array[i].key_id + key_array[i].key_id_length);
|
||||
|
||||
@@ -318,14 +318,21 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
|
||||
// Later on, we use pst_length to verify the the pst is valid. This makes
|
||||
// sure that we aren't given a null string but told it has postiive length.
|
||||
if ((pst == NULL && pst_length > 0) || (pst != NULL && pst_length == 0)) {
|
||||
LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_ONCTEXT - null pst.]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
|
||||
// Range check
|
||||
if (!RangeCheck(message, message_length, enc_mac_keys,
|
||||
2 * wvcdm::MAC_KEY_SIZE, true) ||
|
||||
!RangeCheck(message, message_length, enc_mac_key_iv, wvcdm::KEY_IV_SIZE,
|
||||
true) ||
|
||||
!RangeCheck(message, message_length, pst, pst_length, true)) {
|
||||
LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_SIGNATURE_FAILURE - range check.]");
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - range check.]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < num_keys; i++) {
|
||||
|
||||
@@ -4525,9 +4525,7 @@ class DISABLED_UsageTableTest : public DISABLED_GenericDRMTest,
|
||||
void LoadOfflineLicense(Session& s, const std::string& pst) {
|
||||
s.open();
|
||||
s.GenerateDerivedKeys();
|
||||
s.FillSimpleMessage(
|
||||
0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceOrEntry,
|
||||
s.get_nonce(), pst);
|
||||
s.FillSimpleMessage(0, wvoec_mock::kControlNonceOrEntry, s.get_nonce(), pst);
|
||||
s.EncryptAndSign();
|
||||
s.LoadTestKeys(pst, new_mac_keys_);
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable());
|
||||
@@ -4613,6 +4611,27 @@ TEST_P(DISABLED_UsageTableTest, RepeatOnlineLicense) {
|
||||
}
|
||||
}
|
||||
|
||||
// A license with non-zero replay control bits needs a valid pst..
|
||||
TEST_P(DISABLED_UsageTableTest, OnlineEmptyPST) {
|
||||
if (OEMCrypto_SupportsUsageTable()) {
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable());
|
||||
Session s;
|
||||
s.open();
|
||||
s.GenerateDerivedKeys();
|
||||
s.FillSimpleMessage(
|
||||
0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired,
|
||||
s.get_nonce());
|
||||
s.EncryptAndSign();
|
||||
OEMCryptoResult sts = OEMCrypto_LoadKeys(
|
||||
s.session_id(), s.message_ptr(), sizeof(MessageData), &s.signature()[0],
|
||||
s.signature().size(), s.encrypted_license().mac_key_iv,
|
||||
s.encrypted_license().mac_keys, kNumKeys, s.key_array(),
|
||||
NULL, 0);
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
||||
s.close();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(DISABLED_UsageTableTest, EmptyTable) {
|
||||
if (OEMCrypto_SupportsUsageTable()) {
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable());
|
||||
@@ -5178,9 +5197,8 @@ TEST_P(DISABLED_UsageTableTest, BadReloadOfflineLicense) {
|
||||
Session s2;
|
||||
s2.open();
|
||||
s2.GenerateDerivedKeys();
|
||||
s2.FillSimpleMessage(
|
||||
0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceOrEntry,
|
||||
s2.get_nonce(), pst);
|
||||
s2.FillSimpleMessage(0, wvoec_mock::kControlNonceOrEntry,
|
||||
s2.get_nonce(), pst);
|
||||
s2.EncryptAndSign();
|
||||
uint8_t* pst_ptr = s2.encrypted_license().pst;
|
||||
ASSERT_NE(OEMCrypto_SUCCESS,
|
||||
@@ -5201,6 +5219,50 @@ TEST_P(DISABLED_UsageTableTest, BadReloadOfflineLicense) {
|
||||
}
|
||||
}
|
||||
|
||||
// An offline license should not load on the first call if the nonce is bad.
|
||||
TEST_P(DISABLED_UsageTableTest, OfflineBadNonce) {
|
||||
if (OEMCrypto_SupportsUsageTable()) {
|
||||
std::string pst = "my_pst";
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable());
|
||||
Session s;
|
||||
s.open();
|
||||
s.GenerateDerivedKeys();
|
||||
s.FillSimpleMessage(
|
||||
0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceOrEntry,
|
||||
42, pst);
|
||||
s.EncryptAndSign();
|
||||
uint8_t* pst_ptr = s.encrypted_license().pst;
|
||||
OEMCryptoResult sts = OEMCrypto_LoadKeys(
|
||||
s.session_id(), s.message_ptr(), sizeof(MessageData), &s.signature()[0],
|
||||
s.signature().size(), s.encrypted_license().mac_key_iv,
|
||||
s.encrypted_license().mac_keys, kNumKeys, s.key_array(),
|
||||
pst_ptr, pst.length());
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
||||
s.close();
|
||||
}
|
||||
}
|
||||
|
||||
// An offline license needs a valid pst.
|
||||
TEST_P(DISABLED_UsageTableTest, OfflineEmptyPST) {
|
||||
if (OEMCrypto_SupportsUsageTable()) {
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable());
|
||||
Session s;
|
||||
s.open();
|
||||
s.GenerateDerivedKeys();
|
||||
s.FillSimpleMessage(
|
||||
0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceOrEntry,
|
||||
s.get_nonce());
|
||||
s.EncryptAndSign();
|
||||
OEMCryptoResult sts = OEMCrypto_LoadKeys(
|
||||
s.session_id(), s.message_ptr(), sizeof(MessageData), &s.signature()[0],
|
||||
s.signature().size(), s.encrypted_license().mac_key_iv,
|
||||
s.encrypted_license().mac_keys, kNumKeys, s.key_array(),
|
||||
NULL, 0);
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
||||
s.close();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(DISABLED_UsageTableTest, DeactivateOfflineLicense) {
|
||||
if (OEMCrypto_SupportsUsageTable()) {
|
||||
std::string pst = "my_pst";
|
||||
@@ -5248,9 +5310,8 @@ TEST_P(DISABLED_UsageTableTest, BadRange) {
|
||||
Session s;
|
||||
s.open();
|
||||
s.GenerateDerivedKeys();
|
||||
s.FillSimpleMessage(
|
||||
0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceOrEntry,
|
||||
s.get_nonce(), pst);
|
||||
s.FillSimpleMessage(0, wvoec_mock::kControlNonceOrEntry,
|
||||
s.get_nonce(), pst);
|
||||
s.EncryptAndSign();
|
||||
uint8_t* pst_ptr = s.license().pst; // Bad: not in encrypted_license.
|
||||
ASSERT_NE(
|
||||
|
||||
Reference in New Issue
Block a user