Update OEMCrypto calls to use substrings
Merge from master branch of Widevine repo of http://go/wvgerrit/66073 Merge from oemcrypto-v15 branch of Widevine repo of http://go/wvgerrit/64083 As part of the update to v15, LoadKeys, RefreshKeys, and LoadEntitledContentKeys should all use offsets and lengths into the message rather than a pointer for its parameters. The CDM, tests, adapters, and OEMCrypto implementations are changed to reflect this. Test: tested as part of http://go/ag/5501993 Bug: 115874964 Change-Id: I981fa322dec7c565066fd163ca5775dbff71fccf
This commit is contained in:
committed by
Fred Gylys-Colwell
parent
4550979f22
commit
e6439255ba
@@ -913,9 +913,10 @@ TEST_F(OEMCryptoSessionTests, LoadEntitlementKeysWrongEntitlementKeysAPI14) {
|
||||
ASSERT_NO_FATAL_FAILURE(s.LoadEntitlementTestKeys());
|
||||
s.FillEntitledKeyArray();
|
||||
const std::string key_id = "no_key";
|
||||
s.entitled_key_array()[0].entitlement_key_id =
|
||||
reinterpret_cast<const uint8_t*>(key_id.c_str());
|
||||
s.entitled_key_array()[0].entitlement_key_id_length = key_id.length();
|
||||
memcpy(const_cast<uint8_t*>(s.encrypted_entitled_message_ptr()) +
|
||||
s.entitled_key_array()[0].entitlement_key_id.offset,
|
||||
reinterpret_cast<const uint8_t*>(key_id.c_str()), key_id.length());
|
||||
s.entitled_key_array()[0].entitlement_key_id.length = key_id.length();
|
||||
s.LoadEntitledContentKeys(OEMCrypto_KEY_NOT_ENTITLED);
|
||||
}
|
||||
|
||||
@@ -961,6 +962,15 @@ TEST_F(OEMCryptoSessionTests, LoadKeyLargeBuffer) {
|
||||
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys());
|
||||
}
|
||||
|
||||
// Returns a string containing two times the original message in continuous
|
||||
// memory. Used as part of the BadRange tests.
|
||||
std::string DuplicateMessage(MessageData& message) {
|
||||
std::string single_message = wvcdm::BytesToString(
|
||||
reinterpret_cast<const uint8_t*>(&message), sizeof(message));
|
||||
std::string double_message = single_message + single_message;
|
||||
return double_message;
|
||||
}
|
||||
|
||||
/* The Bad Range tests verify that OEMCrypto_LoadKeys checks the range
|
||||
of all the pointers. It should reject a message if the pointer does
|
||||
not point into the message buffer */
|
||||
@@ -970,15 +980,17 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange1) {
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
|
||||
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0));
|
||||
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
|
||||
vector<uint8_t> mac_keys(
|
||||
s.encrypted_license().mac_keys,
|
||||
s.encrypted_license().mac_keys + sizeof(s.encrypted_license().mac_keys));
|
||||
std::string double_message = DuplicateMessage(s.encrypted_license());
|
||||
OEMCrypto_Substring wrong_mac_keys = s.enc_mac_keys_substr();
|
||||
wrong_mac_keys.offset += s.message_size();
|
||||
|
||||
OEMCryptoResult sts = OEMCrypto_LoadKeys(
|
||||
s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0],
|
||||
s.signature().size(), s.encrypted_license().mac_key_iv,
|
||||
&mac_keys[0], // Not pointing into buffer.
|
||||
s.num_keys(), s.key_array(), NULL, 0, NULL, OEMCrypto_ContentLicense);
|
||||
s.session_id(), reinterpret_cast<const uint8_t*>(double_message.data()),
|
||||
s.message_size(), &s.signature()[0], s.signature().size(),
|
||||
s.enc_mac_keys_iv_substr(),
|
||||
wrong_mac_keys, // Not within range of one message.
|
||||
s.num_keys(), s.key_array(), GetSubstring(), GetSubstring(),
|
||||
OEMCrypto_ContentLicense);
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
||||
}
|
||||
|
||||
@@ -988,17 +1000,16 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange2) {
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
|
||||
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0));
|
||||
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
|
||||
vector<uint8_t> mac_key_iv(s.encrypted_license().mac_key_iv,
|
||||
s.encrypted_license().mac_key_iv +
|
||||
sizeof(s.encrypted_license().mac_key_iv));
|
||||
std::string double_message = DuplicateMessage(s.encrypted_license());
|
||||
OEMCrypto_Substring wrong_mac_keys_iv = s.enc_mac_keys_iv_substr();
|
||||
wrong_mac_keys_iv.offset += s.message_size();
|
||||
|
||||
OEMCryptoResult sts =
|
||||
OEMCrypto_LoadKeys(s.session_id(), s.message_ptr(), s.message_size(),
|
||||
&s.signature()[0], s.signature().size(),
|
||||
&mac_key_iv[0], // bad.
|
||||
s.encrypted_license().mac_keys, s.num_keys(),
|
||||
s.key_array(), NULL, 0, NULL,
|
||||
OEMCrypto_ContentLicense);
|
||||
OEMCryptoResult sts = OEMCrypto_LoadKeys(
|
||||
s.session_id(), reinterpret_cast<const uint8_t*>(double_message.data()),
|
||||
s.message_size(), &s.signature()[0], s.signature().size(),
|
||||
wrong_mac_keys_iv, // bad.
|
||||
s.enc_mac_keys_substr(), s.num_keys(), s.key_array(), GetSubstring(),
|
||||
GetSubstring(), OEMCrypto_ContentLicense);
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
||||
}
|
||||
|
||||
@@ -1008,16 +1019,14 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange3) {
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
|
||||
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0));
|
||||
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
|
||||
vector<uint8_t> bad_buffer(s.encrypted_license().keys[0].key_id,
|
||||
s.encrypted_license().keys[0].key_id +
|
||||
s.encrypted_license().keys[0].key_id_length);
|
||||
s.key_array()[0].key_id = &bad_buffer[0];
|
||||
std::string double_message = DuplicateMessage(s.encrypted_license());
|
||||
s.key_array()[0].key_id.offset += s.message_size();
|
||||
|
||||
OEMCryptoResult sts = 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(), NULL, 0,
|
||||
NULL, OEMCrypto_ContentLicense);
|
||||
s.session_id(), reinterpret_cast<const uint8_t*>(double_message.data()),
|
||||
s.message_size(), &s.signature()[0], s.signature().size(),
|
||||
s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), s.num_keys(),
|
||||
s.key_array(), GetSubstring(), GetSubstring(), OEMCrypto_ContentLicense);
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
||||
}
|
||||
|
||||
@@ -1028,16 +1037,14 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange4) {
|
||||
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0));
|
||||
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
|
||||
|
||||
vector<uint8_t> bad_buffer(
|
||||
s.encrypted_license().keys[1].key_data,
|
||||
s.encrypted_license().keys[1].key_data + wvoec::KEY_SIZE);
|
||||
s.key_array()[1].key_data = &bad_buffer[0];
|
||||
std::string double_message = DuplicateMessage(s.encrypted_license());
|
||||
s.key_array()[1].key_data.offset += s.message_size();
|
||||
|
||||
OEMCryptoResult sts = 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(), NULL, 0,
|
||||
NULL, OEMCrypto_ContentLicense);
|
||||
s.session_id(), reinterpret_cast<const uint8_t*>(double_message.data()),
|
||||
s.message_size(), &s.signature()[0], s.signature().size(),
|
||||
s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), s.num_keys(),
|
||||
s.key_array(), GetSubstring(), GetSubstring(), OEMCrypto_ContentLicense);
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
||||
}
|
||||
|
||||
@@ -1047,15 +1054,13 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange5) {
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
|
||||
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0));
|
||||
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
|
||||
vector<uint8_t> bad_buffer(s.encrypted_license().keys[1].key_iv,
|
||||
s.encrypted_license().keys[1].key_iv +
|
||||
sizeof(s.encrypted_license().keys[1].key_iv));
|
||||
s.key_array()[1].key_data_iv = &bad_buffer[0];
|
||||
std::string double_message = DuplicateMessage(s.encrypted_license());
|
||||
s.key_array()[1].key_data_iv.offset += s.message_size();
|
||||
OEMCryptoResult sts = 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(), NULL, 0,
|
||||
NULL, OEMCrypto_ContentLicense);
|
||||
s.session_id(), reinterpret_cast<const uint8_t*>(double_message.data()),
|
||||
s.message_size(), &s.signature()[0], s.signature().size(),
|
||||
s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), s.num_keys(),
|
||||
s.key_array(), GetSubstring(), GetSubstring(), OEMCrypto_ContentLicense);
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
||||
}
|
||||
|
||||
@@ -1066,16 +1071,14 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange6) {
|
||||
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0));
|
||||
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
|
||||
|
||||
vector<uint8_t> bad_buffer(s.key_array()[2].key_control,
|
||||
s.key_array()[2].key_control +
|
||||
sizeof(s.encrypted_license().keys[1].control));
|
||||
s.key_array()[2].key_control = &bad_buffer[0];
|
||||
std::string double_message = DuplicateMessage(s.encrypted_license());
|
||||
s.key_array()[2].key_control.offset += s.message_size();
|
||||
|
||||
OEMCryptoResult sts = 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(), NULL, 0,
|
||||
NULL, OEMCrypto_ContentLicense);
|
||||
s.session_id(), reinterpret_cast<const uint8_t*>(double_message.data()),
|
||||
s.message_size(), &s.signature()[0], s.signature().size(),
|
||||
s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), s.num_keys(),
|
||||
s.key_array(), GetSubstring(), GetSubstring(), OEMCrypto_ContentLicense);
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
||||
}
|
||||
|
||||
@@ -1085,17 +1088,14 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange7) {
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
|
||||
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0));
|
||||
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
|
||||
vector<uint8_t> bad_buffer(
|
||||
s.key_array()[2].key_control_iv,
|
||||
s.key_array()[2].key_control_iv +
|
||||
sizeof(s.encrypted_license().keys[1].control_iv));
|
||||
s.key_array()[2].key_control_iv = &bad_buffer[0];
|
||||
std::string double_message = DuplicateMessage(s.encrypted_license());
|
||||
s.key_array()[2].key_control_iv.offset += s.message_size();
|
||||
|
||||
OEMCryptoResult sts = 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(), NULL, 0,
|
||||
NULL, OEMCrypto_ContentLicense);
|
||||
s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(),
|
||||
s.num_keys(), s.key_array(), GetSubstring(), GetSubstring(),
|
||||
OEMCrypto_ContentLicense);
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
||||
}
|
||||
|
||||
@@ -1103,15 +1103,14 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadNonce) {
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
|
||||
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0,
|
||||
wvoec::kControlNonceEnabled,
|
||||
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, wvoec::kControlNonceEnabled,
|
||||
42)); // bad nonce.
|
||||
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
|
||||
OEMCryptoResult sts = 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(), NULL, 0,
|
||||
NULL, OEMCrypto_ContentLicense);
|
||||
s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(),
|
||||
s.num_keys(), s.key_array(), GetSubstring(), GetSubstring(),
|
||||
OEMCrypto_ContentLicense);
|
||||
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
||||
}
|
||||
@@ -1129,15 +1128,14 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithRepeatNonce) {
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
|
||||
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0,
|
||||
wvoec::kControlNonceEnabled,
|
||||
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, wvoec::kControlNonceEnabled,
|
||||
nonce)); // same old nonce.
|
||||
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
|
||||
OEMCryptoResult sts = 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(), NULL, 0,
|
||||
NULL, OEMCrypto_ContentLicense);
|
||||
s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(),
|
||||
s.num_keys(), s.key_array(), GetSubstring(), GetSubstring(),
|
||||
OEMCrypto_ContentLicense);
|
||||
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
||||
}
|
||||
@@ -1161,9 +1159,9 @@ TEST_F(OEMCryptoSessionTests, LoadKeyNonceReopenSession) {
|
||||
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
|
||||
OEMCryptoResult sts = 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(), NULL, 0,
|
||||
NULL, OEMCrypto_ContentLicense);
|
||||
s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(),
|
||||
s.num_keys(), s.key_array(), GetSubstring(), GetSubstring(),
|
||||
OEMCrypto_ContentLicense);
|
||||
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
||||
}
|
||||
@@ -1186,9 +1184,9 @@ TEST_F(OEMCryptoSessionTests, LoadKeyNonceWrongSession) {
|
||||
ASSERT_NO_FATAL_FAILURE(s2.EncryptAndSign());
|
||||
OEMCryptoResult sts = OEMCrypto_LoadKeys(
|
||||
s2.session_id(), s2.message_ptr(), s2.message_size(), &s2.signature()[0],
|
||||
s2.signature().size(), s2.encrypted_license().mac_key_iv,
|
||||
s2.encrypted_license().mac_keys, s2.num_keys(), s2.key_array(), NULL, 0,
|
||||
NULL, OEMCrypto_ContentLicense);
|
||||
s2.signature().size(), s2.enc_mac_keys_iv_substr(),
|
||||
s2.enc_mac_keys_substr(), s2.num_keys(), s2.key_array(), GetSubstring(),
|
||||
GetSubstring(), OEMCrypto_ContentLicense);
|
||||
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
||||
}
|
||||
@@ -1202,9 +1200,9 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadVerification) {
|
||||
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
|
||||
OEMCryptoResult sts = 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(), NULL, 0,
|
||||
NULL, OEMCrypto_ContentLicense);
|
||||
s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(),
|
||||
s.num_keys(), s.key_array(), GetSubstring(), GetSubstring(),
|
||||
OEMCrypto_ContentLicense);
|
||||
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
||||
}
|
||||
@@ -1238,9 +1236,9 @@ TEST_P(SessionTestAlternateVerification, LoadKeys) {
|
||||
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
|
||||
OEMCryptoResult sts = 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(), NULL, 0,
|
||||
NULL, OEMCrypto_ContentLicense);
|
||||
s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(),
|
||||
s.num_keys(), s.key_array(), GetSubstring(), GetSubstring(),
|
||||
OEMCrypto_ContentLicense);
|
||||
// If this is a future API, then LoadKeys should fail.
|
||||
if (global_features.api_version < target_api_) {
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
||||
@@ -1266,9 +1264,9 @@ TEST_F(OEMCryptoSessionTests, LoadKeysBadSignature) {
|
||||
s.signature()[0] ^= 42; // Bad signature.
|
||||
OEMCryptoResult sts = 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(), NULL, 0,
|
||||
NULL, OEMCrypto_ContentLicense);
|
||||
s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(),
|
||||
s.num_keys(), s.key_array(), GetSubstring(), GetSubstring(),
|
||||
OEMCrypto_ContentLicense);
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
||||
}
|
||||
|
||||
@@ -1280,9 +1278,9 @@ TEST_F(OEMCryptoSessionTests, LoadKeysWithNoDerivedKeys) {
|
||||
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
|
||||
OEMCryptoResult sts = 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(), NULL, 0,
|
||||
NULL, OEMCrypto_ContentLicense);
|
||||
s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(),
|
||||
s.num_keys(), s.key_array(), GetSubstring(), GetSubstring(),
|
||||
OEMCrypto_ContentLicense);
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
||||
}
|
||||
|
||||
@@ -1298,8 +1296,9 @@ TEST_F(OEMCryptoSessionTests, LoadKeyNoKeys) {
|
||||
ASSERT_NE(
|
||||
OEMCrypto_SUCCESS,
|
||||
OEMCrypto_LoadKeys(s.session_id(), s.message_ptr(), s.message_size(),
|
||||
&s.signature()[0], s.signature().size(), NULL, NULL,
|
||||
kNoKeys, s.key_array(), NULL, 0, NULL,
|
||||
&s.signature()[0], s.signature().size(),
|
||||
s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(),
|
||||
kNoKeys, s.key_array(), GetSubstring(), GetSubstring(),
|
||||
OEMCrypto_ContentLicense));
|
||||
}
|
||||
|
||||
@@ -1314,8 +1313,9 @@ TEST_F(OEMCryptoSessionTests, LoadKeyNoKeyWithNonce) {
|
||||
ASSERT_NE(
|
||||
OEMCrypto_SUCCESS,
|
||||
OEMCrypto_LoadKeys(s.session_id(), s.message_ptr(), s.message_size(),
|
||||
&s.signature()[0], s.signature().size(), NULL, NULL,
|
||||
kNoKeys, s.key_array(), NULL, 0, NULL,
|
||||
&s.signature()[0], s.signature().size(),
|
||||
s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(),
|
||||
kNoKeys, s.key_array(), GetSubstring(), GetSubstring(),
|
||||
OEMCrypto_ContentLicense));
|
||||
}
|
||||
|
||||
@@ -1370,9 +1370,9 @@ TEST_F(OEMCryptoSessionTests, AntiRollbackHardwareRequired) {
|
||||
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
|
||||
OEMCryptoResult sts = 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(), NULL, 0,
|
||||
NULL, OEMCrypto_ContentLicense);
|
||||
s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(),
|
||||
s.num_keys(), s.key_array(), GetSubstring(), GetSubstring(),
|
||||
OEMCrypto_ContentLicense);
|
||||
if (OEMCrypto_IsAntiRollbackHwPresent()) {
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
} else {
|
||||
@@ -1394,44 +1394,39 @@ TEST_F(OEMCryptoSessionTests, CheckMinimumPatchLevel) {
|
||||
OEMCrypto_SUCCESS,
|
||||
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(), NULL, 0, NULL,
|
||||
OEMCrypto_ContentLicense));
|
||||
s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(),
|
||||
s.num_keys(), s.key_array(), GetSubstring(),
|
||||
GetSubstring(), OEMCrypto_ContentLicense));
|
||||
}
|
||||
if (patch_level < 0x3F) {
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
|
||||
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
|
||||
0, (patch_level + 1) << wvoec::kControlSecurityPatchLevelShift,
|
||||
0));
|
||||
0, (patch_level + 1) << wvoec::kControlSecurityPatchLevelShift, 0));
|
||||
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_ERROR_UNKNOWN_FAILURE,
|
||||
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(), NULL, 0, NULL,
|
||||
OEMCrypto_ContentLicense));
|
||||
s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(),
|
||||
s.num_keys(), s.key_array(), GetSubstring(),
|
||||
GetSubstring(), OEMCrypto_ContentLicense));
|
||||
}
|
||||
if (patch_level > 0) {
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
|
||||
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
|
||||
0, (patch_level - 1) << wvoec::kControlSecurityPatchLevelShift,
|
||||
0));
|
||||
0, (patch_level - 1) << wvoec::kControlSecurityPatchLevelShift, 0));
|
||||
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
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(), NULL, 0, NULL,
|
||||
OEMCrypto_ContentLicense));
|
||||
s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(),
|
||||
s.num_keys(), s.key_array(), GetSubstring(),
|
||||
GetSubstring(), OEMCrypto_ContentLicense));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4781,7 +4776,6 @@ TEST_F(UsageTableTest, RepeatOnlineLicense) {
|
||||
Session s2;
|
||||
ASSERT_NO_FATAL_FAILURE(s2.open());
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s2));
|
||||
uint8_t* pst_ptr = s.encrypted_license().pst;
|
||||
s2.LoadUsageEntry(s); // Use the same entry.
|
||||
// Trying to reuse a PST is bad. We use session ID for s2, everything else
|
||||
// reused from s.
|
||||
@@ -4789,10 +4783,9 @@ TEST_F(UsageTableTest, RepeatOnlineLicense) {
|
||||
OEMCrypto_SUCCESS,
|
||||
OEMCrypto_LoadKeys(s2.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,
|
||||
OEMCrypto_ContentLicense));
|
||||
s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(),
|
||||
s.num_keys(), s.key_array(), s.pst_substr(),
|
||||
GetSubstring(), OEMCrypto_ContentLicense));
|
||||
ASSERT_NO_FATAL_FAILURE(s2.close());
|
||||
}
|
||||
|
||||
@@ -4808,9 +4801,9 @@ TEST_F(UsageTableTest, OnlineEmptyPST) {
|
||||
ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry());
|
||||
OEMCryptoResult sts = 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(), NULL, 0,
|
||||
NULL, OEMCrypto_ContentLicense);
|
||||
s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(),
|
||||
s.num_keys(), s.key_array(), GetSubstring(), GetSubstring(),
|
||||
OEMCrypto_ContentLicense);
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
||||
ASSERT_NO_FATAL_FAILURE(s.close());
|
||||
}
|
||||
@@ -4828,9 +4821,9 @@ TEST_F(UsageTableTest, OnlineMissingEntry) {
|
||||
// ENTRY NOT CREATED: ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry());
|
||||
OEMCryptoResult sts = 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(),
|
||||
s.encrypted_license().pst, pst.length(), NULL, OEMCrypto_ContentLicense);
|
||||
s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(),
|
||||
s.num_keys(), s.key_array(), s.pst_substr(), GetSubstring(),
|
||||
OEMCrypto_ContentLicense);
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
||||
ASSERT_NO_FATAL_FAILURE(s.close());
|
||||
}
|
||||
@@ -4838,9 +4831,8 @@ TEST_F(UsageTableTest, OnlineMissingEntry) {
|
||||
TEST_P(UsageTableTestWithMAC, GenericCryptoEncrypt) {
|
||||
std::string pst = "A PST";
|
||||
uint32_t nonce = session_.get_nonce();
|
||||
MakeFourKeys(
|
||||
0, wvoec::kControlNonceEnabled | wvoec::kControlNonceRequired,
|
||||
nonce, pst);
|
||||
MakeFourKeys(0, wvoec::kControlNonceEnabled | wvoec::kControlNonceRequired,
|
||||
nonce, pst);
|
||||
ASSERT_NO_FATAL_FAILURE(session_.EncryptAndSign());
|
||||
ASSERT_NO_FATAL_FAILURE(session_.CreateNewUsageEntry());
|
||||
ASSERT_NO_FATAL_FAILURE(session_.LoadTestKeys(pst, new_mac_keys_));
|
||||
@@ -5116,15 +5108,13 @@ TEST_P(UsageTableTestWithMAC, BadReloadOfflineLicense) {
|
||||
0, wvoec::kControlNonceOrEntry, s2.get_nonce(), pst));
|
||||
ASSERT_NO_FATAL_FAILURE(s2.EncryptAndSign());
|
||||
ASSERT_NO_FATAL_FAILURE(s2.LoadUsageEntry(s));
|
||||
uint8_t* pst_ptr = s2.encrypted_license().pst;
|
||||
ASSERT_NE(
|
||||
OEMCrypto_SUCCESS,
|
||||
OEMCrypto_LoadKeys(s2.session_id(), s2.message_ptr(), s2.message_size(),
|
||||
&s2.signature()[0], s2.signature().size(),
|
||||
s2.encrypted_license().mac_key_iv,
|
||||
s2.encrypted_license().mac_keys, s.num_keys(),
|
||||
s2.key_array(), pst_ptr, pst.length(), NULL,
|
||||
OEMCrypto_ContentLicense));
|
||||
s2.enc_mac_keys_iv_substr(), s2.enc_mac_keys_substr(),
|
||||
s.num_keys(), s2.key_array(), s2.pst_substr(),
|
||||
GetSubstring(), OEMCrypto_ContentLicense));
|
||||
ASSERT_NO_FATAL_FAILURE(s2.close());
|
||||
|
||||
// Offline license with same mac keys should still be OK.
|
||||
@@ -5133,10 +5123,10 @@ TEST_P(UsageTableTestWithMAC, BadReloadOfflineLicense) {
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
|
||||
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys(pst, new_mac_keys_));
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
s.GenerateVerifyReport(pst, kUnused,
|
||||
loaded, // license loaded.
|
||||
0, 0)); // first and last decrypt
|
||||
ASSERT_NO_FATAL_FAILURE(s.GenerateVerifyReport(pst, kUnused,
|
||||
loaded, // license loaded.
|
||||
0,
|
||||
0)); // first and last decrypt
|
||||
}
|
||||
|
||||
// An offline license should not load on the first call if the nonce is bad.
|
||||
@@ -5149,12 +5139,11 @@ TEST_P(UsageTableTestWithMAC, OfflineBadNonce) {
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
s.FillSimpleMessage(0, wvoec::kControlNonceOrEntry, 42, pst));
|
||||
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
|
||||
uint8_t* pst_ptr = s.encrypted_license().pst;
|
||||
OEMCryptoResult sts = 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, OEMCrypto_ContentLicense);
|
||||
s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(),
|
||||
s.num_keys(), s.key_array(), s.pst_substr(), GetSubstring(),
|
||||
OEMCrypto_ContentLicense);
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
||||
ASSERT_NO_FATAL_FAILURE(s.close());
|
||||
}
|
||||
@@ -5170,9 +5159,9 @@ TEST_P(UsageTableTestWithMAC, OfflineEmptyPST) {
|
||||
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
|
||||
OEMCryptoResult sts = 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(), NULL, 0,
|
||||
NULL, OEMCrypto_ContentLicense);
|
||||
s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(),
|
||||
s.num_keys(), s.key_array(), GetSubstring(), GetSubstring(),
|
||||
OEMCrypto_ContentLicense);
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
||||
ASSERT_NO_FATAL_FAILURE(s.close());
|
||||
}
|
||||
@@ -5188,14 +5177,12 @@ TEST_P(UsageTableTestWithMAC, ReloadOfflineWrongPST) {
|
||||
ASSERT_NO_FATAL_FAILURE(s.ReloadUsageEntry());
|
||||
memcpy(s.license().pst, bad_pst.c_str(), bad_pst.length());
|
||||
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
|
||||
uint8_t* pst_ptr = s.encrypted_license().pst;
|
||||
ASSERT_NE(
|
||||
OEMCrypto_SUCCESS,
|
||||
OEMCrypto_LoadKeys(s.session_id(), s.message_ptr(), s.message_size(),
|
||||
&s.signature()[0], s.signature().size(), NULL, NULL,
|
||||
s.num_keys(), s.key_array(),
|
||||
pst_ptr, bad_pst.length(), NULL,
|
||||
OEMCrypto_ContentLicense));
|
||||
ASSERT_NE(OEMCrypto_SUCCESS,
|
||||
OEMCrypto_LoadKeys(
|
||||
s.session_id(), s.message_ptr(), s.message_size(),
|
||||
&s.signature()[0], s.signature().size(), GetSubstring(),
|
||||
GetSubstring(), s.num_keys(), s.key_array(), s.pst_substr(),
|
||||
GetSubstring(), OEMCrypto_ContentLicense));
|
||||
}
|
||||
|
||||
TEST_P(UsageTableTestWithMAC, DeactivateOfflineLicense) {
|
||||
@@ -5222,15 +5209,13 @@ TEST_P(UsageTableTestWithMAC, DeactivateOfflineLicense) {
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s2));
|
||||
ASSERT_NO_FATAL_FAILURE(s2.LoadUsageEntry(s));
|
||||
// Offile license can not be reused if it has been deactivated.
|
||||
uint8_t* pst_ptr = s.encrypted_license().pst;
|
||||
EXPECT_NE(
|
||||
OEMCrypto_SUCCESS,
|
||||
OEMCrypto_LoadKeys(s2.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,
|
||||
OEMCrypto_ContentLicense));
|
||||
s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(),
|
||||
s.num_keys(), s.key_array(), s.pst_substr(),
|
||||
GetSubstring(), OEMCrypto_ContentLicense));
|
||||
s2.close();
|
||||
// But we can still generate a report.
|
||||
Session s3;
|
||||
@@ -5265,15 +5250,13 @@ TEST_P(UsageTableTestWithMAC, DeactivateOfflineLicenseUnused) {
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s2));
|
||||
ASSERT_NO_FATAL_FAILURE(s2.LoadUsageEntry(s1));
|
||||
// Offline license can not be reused if it has been deactivated.
|
||||
uint8_t* pst_ptr = s1.encrypted_license().pst;
|
||||
EXPECT_NE(
|
||||
OEMCrypto_SUCCESS,
|
||||
OEMCrypto_LoadKeys(s2.session_id(), s1.message_ptr(), s1.message_size(),
|
||||
&s1.signature()[0], s1.signature().size(),
|
||||
s1.encrypted_license().mac_key_iv,
|
||||
s1.encrypted_license().mac_keys, s1.num_keys(),
|
||||
s1.key_array(), pst_ptr, pst.length(), NULL,
|
||||
OEMCrypto_ContentLicense));
|
||||
s1.enc_mac_keys_iv_substr(), s1.enc_mac_keys_substr(),
|
||||
s1.num_keys(), s1.key_array(), s1.pst_substr(),
|
||||
GetSubstring(), OEMCrypto_ContentLicense));
|
||||
s2.close();
|
||||
// But we can still generate a report.
|
||||
Session s3;
|
||||
@@ -5293,15 +5276,13 @@ TEST_P(UsageTableTestWithMAC, BadRange) {
|
||||
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
|
||||
0, wvoec::kControlNonceOrEntry, s.get_nonce(), pst));
|
||||
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
|
||||
uint8_t* pst_ptr = s.license().pst; // Bad: not in encrypted_license.
|
||||
ASSERT_NE(
|
||||
OEMCrypto_SUCCESS,
|
||||
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,
|
||||
OEMCrypto_ContentLicense));
|
||||
s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(),
|
||||
s.num_keys(), s.key_array(), s.pst_substr(),
|
||||
GetSubstring(), OEMCrypto_ContentLicense));
|
||||
}
|
||||
|
||||
TEST_F(UsageTableTest, UpdateFailsWithNullPtr) {
|
||||
@@ -5371,15 +5352,13 @@ class UsageTableDefragTest : public UsageTableTest {
|
||||
&s->encrypted_usage_entry()[0],
|
||||
s->encrypted_usage_entry().size()));
|
||||
|
||||
uint8_t* pst_ptr = s->encrypted_license().pst;
|
||||
ASSERT_NE(
|
||||
OEMCrypto_SUCCESS,
|
||||
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, s->pst().length(), NULL,
|
||||
OEMCrypto_ContentLicense));
|
||||
ASSERT_NE(OEMCrypto_SUCCESS,
|
||||
OEMCrypto_LoadKeys(
|
||||
s->session_id(), s->message_ptr(), s->message_size(),
|
||||
&s->signature()[0], s->signature().size(),
|
||||
s->enc_mac_keys_iv_substr(), s->enc_mac_keys_substr(),
|
||||
s->num_keys(), s->key_array(), s->pst_substr(),
|
||||
GetSubstring(), OEMCrypto_ContentLicense));
|
||||
ASSERT_NO_FATAL_FAILURE(s->close());
|
||||
}
|
||||
|
||||
@@ -6056,15 +6035,13 @@ TEST_F(UsageTableTest, LoadSharedLicenseWithNoMaster) {
|
||||
htonl(wvoec::kSharedLicense);
|
||||
}
|
||||
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
|
||||
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,
|
||||
OEMCrypto_ContentLicense));
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_ERROR_MISSING_MASTER,
|
||||
OEMCrypto_LoadKeys(s.session_id(), s.message_ptr(), s.message_size(),
|
||||
&s.signature()[0], s.signature().size(),
|
||||
s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(),
|
||||
s.num_keys(), s.key_array(), s.pst_substr(),
|
||||
GetSubstring(), OEMCrypto_ContentLicense));
|
||||
ASSERT_NO_FATAL_FAILURE(s.close());
|
||||
}
|
||||
|
||||
@@ -6091,16 +6068,14 @@ TEST_F(UsageTableTest, PSTLargeBuffer) {
|
||||
ASSERT_NO_FATAL_FAILURE(s2.open());
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s2));
|
||||
// Offile license can not be reused if it has been deactivated.
|
||||
uint8_t* pst_ptr = s.encrypted_license().pst;
|
||||
ASSERT_NO_FATAL_FAILURE(s2.LoadUsageEntry(s));
|
||||
EXPECT_NE(
|
||||
OEMCrypto_SUCCESS,
|
||||
OEMCrypto_LoadKeys(s2.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,
|
||||
OEMCrypto_ContentLicense));
|
||||
s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(),
|
||||
s.num_keys(), s.key_array(), s.pst_substr(),
|
||||
GetSubstring(), OEMCrypto_ContentLicense));
|
||||
s2.close();
|
||||
// But we can still generate a report.
|
||||
Session s3;
|
||||
|
||||
Reference in New Issue
Block a user