Refactor missed provisioning and renewal tests
Merge from Widevine repo of http://go/wvgerrit/169079 Bug: 253779846 Merged from https://widevine-internal-review.googlesource.com/167738 Change-Id: If8fc484f02fc1544977f1fb3a5fe1fa42d7367d7
This commit is contained in:
committed by
Fred Gylys-Colwell
parent
225a3e50ed
commit
f83698a164
@@ -6,6 +6,9 @@
|
|||||||
#include "oemcrypto_license_test.h"
|
#include "oemcrypto_license_test.h"
|
||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
#include "test_sleep.h"
|
||||||
|
|
||||||
|
using ::testing::Range;
|
||||||
|
|
||||||
namespace wvoec {
|
namespace wvoec {
|
||||||
|
|
||||||
@@ -800,5 +803,169 @@ TEST_F(OEMCryptoSessionTests, CheckMinimumPatchLevel) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Load, Refresh Keys Test
|
||||||
|
//
|
||||||
|
|
||||||
|
// Refresh keys should work if the license uses a nonce.
|
||||||
|
TEST_P(OEMCryptoRefreshTest, RefreshWithNonce) {
|
||||||
|
LoadLicense();
|
||||||
|
RenewalRoundTrip renewal_messages(&license_messages_);
|
||||||
|
MakeRenewalRequest(&renewal_messages);
|
||||||
|
LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh keys should work if the license does not use a nonce.
|
||||||
|
TEST_P(OEMCryptoRefreshTest, RefreshNoNonce) {
|
||||||
|
license_messages_.set_control(0);
|
||||||
|
LoadLicense();
|
||||||
|
RenewalRoundTrip renewal_messages(&license_messages_);
|
||||||
|
MakeRenewalRequest(&renewal_messages);
|
||||||
|
LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh keys should NOT work if a license has not been loaded.
|
||||||
|
TEST_P(OEMCryptoRefreshTestAPI16, RefreshNoLicense) {
|
||||||
|
Session s;
|
||||||
|
s.open();
|
||||||
|
constexpr size_t message_size = kMaxCoreMessage + 42;
|
||||||
|
std::vector<uint8_t> data(message_size);
|
||||||
|
for (size_t i = 0; i < data.size(); i++) data[i] = i & 0xFF;
|
||||||
|
size_t gen_signature_length = 0;
|
||||||
|
size_t core_message_length = 0;
|
||||||
|
OEMCryptoResult sts = OEMCrypto_PrepAndSignRenewalRequest(
|
||||||
|
s.session_id(), data.data(), data.size(), &core_message_length, nullptr,
|
||||||
|
&gen_signature_length);
|
||||||
|
ASSERT_LT(core_message_length, message_size);
|
||||||
|
if (sts == OEMCrypto_ERROR_SHORT_BUFFER) {
|
||||||
|
vector<uint8_t> gen_signature(gen_signature_length);
|
||||||
|
sts = OEMCrypto_PrepAndSignRenewalRequest(
|
||||||
|
s.session_id(), data.data(), data.size(), &core_message_length,
|
||||||
|
gen_signature.data(), &gen_signature_length);
|
||||||
|
}
|
||||||
|
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh keys should fail if the nonce is not in the session.
|
||||||
|
TEST_P(OEMCryptoRefreshTestAPI16, RefreshBadNonce) {
|
||||||
|
LoadLicense();
|
||||||
|
RenewalRoundTrip renewal_messages(&license_messages_);
|
||||||
|
MakeRenewalRequest(&renewal_messages);
|
||||||
|
renewal_messages.core_request().nonce ^= 42;
|
||||||
|
LoadRenewal(&renewal_messages, OEMCrypto_ERROR_INVALID_NONCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh keys should fail if the session_id does not match the license.
|
||||||
|
TEST_P(OEMCryptoRefreshTestAPI16, RefreshBadSessionID) {
|
||||||
|
LoadLicense();
|
||||||
|
RenewalRoundTrip renewal_messages(&license_messages_);
|
||||||
|
MakeRenewalRequest(&renewal_messages);
|
||||||
|
renewal_messages.core_request().session_id += 1;
|
||||||
|
LoadRenewal(&renewal_messages, OEMCrypto_ERROR_INVALID_NONCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh keys should handle the maximum message size.
|
||||||
|
TEST_P(OEMCryptoRefreshTest, RefreshLargeBuffer) {
|
||||||
|
LoadLicense();
|
||||||
|
RenewalRoundTrip renewal_messages(&license_messages_);
|
||||||
|
const size_t max_size = GetResourceValue(kLargeMessageSize);
|
||||||
|
renewal_messages.set_message_size(max_size);
|
||||||
|
MakeRenewalRequest(&renewal_messages);
|
||||||
|
LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This situation would occur if an app only uses one key in the license. When
|
||||||
|
// that happens, SelectKey would be called before the first decrypt, and then
|
||||||
|
// would not need to be called again, even if the license is refreshed.
|
||||||
|
TEST_P(OEMCryptoRefreshTest, RefreshWithNoSelectKey) {
|
||||||
|
LoadLicense();
|
||||||
|
|
||||||
|
// Call select key before the refresh. No calls below to TestDecryptCTR with
|
||||||
|
// select key set to true.
|
||||||
|
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(true));
|
||||||
|
|
||||||
|
// This should still be valid key, even if the refresh failed, because this
|
||||||
|
// is before the original license duration.
|
||||||
|
wvutil::TestSleep::Sleep(kShortSleep);
|
||||||
|
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(false));
|
||||||
|
|
||||||
|
// This should be after duration of the original license, but before the
|
||||||
|
// expiration of the refresh message. This should fail until we have loaded
|
||||||
|
// the renewal.
|
||||||
|
wvutil::TestSleep::Sleep(kShortSleep + kLongSleep);
|
||||||
|
ASSERT_NO_FATAL_FAILURE(
|
||||||
|
session_.TestDecryptCTR(false, OEMCrypto_ERROR_KEY_EXPIRED));
|
||||||
|
|
||||||
|
RenewalRoundTrip renewal_messages(&license_messages_);
|
||||||
|
MakeRenewalRequest(&renewal_messages);
|
||||||
|
LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS);
|
||||||
|
|
||||||
|
// After we've loaded the renewal, decrypt should succeed again.
|
||||||
|
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that playback clock is correctly started and that the license can be
|
||||||
|
// renewed.
|
||||||
|
TEST_P(OEMCryptoRefreshTest, RenewLicenseLoadSuccess) {
|
||||||
|
license_messages_.core_response().renewal_delay_base = OEMCrypto_License_Load;
|
||||||
|
timer_limits_.rental_duration_seconds = kDuration; // 2 seconds.
|
||||||
|
timer_limits_.initial_renewal_duration_seconds = kLongDuration; // 5 seconds.
|
||||||
|
// First version to support Renew on Load.
|
||||||
|
constexpr uint32_t kFeatureVersion = 18;
|
||||||
|
|
||||||
|
// Loading the license should start the playback clock.
|
||||||
|
LoadLicense();
|
||||||
|
// Sleep until just after rental window is over.
|
||||||
|
wvutil::TestSleep::Sleep(kDuration + kShortSleep);
|
||||||
|
if (license_api_version_ < kFeatureVersion ||
|
||||||
|
global_features.api_version < kFeatureVersion) {
|
||||||
|
// If the feature is not supported, then we expect failure because the
|
||||||
|
// playback clock was not started and we are outside the rental window.
|
||||||
|
ASSERT_NO_FATAL_FAILURE(
|
||||||
|
session_.TestDecryptCTR(true, OEMCrypto_ERROR_KEY_EXPIRED));
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// If the feature is supported, we expect decrypt to work because we are
|
||||||
|
// still within the initial renewal window, and the playback clock should
|
||||||
|
// have started.
|
||||||
|
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(true, OEMCrypto_SUCCESS));
|
||||||
|
}
|
||||||
|
// This is after the initial renewal duration, so we expect failure before
|
||||||
|
// loading the renewal.
|
||||||
|
wvutil::TestSleep::Sleep(kShortSleep + kLongSleep);
|
||||||
|
ASSERT_NO_FATAL_FAILURE(
|
||||||
|
session_.TestDecryptCTR(false, OEMCrypto_ERROR_KEY_EXPIRED));
|
||||||
|
|
||||||
|
RenewalRoundTrip renewal_messages(&license_messages_);
|
||||||
|
MakeRenewalRequest(&renewal_messages);
|
||||||
|
LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS);
|
||||||
|
|
||||||
|
// After we've loaded the renewal, decrypt should succeed again.
|
||||||
|
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(OEMCryptoRefreshTest, RenewLicenseLoadOutsideRentalDuration) {
|
||||||
|
license_messages_.core_response().renewal_delay_base = OEMCrypto_License_Load;
|
||||||
|
timer_limits_.rental_duration_seconds = kDuration; // 2 seconds.
|
||||||
|
timer_limits_.initial_renewal_duration_seconds = kLongDuration; // 5 seconds.
|
||||||
|
|
||||||
|
// Sleep until just after rental window is over.
|
||||||
|
wvutil::TestSleep::Sleep(kDuration + kShortSleep);
|
||||||
|
// Loading the license should start the playback clock.
|
||||||
|
LoadLicense();
|
||||||
|
// If the license is loaded after the rental duration window, we expect
|
||||||
|
// failure.
|
||||||
|
ASSERT_NO_FATAL_FAILURE(
|
||||||
|
session_.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoRefreshTest,
|
||||||
|
Range<uint32_t>(kCurrentAPI - 1, kCurrentAPI + 1));
|
||||||
|
|
||||||
|
// These tests only work when the license has a core message.
|
||||||
|
INSTANTIATE_TEST_SUITE_P(TestAPI16, OEMCryptoRefreshTestAPI16,
|
||||||
|
Range<uint32_t>(kCoreMessagesAPI, kCurrentAPI + 1));
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
} // namespace wvoec
|
} // namespace wvoec
|
||||||
@@ -359,6 +359,52 @@ class LicenseWithUsageEntry {
|
|||||||
bool active_;
|
bool active_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class OEMCryptoRefreshTest : public OEMCryptoLicenseTest {
|
||||||
|
protected:
|
||||||
|
void SetUp() override {
|
||||||
|
OEMCryptoLicenseTest::SetUp();
|
||||||
|
// These values allow us to run a few simple duration tests or just start
|
||||||
|
// playback right away. All times are in seconds since the license was
|
||||||
|
// signed.
|
||||||
|
// Soft expiry false means timers are strictly enforce.
|
||||||
|
timer_limits_.soft_enforce_rental_duration = true;
|
||||||
|
timer_limits_.soft_enforce_playback_duration = false;
|
||||||
|
// Playback may begin immediately.
|
||||||
|
timer_limits_.earliest_playback_start_seconds = 0;
|
||||||
|
// First playback may be within the first two seconds.
|
||||||
|
timer_limits_.rental_duration_seconds = kDuration;
|
||||||
|
// Once started, playback may last two seconds without a renewal.
|
||||||
|
timer_limits_.initial_renewal_duration_seconds = kDuration;
|
||||||
|
// Total playback is not limited.
|
||||||
|
timer_limits_.total_playback_duration_seconds = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadLicense() {
|
||||||
|
license_messages_.core_response().timer_limits = timer_limits_;
|
||||||
|
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||||
|
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MakeRenewalRequest(RenewalRoundTrip* renewal_messages) {
|
||||||
|
ASSERT_NO_FATAL_FAILURE(renewal_messages->SignAndVerifyRequest());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(renewal_messages->CreateDefaultResponse());
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadRenewal(RenewalRoundTrip* renewal_messages,
|
||||||
|
OEMCryptoResult expected_result) {
|
||||||
|
ASSERT_NO_FATAL_FAILURE(renewal_messages->EncryptAndSignResponse());
|
||||||
|
ASSERT_EQ(expected_result, renewal_messages->LoadResponse());
|
||||||
|
}
|
||||||
|
|
||||||
|
ODK_TimerLimits timer_limits_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This class is for the refresh tests that should only be run on licenses with
|
||||||
|
// a core message.
|
||||||
|
class OEMCryptoRefreshTestAPI16 : public OEMCryptoRefreshTest {};
|
||||||
|
|
||||||
} // namespace wvoec
|
} // namespace wvoec
|
||||||
|
|
||||||
#endif // CDM_OEMCRYPTO_LICENSE_TEST_
|
#endif // CDM_OEMCRYPTO_LICENSE_TEST_
|
||||||
@@ -868,5 +868,195 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionLargeBuffer) {
|
|||||||
provisioning_messages.encoded_rsa_key()));
|
provisioning_messages.encoded_rsa_key()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that a wrapped RSA key can be loaded.
|
||||||
|
TEST_F(OEMCryptoLoadsCertificate, LoadWrappedRSAKey) {
|
||||||
|
ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey());
|
||||||
|
Session s;
|
||||||
|
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_));
|
||||||
|
}
|
||||||
|
|
||||||
|
class OEMCryptoLoadsCertVariousKeys : public OEMCryptoLoadsCertificate {
|
||||||
|
public:
|
||||||
|
void TestKey(const uint8_t* key, size_t key_length) {
|
||||||
|
encoded_rsa_key_.assign(key, key + key_length);
|
||||||
|
ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey());
|
||||||
|
Session s;
|
||||||
|
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(s.SetRsaPublicKeyFromPrivateKeyInfo(
|
||||||
|
encoded_rsa_key_.data(), encoded_rsa_key_.size()));
|
||||||
|
ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_));
|
||||||
|
|
||||||
|
LicenseRoundTrip license_messages(&s);
|
||||||
|
ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(license_messages.EncryptAndSignResponse());
|
||||||
|
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages.LoadResponse());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Test a 3072 bit RSA key certificate.
|
||||||
|
TEST_F(OEMCryptoLoadsCertVariousKeys, TestLargeRSAKey3072) {
|
||||||
|
TestKey(kTestRSAPKCS8PrivateKeyInfo3_3072,
|
||||||
|
sizeof(kTestRSAPKCS8PrivateKeyInfo3_3072));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test an RSA key certificate which has a private key generated using the
|
||||||
|
// Carmichael totient.
|
||||||
|
TEST_F(OEMCryptoLoadsCertVariousKeys, TestCarmichaelRSAKey) {
|
||||||
|
TestKey(kTestKeyRSACarmichael_2048, sizeof(kTestKeyRSACarmichael_2048));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OEMCryptoLoadsCertVariousKeys, TestCarmichaelNonZeroNormalDer) {
|
||||||
|
TestKey(kCarmichaelNonZeroNormalDer, kCarmichaelNonZeroNormalDerLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OEMCryptoLoadsCertVariousKeys, TestCarmichaelNonZeroShortDer) {
|
||||||
|
TestKey(kCarmichaelNonZeroShortDer, kCarmichaelNonZeroShortDerLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OEMCryptoLoadsCertVariousKeys, TestCarmichaelZeroNormalDer) {
|
||||||
|
TestKey(kCarmichaelZeroNormalDer, kCarmichaelZeroNormalDerLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OEMCryptoLoadsCertVariousKeys, TestCarmichaelZeroShortDer) {
|
||||||
|
TestKey(kCarmichaelZeroShortDer, kCarmichaelZeroShortDerLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OEMCryptoLoadsCertVariousKeys, TestDualNonZeroNormalDer) {
|
||||||
|
TestKey(kDualNonZeroNormalDer, kDualNonZeroNormalDerLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OEMCryptoLoadsCertVariousKeys, TestDualNonZeroShortDer) {
|
||||||
|
TestKey(kDualNonZeroShortDer, kDualNonZeroShortDerLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OEMCryptoLoadsCertVariousKeys, TestDualZeroNormalDer) {
|
||||||
|
TestKey(kDualZeroNormalDer, kDualZeroNormalDerLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OEMCryptoLoadsCertVariousKeys, TestDualZeroShortDer) {
|
||||||
|
TestKey(kDualZeroShortDer, kDualZeroShortDerLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OEMCryptoLoadsCertVariousKeys, TestEulerNonZeroNormalDer) {
|
||||||
|
TestKey(kEulerNonZeroNormalDer, kEulerNonZeroNormalDerLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OEMCryptoLoadsCertVariousKeys, TestEulerZeroNormalDer) {
|
||||||
|
TestKey(kEulerZeroNormalDer, kEulerZeroNormalDerLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This tests that two sessions can use different RSA keys simultaneously.
|
||||||
|
TEST_F(OEMCryptoLoadsCertificate, TestMultipleRSAKeys) {
|
||||||
|
ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey());
|
||||||
|
Session s1; // Session s1 loads the default rsa key, but doesn't use it
|
||||||
|
// until after s2 uses its key.
|
||||||
|
ASSERT_NO_FATAL_FAILURE(s1.open());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(s1.SetRsaPublicKeyFromPrivateKeyInfo(
|
||||||
|
encoded_rsa_key_.data(), encoded_rsa_key_.size()));
|
||||||
|
ASSERT_NO_FATAL_FAILURE(s1.LoadWrappedRsaDrmKey(wrapped_drm_key_));
|
||||||
|
|
||||||
|
Session s2; // Session s2 uses a different rsa key.
|
||||||
|
encoded_rsa_key_.assign(kTestRSAPKCS8PrivateKeyInfo4_2048,
|
||||||
|
kTestRSAPKCS8PrivateKeyInfo4_2048 +
|
||||||
|
sizeof(kTestRSAPKCS8PrivateKeyInfo4_2048));
|
||||||
|
ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(s2.open());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(s2.SetRsaPublicKeyFromPrivateKeyInfo(
|
||||||
|
encoded_rsa_key_.data(), encoded_rsa_key_.size()));
|
||||||
|
ASSERT_NO_FATAL_FAILURE(s2.LoadWrappedRsaDrmKey(wrapped_drm_key_));
|
||||||
|
LicenseRoundTrip license_messages2(&s2);
|
||||||
|
ASSERT_NO_FATAL_FAILURE(license_messages2.SignAndVerifyRequest());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(license_messages2.CreateDefaultResponse());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(license_messages2.EncryptAndSignResponse());
|
||||||
|
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages2.LoadResponse());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(s2.TestDecryptCTR());
|
||||||
|
s2.close();
|
||||||
|
|
||||||
|
// After s2 has loaded its rsa key, we continue using s1's key.
|
||||||
|
LicenseRoundTrip license_messages1(&s1);
|
||||||
|
ASSERT_NO_FATAL_FAILURE(license_messages1.SignAndVerifyRequest());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(license_messages1.CreateDefaultResponse());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(license_messages1.EncryptAndSignResponse());
|
||||||
|
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages1.LoadResponse());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(s1.TestDecryptCTR());
|
||||||
|
}
|
||||||
|
|
||||||
|
// This tests the maximum number of DRM private keys that OEMCrypto can load
|
||||||
|
TEST_F(OEMCryptoLoadsCertificate, TestMaxDRMKeys) {
|
||||||
|
const size_t max_total_keys = GetResourceValue(kMaxTotalDRMPrivateKeys);
|
||||||
|
std::vector<std::unique_ptr<Session>> sessions;
|
||||||
|
std::vector<std::unique_ptr<LicenseRoundTrip>> licenses;
|
||||||
|
|
||||||
|
// It should be able to load up to kMaxTotalDRMPrivateKeys keys
|
||||||
|
for (size_t i = 0; i < max_total_keys; i++) {
|
||||||
|
sessions.push_back(std::unique_ptr<Session>(new Session()));
|
||||||
|
licenses.push_back(std::unique_ptr<LicenseRoundTrip>(
|
||||||
|
new LicenseRoundTrip(sessions[i].get())));
|
||||||
|
const size_t key_index = i % kTestRSAPKCS8PrivateKeys_2048.size();
|
||||||
|
encoded_rsa_key_.assign(kTestRSAPKCS8PrivateKeys_2048[key_index].begin(),
|
||||||
|
kTestRSAPKCS8PrivateKeys_2048[key_index].end());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(sessions[i]->open());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(sessions[i].get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempts to load one more key than the kMaxTotalDRMPrivateKeys
|
||||||
|
if (global_features.provisioning_method == OEMCrypto_BootCertificateChain) {
|
||||||
|
Session s;
|
||||||
|
const size_t buffer_size = 5000; // Make sure it is large enough.
|
||||||
|
std::vector<uint8_t> public_key(buffer_size);
|
||||||
|
size_t public_key_size = buffer_size;
|
||||||
|
std::vector<uint8_t> public_key_signature(buffer_size);
|
||||||
|
size_t public_key_signature_size = buffer_size;
|
||||||
|
std::vector<uint8_t> wrapped_private_key(buffer_size);
|
||||||
|
size_t wrapped_private_key_size = buffer_size;
|
||||||
|
OEMCrypto_PrivateKeyType key_type;
|
||||||
|
OEMCryptoResult result = OEMCrypto_GenerateCertificateKeyPair(
|
||||||
|
s.session_id(), public_key.data(), &public_key_size,
|
||||||
|
public_key_signature.data(), &public_key_signature_size,
|
||||||
|
wrapped_private_key.data(), &wrapped_private_key_size, &key_type);
|
||||||
|
// Key creation is allowed to fail due to resource restriction
|
||||||
|
if (result != OEMCrypto_SUCCESS) {
|
||||||
|
ASSERT_TRUE(result == OEMCrypto_ERROR_INSUFFICIENT_RESOURCES ||
|
||||||
|
result == OEMCrypto_ERROR_TOO_MANY_KEYS);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Session s;
|
||||||
|
encoded_rsa_key_.assign(kTestRSAPKCS8PrivateKeyInfo2_2048,
|
||||||
|
kTestRSAPKCS8PrivateKeyInfo2_2048 +
|
||||||
|
sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048));
|
||||||
|
Session ps;
|
||||||
|
ProvisioningRoundTrip provisioning_messages(&ps, encoded_rsa_key_);
|
||||||
|
provisioning_messages.PrepareSession(keybox_);
|
||||||
|
ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse());
|
||||||
|
OEMCryptoResult result = provisioning_messages.LoadResponse();
|
||||||
|
// Key loading is allowed to fail due to resource restriction
|
||||||
|
if (result != OEMCrypto_SUCCESS) {
|
||||||
|
ASSERT_TRUE(result == OEMCrypto_ERROR_INSUFFICIENT_RESOURCES ||
|
||||||
|
result == OEMCrypto_ERROR_TOO_MANY_KEYS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Verifies that the DRM keys which are already loaded should still function
|
||||||
|
for (size_t i = 0; i < licenses.size(); i++) {
|
||||||
|
ASSERT_NO_FATAL_FAILURE(licenses[i]->SignAndVerifyRequest());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(licenses[i]->CreateDefaultResponse());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(licenses[i]->EncryptAndSignResponse());
|
||||||
|
ASSERT_EQ(OEMCrypto_SUCCESS, licenses[i]->LoadResponse());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(sessions[i]->TestDecryptCTR());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Devices that load certificates, should at least support RSA 2048 keys.
|
||||||
|
TEST_F(OEMCryptoLoadsCertificate, SupportsCertificatesAPI13) {
|
||||||
|
ASSERT_NE(0u,
|
||||||
|
OEMCrypto_Supports_RSA_2048bit & OEMCrypto_SupportedCertificates())
|
||||||
|
<< "Supported certificates is only " << OEMCrypto_SupportedCertificates();
|
||||||
|
}
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
} // namespace wvoec
|
} // namespace wvoec
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
#include "OEMCryptoCENC.h"
|
#include "OEMCryptoCENC.h"
|
||||||
|
#include "oec_extra_test_keys.h"
|
||||||
#include "oemcrypto_basic_test.h"
|
#include "oemcrypto_basic_test.h"
|
||||||
#include "oemcrypto_license_test.h"
|
#include "oemcrypto_license_test.h"
|
||||||
#include "oemcrypto_resource_test.h"
|
#include "oemcrypto_resource_test.h"
|
||||||
|
|||||||
@@ -1432,179 +1432,6 @@ INSTANTIATE_TEST_SUITE_P(TestHDCP, OEMCryptoSessionTestLoadCasKeysWithHDCP,
|
|||||||
Range(1, 6));
|
Range(1, 6));
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
/// @addtogroup renewal
|
|
||||||
/// @{
|
|
||||||
|
|
||||||
//
|
|
||||||
// Load, Refresh Keys Test
|
|
||||||
//
|
|
||||||
|
|
||||||
// This class is for the refresh tests that should only be run on licenses with
|
|
||||||
// a core message.
|
|
||||||
class OEMCryptoRefreshTestAPI16 : public OEMCryptoRefreshTest {};
|
|
||||||
|
|
||||||
// Refresh keys should work if the license uses a nonce.
|
|
||||||
TEST_P(OEMCryptoRefreshTest, RefreshWithNonce) {
|
|
||||||
LoadLicense();
|
|
||||||
RenewalRoundTrip renewal_messages(&license_messages_);
|
|
||||||
MakeRenewalRequest(&renewal_messages);
|
|
||||||
LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh keys should work if the license does not use a nonce.
|
|
||||||
TEST_P(OEMCryptoRefreshTest, RefreshNoNonce) {
|
|
||||||
license_messages_.set_control(0);
|
|
||||||
LoadLicense();
|
|
||||||
RenewalRoundTrip renewal_messages(&license_messages_);
|
|
||||||
MakeRenewalRequest(&renewal_messages);
|
|
||||||
LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh keys should NOT work if a license has not been loaded.
|
|
||||||
TEST_P(OEMCryptoRefreshTestAPI16, RefreshNoLicense) {
|
|
||||||
Session s;
|
|
||||||
s.open();
|
|
||||||
constexpr size_t message_size = kMaxCoreMessage + 42;
|
|
||||||
std::vector<uint8_t> data(message_size);
|
|
||||||
for (size_t i = 0; i < data.size(); i++) data[i] = i & 0xFF;
|
|
||||||
size_t gen_signature_length = 0;
|
|
||||||
size_t core_message_length = 0;
|
|
||||||
OEMCryptoResult sts = OEMCrypto_PrepAndSignRenewalRequest(
|
|
||||||
s.session_id(), data.data(), data.size(), &core_message_length, nullptr,
|
|
||||||
&gen_signature_length);
|
|
||||||
ASSERT_LT(core_message_length, message_size);
|
|
||||||
if (sts == OEMCrypto_ERROR_SHORT_BUFFER) {
|
|
||||||
vector<uint8_t> gen_signature(gen_signature_length);
|
|
||||||
sts = OEMCrypto_PrepAndSignRenewalRequest(
|
|
||||||
s.session_id(), data.data(), data.size(), &core_message_length,
|
|
||||||
gen_signature.data(), &gen_signature_length);
|
|
||||||
}
|
|
||||||
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh keys should fail if the nonce is not in the session.
|
|
||||||
TEST_P(OEMCryptoRefreshTestAPI16, RefreshBadNonce) {
|
|
||||||
LoadLicense();
|
|
||||||
RenewalRoundTrip renewal_messages(&license_messages_);
|
|
||||||
MakeRenewalRequest(&renewal_messages);
|
|
||||||
renewal_messages.core_request().nonce ^= 42;
|
|
||||||
LoadRenewal(&renewal_messages, OEMCrypto_ERROR_INVALID_NONCE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh keys should fail if the session_id does not match the license.
|
|
||||||
TEST_P(OEMCryptoRefreshTestAPI16, RefreshBadSessionID) {
|
|
||||||
LoadLicense();
|
|
||||||
RenewalRoundTrip renewal_messages(&license_messages_);
|
|
||||||
MakeRenewalRequest(&renewal_messages);
|
|
||||||
renewal_messages.core_request().session_id += 1;
|
|
||||||
LoadRenewal(&renewal_messages, OEMCrypto_ERROR_INVALID_NONCE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh keys should handle the maximum message size.
|
|
||||||
TEST_P(OEMCryptoRefreshTest, RefreshLargeBuffer) {
|
|
||||||
LoadLicense();
|
|
||||||
RenewalRoundTrip renewal_messages(&license_messages_);
|
|
||||||
const size_t max_size = GetResourceValue(kLargeMessageSize);
|
|
||||||
renewal_messages.set_message_size(max_size);
|
|
||||||
MakeRenewalRequest(&renewal_messages);
|
|
||||||
LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This situation would occur if an app only uses one key in the license. When
|
|
||||||
// that happens, SelectKey would be called before the first decrypt, and then
|
|
||||||
// would not need to be called again, even if the license is refreshed.
|
|
||||||
TEST_P(OEMCryptoRefreshTest, RefreshWithNoSelectKey) {
|
|
||||||
LoadLicense();
|
|
||||||
|
|
||||||
// Call select key before the refresh. No calls below to TestDecryptCTR with
|
|
||||||
// select key set to true.
|
|
||||||
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(true));
|
|
||||||
|
|
||||||
// This should still be valid key, even if the refresh failed, because this
|
|
||||||
// is before the original license duration.
|
|
||||||
wvutil::TestSleep::Sleep(kShortSleep);
|
|
||||||
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(false));
|
|
||||||
|
|
||||||
// This should be after duration of the original license, but before the
|
|
||||||
// expiration of the refresh message. This should fail until we have loaded
|
|
||||||
// the renewal.
|
|
||||||
wvutil::TestSleep::Sleep(kShortSleep + kLongSleep);
|
|
||||||
ASSERT_NO_FATAL_FAILURE(
|
|
||||||
session_.TestDecryptCTR(false, OEMCrypto_ERROR_KEY_EXPIRED));
|
|
||||||
|
|
||||||
RenewalRoundTrip renewal_messages(&license_messages_);
|
|
||||||
MakeRenewalRequest(&renewal_messages);
|
|
||||||
LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS);
|
|
||||||
|
|
||||||
// After we've loaded the renewal, decrypt should succeed again.
|
|
||||||
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that playback clock is correctly started and that the license can be
|
|
||||||
// renewed.
|
|
||||||
TEST_P(OEMCryptoRefreshTest, RenewLicenseLoadSuccess) {
|
|
||||||
license_messages_.core_response().renewal_delay_base = OEMCrypto_License_Load;
|
|
||||||
timer_limits_.rental_duration_seconds = kDuration; // 2 seconds.
|
|
||||||
timer_limits_.initial_renewal_duration_seconds = kLongDuration; // 5 seconds.
|
|
||||||
// First version to support Renew on Load.
|
|
||||||
constexpr uint32_t kFeatureVersion = 18;
|
|
||||||
|
|
||||||
// Loading the license should start the playback clock.
|
|
||||||
LoadLicense();
|
|
||||||
// Sleep until just after rental window is over.
|
|
||||||
wvutil::TestSleep::Sleep(kDuration + kShortSleep);
|
|
||||||
if (license_api_version_ < kFeatureVersion ||
|
|
||||||
global_features.api_version < kFeatureVersion) {
|
|
||||||
// If the feature is not supported, then we expect failure because the
|
|
||||||
// playback clock was not started and we are outside the rental window.
|
|
||||||
ASSERT_NO_FATAL_FAILURE(
|
|
||||||
session_.TestDecryptCTR(true, OEMCrypto_ERROR_KEY_EXPIRED));
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
// If the feature is supported, we expect decrypt to work because we are
|
|
||||||
// still within the initial renewal window, and the playback clock should
|
|
||||||
// have started.
|
|
||||||
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(true, OEMCrypto_SUCCESS));
|
|
||||||
}
|
|
||||||
// This is after the initial renewal duration, so we expect failure before
|
|
||||||
// loading the renewal.
|
|
||||||
wvutil::TestSleep::Sleep(kShortSleep + kLongSleep);
|
|
||||||
ASSERT_NO_FATAL_FAILURE(
|
|
||||||
session_.TestDecryptCTR(false, OEMCrypto_ERROR_KEY_EXPIRED));
|
|
||||||
|
|
||||||
RenewalRoundTrip renewal_messages(&license_messages_);
|
|
||||||
MakeRenewalRequest(&renewal_messages);
|
|
||||||
LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS);
|
|
||||||
|
|
||||||
// After we've loaded the renewal, decrypt should succeed again.
|
|
||||||
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_P(OEMCryptoRefreshTest, RenewLicenseLoadOutsideRentalDuration) {
|
|
||||||
license_messages_.core_response().renewal_delay_base = OEMCrypto_License_Load;
|
|
||||||
timer_limits_.rental_duration_seconds = kDuration; // 2 seconds.
|
|
||||||
timer_limits_.initial_renewal_duration_seconds = kLongDuration; // 5 seconds.
|
|
||||||
|
|
||||||
// Sleep until just after rental window is over.
|
|
||||||
wvutil::TestSleep::Sleep(kDuration + kShortSleep);
|
|
||||||
// Loading the license should start the playback clock.
|
|
||||||
LoadLicense();
|
|
||||||
// If the license is loaded after the rental duration window, we expect
|
|
||||||
// failure.
|
|
||||||
ASSERT_NO_FATAL_FAILURE(
|
|
||||||
session_.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoRefreshTest,
|
|
||||||
Range<uint32_t>(kCurrentAPI - 1, kCurrentAPI + 1));
|
|
||||||
|
|
||||||
// These tests only work when the license has a core message.
|
|
||||||
INSTANTIATE_TEST_SUITE_P(TestAPI16, OEMCryptoRefreshTestAPI16,
|
|
||||||
Range<uint32_t>(kCoreMessagesAPI, kCurrentAPI + 1));
|
|
||||||
|
|
||||||
/// @}
|
|
||||||
|
|
||||||
/// @addtogroup security
|
/// @addtogroup security
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
@@ -1770,201 +1597,6 @@ TEST_F(
|
|||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
/// @addtogroup provision
|
|
||||||
/// @{
|
|
||||||
|
|
||||||
// Test that a wrapped RSA key can be loaded.
|
|
||||||
TEST_F(OEMCryptoLoadsCertificate, LoadWrappedRSAKey) {
|
|
||||||
ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey());
|
|
||||||
Session s;
|
|
||||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
|
||||||
ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_));
|
|
||||||
}
|
|
||||||
|
|
||||||
class OEMCryptoLoadsCertVariousKeys : public OEMCryptoLoadsCertificate {
|
|
||||||
public:
|
|
||||||
void TestKey(const uint8_t* key, size_t key_length) {
|
|
||||||
encoded_rsa_key_.assign(key, key + key_length);
|
|
||||||
ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey());
|
|
||||||
Session s;
|
|
||||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
|
||||||
ASSERT_NO_FATAL_FAILURE(s.SetRsaPublicKeyFromPrivateKeyInfo(
|
|
||||||
encoded_rsa_key_.data(), encoded_rsa_key_.size()));
|
|
||||||
ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_));
|
|
||||||
|
|
||||||
LicenseRoundTrip license_messages(&s);
|
|
||||||
ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest());
|
|
||||||
ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse());
|
|
||||||
ASSERT_NO_FATAL_FAILURE(license_messages.EncryptAndSignResponse());
|
|
||||||
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages.LoadResponse());
|
|
||||||
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Test a 3072 bit RSA key certificate.
|
|
||||||
TEST_F(OEMCryptoLoadsCertVariousKeys, TestLargeRSAKey3072) {
|
|
||||||
TestKey(kTestRSAPKCS8PrivateKeyInfo3_3072,
|
|
||||||
sizeof(kTestRSAPKCS8PrivateKeyInfo3_3072));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test an RSA key certificate which has a private key generated using the
|
|
||||||
// Carmichael totient.
|
|
||||||
TEST_F(OEMCryptoLoadsCertVariousKeys, TestCarmichaelRSAKey) {
|
|
||||||
TestKey(kTestKeyRSACarmichael_2048, sizeof(kTestKeyRSACarmichael_2048));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(OEMCryptoLoadsCertVariousKeys, TestCarmichaelNonZeroNormalDer) {
|
|
||||||
TestKey(kCarmichaelNonZeroNormalDer, kCarmichaelNonZeroNormalDerLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(OEMCryptoLoadsCertVariousKeys, TestCarmichaelNonZeroShortDer) {
|
|
||||||
TestKey(kCarmichaelNonZeroShortDer, kCarmichaelNonZeroShortDerLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(OEMCryptoLoadsCertVariousKeys, TestCarmichaelZeroNormalDer) {
|
|
||||||
TestKey(kCarmichaelZeroNormalDer, kCarmichaelZeroNormalDerLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(OEMCryptoLoadsCertVariousKeys, TestCarmichaelZeroShortDer) {
|
|
||||||
TestKey(kCarmichaelZeroShortDer, kCarmichaelZeroShortDerLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(OEMCryptoLoadsCertVariousKeys, TestDualNonZeroNormalDer) {
|
|
||||||
TestKey(kDualNonZeroNormalDer, kDualNonZeroNormalDerLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(OEMCryptoLoadsCertVariousKeys, TestDualNonZeroShortDer) {
|
|
||||||
TestKey(kDualNonZeroShortDer, kDualNonZeroShortDerLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(OEMCryptoLoadsCertVariousKeys, TestDualZeroNormalDer) {
|
|
||||||
TestKey(kDualZeroNormalDer, kDualZeroNormalDerLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(OEMCryptoLoadsCertVariousKeys, TestDualZeroShortDer) {
|
|
||||||
TestKey(kDualZeroShortDer, kDualZeroShortDerLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(OEMCryptoLoadsCertVariousKeys, TestEulerNonZeroNormalDer) {
|
|
||||||
TestKey(kEulerNonZeroNormalDer, kEulerNonZeroNormalDerLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(OEMCryptoLoadsCertVariousKeys, TestEulerZeroNormalDer) {
|
|
||||||
TestKey(kEulerZeroNormalDer, kEulerZeroNormalDerLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This tests that two sessions can use different RSA keys simultaneously.
|
|
||||||
TEST_F(OEMCryptoLoadsCertificate, TestMultipleRSAKeys) {
|
|
||||||
ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey());
|
|
||||||
Session s1; // Session s1 loads the default rsa key, but doesn't use it
|
|
||||||
// until after s2 uses its key.
|
|
||||||
ASSERT_NO_FATAL_FAILURE(s1.open());
|
|
||||||
ASSERT_NO_FATAL_FAILURE(s1.SetRsaPublicKeyFromPrivateKeyInfo(
|
|
||||||
encoded_rsa_key_.data(), encoded_rsa_key_.size()));
|
|
||||||
ASSERT_NO_FATAL_FAILURE(s1.LoadWrappedRsaDrmKey(wrapped_drm_key_));
|
|
||||||
|
|
||||||
Session s2; // Session s2 uses a different rsa key.
|
|
||||||
encoded_rsa_key_.assign(kTestRSAPKCS8PrivateKeyInfo4_2048,
|
|
||||||
kTestRSAPKCS8PrivateKeyInfo4_2048 +
|
|
||||||
sizeof(kTestRSAPKCS8PrivateKeyInfo4_2048));
|
|
||||||
ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey());
|
|
||||||
ASSERT_NO_FATAL_FAILURE(s2.open());
|
|
||||||
ASSERT_NO_FATAL_FAILURE(s2.SetRsaPublicKeyFromPrivateKeyInfo(
|
|
||||||
encoded_rsa_key_.data(), encoded_rsa_key_.size()));
|
|
||||||
ASSERT_NO_FATAL_FAILURE(s2.LoadWrappedRsaDrmKey(wrapped_drm_key_));
|
|
||||||
LicenseRoundTrip license_messages2(&s2);
|
|
||||||
ASSERT_NO_FATAL_FAILURE(license_messages2.SignAndVerifyRequest());
|
|
||||||
ASSERT_NO_FATAL_FAILURE(license_messages2.CreateDefaultResponse());
|
|
||||||
ASSERT_NO_FATAL_FAILURE(license_messages2.EncryptAndSignResponse());
|
|
||||||
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages2.LoadResponse());
|
|
||||||
ASSERT_NO_FATAL_FAILURE(s2.TestDecryptCTR());
|
|
||||||
s2.close();
|
|
||||||
|
|
||||||
// After s2 has loaded its rsa key, we continue using s1's key.
|
|
||||||
LicenseRoundTrip license_messages1(&s1);
|
|
||||||
ASSERT_NO_FATAL_FAILURE(license_messages1.SignAndVerifyRequest());
|
|
||||||
ASSERT_NO_FATAL_FAILURE(license_messages1.CreateDefaultResponse());
|
|
||||||
ASSERT_NO_FATAL_FAILURE(license_messages1.EncryptAndSignResponse());
|
|
||||||
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages1.LoadResponse());
|
|
||||||
ASSERT_NO_FATAL_FAILURE(s1.TestDecryptCTR());
|
|
||||||
}
|
|
||||||
|
|
||||||
// This tests the maximum number of DRM private keys that OEMCrypto can load
|
|
||||||
TEST_F(OEMCryptoLoadsCertificate, TestMaxDRMKeys) {
|
|
||||||
const size_t max_total_keys = GetResourceValue(kMaxTotalDRMPrivateKeys);
|
|
||||||
std::vector<std::unique_ptr<Session>> sessions;
|
|
||||||
std::vector<std::unique_ptr<LicenseRoundTrip>> licenses;
|
|
||||||
|
|
||||||
// It should be able to load up to kMaxTotalDRMPrivateKeys keys
|
|
||||||
for (size_t i = 0; i < max_total_keys; i++) {
|
|
||||||
sessions.push_back(std::unique_ptr<Session>(new Session()));
|
|
||||||
licenses.push_back(std::unique_ptr<LicenseRoundTrip>(
|
|
||||||
new LicenseRoundTrip(sessions[i].get())));
|
|
||||||
const size_t key_index = i % kTestRSAPKCS8PrivateKeys_2048.size();
|
|
||||||
encoded_rsa_key_.assign(kTestRSAPKCS8PrivateKeys_2048[key_index].begin(),
|
|
||||||
kTestRSAPKCS8PrivateKeys_2048[key_index].end());
|
|
||||||
ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey());
|
|
||||||
ASSERT_NO_FATAL_FAILURE(sessions[i]->open());
|
|
||||||
ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(sessions[i].get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempts to load one more key than the kMaxTotalDRMPrivateKeys
|
|
||||||
if (global_features.provisioning_method == OEMCrypto_BootCertificateChain) {
|
|
||||||
Session s;
|
|
||||||
const size_t buffer_size = 5000; // Make sure it is large enough.
|
|
||||||
std::vector<uint8_t> public_key(buffer_size);
|
|
||||||
size_t public_key_size = buffer_size;
|
|
||||||
std::vector<uint8_t> public_key_signature(buffer_size);
|
|
||||||
size_t public_key_signature_size = buffer_size;
|
|
||||||
std::vector<uint8_t> wrapped_private_key(buffer_size);
|
|
||||||
size_t wrapped_private_key_size = buffer_size;
|
|
||||||
OEMCrypto_PrivateKeyType key_type;
|
|
||||||
OEMCryptoResult result = OEMCrypto_GenerateCertificateKeyPair(
|
|
||||||
s.session_id(), public_key.data(), &public_key_size,
|
|
||||||
public_key_signature.data(), &public_key_signature_size,
|
|
||||||
wrapped_private_key.data(), &wrapped_private_key_size, &key_type);
|
|
||||||
// Key creation is allowed to fail due to resource restriction
|
|
||||||
if (result != OEMCrypto_SUCCESS) {
|
|
||||||
ASSERT_TRUE(result == OEMCrypto_ERROR_INSUFFICIENT_RESOURCES ||
|
|
||||||
result == OEMCrypto_ERROR_TOO_MANY_KEYS);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Session s;
|
|
||||||
encoded_rsa_key_.assign(kTestRSAPKCS8PrivateKeyInfo2_2048,
|
|
||||||
kTestRSAPKCS8PrivateKeyInfo2_2048 +
|
|
||||||
sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048));
|
|
||||||
Session ps;
|
|
||||||
ProvisioningRoundTrip provisioning_messages(&ps, encoded_rsa_key_);
|
|
||||||
provisioning_messages.PrepareSession(keybox_);
|
|
||||||
ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest());
|
|
||||||
ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse());
|
|
||||||
ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse());
|
|
||||||
OEMCryptoResult result = provisioning_messages.LoadResponse();
|
|
||||||
// Key loading is allowed to fail due to resource restriction
|
|
||||||
if (result != OEMCrypto_SUCCESS) {
|
|
||||||
ASSERT_TRUE(result == OEMCrypto_ERROR_INSUFFICIENT_RESOURCES ||
|
|
||||||
result == OEMCrypto_ERROR_TOO_MANY_KEYS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Verifies that the DRM keys which are already loaded should still function
|
|
||||||
for (size_t i = 0; i < licenses.size(); i++) {
|
|
||||||
ASSERT_NO_FATAL_FAILURE(licenses[i]->SignAndVerifyRequest());
|
|
||||||
ASSERT_NO_FATAL_FAILURE(licenses[i]->CreateDefaultResponse());
|
|
||||||
ASSERT_NO_FATAL_FAILURE(licenses[i]->EncryptAndSignResponse());
|
|
||||||
ASSERT_EQ(OEMCrypto_SUCCESS, licenses[i]->LoadResponse());
|
|
||||||
ASSERT_NO_FATAL_FAILURE(sessions[i]->TestDecryptCTR());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Devices that load certificates, should at least support RSA 2048 keys.
|
|
||||||
TEST_F(OEMCryptoLoadsCertificate, SupportsCertificatesAPI13) {
|
|
||||||
ASSERT_NE(0u,
|
|
||||||
OEMCrypto_Supports_RSA_2048bit & OEMCrypto_SupportedCertificates())
|
|
||||||
<< "Supported certificates is only " << OEMCrypto_SupportedCertificates();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @}
|
|
||||||
|
|
||||||
/// @addtogroup security
|
/// @addtogroup security
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
|
|||||||
@@ -19,48 +19,6 @@
|
|||||||
|
|
||||||
namespace wvoec {
|
namespace wvoec {
|
||||||
|
|
||||||
class OEMCryptoRefreshTest : public OEMCryptoLicenseTest {
|
|
||||||
protected:
|
|
||||||
void SetUp() override {
|
|
||||||
OEMCryptoLicenseTest::SetUp();
|
|
||||||
// These values allow us to run a few simple duration tests or just start
|
|
||||||
// playback right away. All times are in seconds since the license was
|
|
||||||
// signed.
|
|
||||||
// Soft expiry false means timers are strictly enforce.
|
|
||||||
timer_limits_.soft_enforce_rental_duration = true;
|
|
||||||
timer_limits_.soft_enforce_playback_duration = false;
|
|
||||||
// Playback may begin immediately.
|
|
||||||
timer_limits_.earliest_playback_start_seconds = 0;
|
|
||||||
// First playback may be within the first two seconds.
|
|
||||||
timer_limits_.rental_duration_seconds = kDuration;
|
|
||||||
// Once started, playback may last two seconds without a renewal.
|
|
||||||
timer_limits_.initial_renewal_duration_seconds = kDuration;
|
|
||||||
// Total playback is not limited.
|
|
||||||
timer_limits_.total_playback_duration_seconds = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LoadLicense() {
|
|
||||||
license_messages_.core_response().timer_limits = timer_limits_;
|
|
||||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
|
||||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
|
||||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
|
||||||
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
|
||||||
}
|
|
||||||
|
|
||||||
void MakeRenewalRequest(RenewalRoundTrip* renewal_messages) {
|
|
||||||
ASSERT_NO_FATAL_FAILURE(renewal_messages->SignAndVerifyRequest());
|
|
||||||
ASSERT_NO_FATAL_FAILURE(renewal_messages->CreateDefaultResponse());
|
|
||||||
}
|
|
||||||
|
|
||||||
void LoadRenewal(RenewalRoundTrip* renewal_messages,
|
|
||||||
OEMCryptoResult expected_result) {
|
|
||||||
ASSERT_NO_FATAL_FAILURE(renewal_messages->EncryptAndSignResponse());
|
|
||||||
ASSERT_EQ(expected_result, renewal_messages->LoadResponse());
|
|
||||||
}
|
|
||||||
|
|
||||||
ODK_TimerLimits timer_limits_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// This class is for testing the generic crypto functionality.
|
// This class is for testing the generic crypto functionality.
|
||||||
class OEMCryptoGenericCryptoTest : public OEMCryptoRefreshTest {
|
class OEMCryptoGenericCryptoTest : public OEMCryptoRefreshTest {
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
Reference in New Issue
Block a user