Improved SystemIdExtractor's opened/closed session behavior.

[ Merge of http://go/wvgerrit/201577 ]
[ Cherry-pick of http://ag/28133919 ]

VIC specific: No DRM reprovisioning support

The SystemIdExtractor did not properly define behavior when working
with opened/closed CryptoSessions.  Due to the CryptoSession's class
dual role of being both a session and a general handle into the
crypto engine, small bugs relying on undefined behavior which happened
to return expected output allowed tests to pass.

This CL makes the following changes:
1) Have SystemIdExtractor verify caller expectations when session is
   open.
2) Improved SystemIdExtractor to operate when CryptoSession is opened
   or closed.
3) Updates several SystemIdExtractorTest cases to better test defined
   behavior without relying on undefined behavior.
4) Better code comments; hopefully some which will help prevent future
   misuse of the internal APIs.

Test: system_id_extractor_unittest on Oriole
Test: WVTS on oriole
Bug: 329713288
Change-Id: I65518fe62f43e8060ea752852eb08a3d7132e2a0
This commit is contained in:
Alex Dale
2024-06-12 16:36:27 -07:00
parent 11025293aa
commit b282ec92b6
3 changed files with 207 additions and 23 deletions

View File

@@ -270,11 +270,13 @@ class MockCryptoSession : public CryptoSession {
MockCryptoSession(metrics::CryptoMetrics* metrics) : CryptoSession(metrics) {}
// ~MockCryptoSession() override {}
bool IsOpen() override { return true; }
CdmSecurityLevel GetSecurityLevel() override { return kSecurityLevelL1; }
bool IsOpen() override { return is_open_; }
CdmSecurityLevel GetSecurityLevel() override {
return is_open_ ? open_security_level_ : kSecurityLevelUninitialized;
}
CdmSecurityLevel GetSecurityLevel(
RequestedSecurityLevel security_level) override {
return security_level == kLevelDefault ? kSecurityLevelL1
return security_level == kLevelDefault ? default_security_level_
: kSecurityLevelL3;
}
@@ -291,6 +293,16 @@ class MockCryptoSession : public CryptoSession {
(RequestedSecurityLevel, std::string*), (override));
MOCK_METHOD(CdmResponseType, GetTokenFromOemCert,
(RequestedSecurityLevel, std::string*), (override));
// These default values should represent good values of a
// CryptoSession used for system ID extractions.
// Test cases should modify them if needing to test edge cases.
bool is_open_ = false;
// Security level which is returned if the session is opened.
CdmSecurityLevel open_security_level_ = kSecurityLevelL1;
// Security level of the underlying default OEMCrypto engine.
CdmSecurityLevel default_security_level_ = kSecurityLevelL1;
};
class MockDeviceFiles : public DeviceFiles {
@@ -328,13 +340,27 @@ class SystemIdExtractorTest : public WvCdmTestBase {
return extractor;
}
void ExpectProvisioningType(CdmClientTokenType type) {
EXPECT_CALL(*crypto_session_, GetCachedSystemId).WillOnce(Return(false));
void ExpectProvisioningType(CdmClientTokenType type, bool is_open = false) {
crypto_session_->is_open_ = is_open;
if (is_open) {
// Extractor should only call GetCachedSystemId if session
// is opened.
EXPECT_CALL(*crypto_session_, GetCachedSystemId).WillOnce(Return(false));
} else {
EXPECT_CALL(*crypto_session_, GetCachedSystemId).Times(0);
}
EXPECT_CALL(*crypto_session_, GetProvisioningMethod(_, NotNull()))
.WillOnce(
DoAll(SetArgPointee<1>(type), Return(CdmResponseType(NO_ERROR))));
}
void ExpectFromCached(uint32_t system_id) {
crypto_session_->is_open_ = true;
EXPECT_CALL(*crypto_session_, GetCachedSystemId(NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(system_id), Return(true)));
}
void ExpectSet(uint32_t system_id) {
EXPECT_CALL(*crypto_session_, SetSystemId(system_id));
}
@@ -361,8 +387,7 @@ TEST_F(SystemIdExtractorTest, ExtractSystemIdFromKeyboxData) {
TEST_F(SystemIdExtractorTest, CachedSystemId) {
const uint32_t kCachedSystemId = 1234;
EXPECT_CALL(*crypto_session_, GetCachedSystemId(NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kCachedSystemId), Return(true)));
ExpectFromCached(kCachedSystemId);
auto extractor = CreateExtractor(kLevelDefault);
ASSERT_TRUE(extractor);
uint32_t system_id;
@@ -372,6 +397,7 @@ TEST_F(SystemIdExtractorTest, CachedSystemId) {
TEST_F(SystemIdExtractorTest, SetSystemIdMetrics) {
const uint32_t kSystemId = 4321;
crypto_session_->is_open_ = true; // Must be open to set system ID.
crypto_session_->SetSystemIdBase(kSystemId);
drm_metrics::WvCdmMetrics::CryptoMetrics metrics_proto;
crypto_metrics_.Serialize(&metrics_proto);
@@ -380,8 +406,54 @@ TEST_F(SystemIdExtractorTest, SetSystemIdMetrics) {
EXPECT_EQ(recorded_system_id, kSystemId);
}
TEST_F(SystemIdExtractorTest,
BadSecurityLevelExpectations_InvalidRequestedSecurityLevel) {
// Extractor caller is using an invalid requested security level.
const RequestedSecurityLevel kBadRequestedSecurityLevel =
static_cast<RequestedSecurityLevel>(9999);
auto extractor = CreateExtractor(kBadRequestedSecurityLevel);
uint32_t system_id;
EXPECT_FALSE(extractor->ExtractSystemId(&system_id));
}
TEST_F(SystemIdExtractorTest,
BadSecurityLevelExpectations_UnexpectedSessionSecurityLevel) {
// CryptoSession is returning an unexpected result for its security
// level.
crypto_session_->is_open_ = true;
crypto_session_->open_security_level_ = kSecurityLevelUnknown;
auto extractor = CreateExtractor(kLevelDefault);
uint32_t system_id;
EXPECT_FALSE(extractor->ExtractSystemId(&system_id));
}
TEST_F(SystemIdExtractorTest,
BadSecurityLevelExpectations_UnexpectedExtractorSecurityLevel) {
// OEMCrypto (via session-less CryptoSession) is returning an
// unexpected result for the default security level.
crypto_session_->is_open_ = true;
crypto_session_->default_security_level_ = kSecurityLevelUnknown;
auto extractor = CreateExtractor(kLevelDefault);
uint32_t system_id;
EXPECT_FALSE(extractor->ExtractSystemId(&system_id));
}
TEST_F(SystemIdExtractorTest,
BadSecurityLevelExpectations_MismatchedSessionSecurityLevel) {
// CryptoSession and Extractor are different security levels.
crypto_session_->is_open_ = true;
// Case 1: Session L3, extractor L1
crypto_session_->open_security_level_ = kSecurityLevelL3;
auto extractor = CreateExtractor(kLevelDefault);
uint32_t system_id;
EXPECT_FALSE(extractor->ExtractSystemId(&system_id));
// Case 2: Session L1, extractor L3
crypto_session_->open_security_level_ = kSecurityLevelL1;
extractor = CreateExtractor(kLevel3);
EXPECT_FALSE(extractor->ExtractSystemId(&system_id));
}
TEST_F(SystemIdExtractorTest, GetProvisioningMethod_Failed) {
EXPECT_CALL(*crypto_session_, GetCachedSystemId).WillOnce(Return(false));
EXPECT_CALL(*crypto_session_, GetProvisioningMethod(_, NotNull()))
.WillOnce(Return(CdmResponseType(UNKNOWN_ERROR)));
auto extractor = CreateExtractor(kLevelDefault);
@@ -420,6 +492,19 @@ TEST_F(SystemIdExtractorTest, KeyboxDevice_Success) {
EXPECT_EQ(system_id, kKeyboxSystemId);
}
TEST_F(SystemIdExtractorTest, KeyboxDevice_Success_WithCallToGetCached) {
ExpectProvisioningType(kClientTokenKeybox, /* is_open = */ true);
EXPECT_CALL(*crypto_session_, GetTokenFromKeybox(kLevelDefault, NotNull()))
.WillOnce(DoAll(SetArgPointee<1>(kKeyboxDataStr),
Return(CdmResponseType(NO_ERROR))));
ExpectSet(kKeyboxSystemId);
auto extractor = CreateExtractor(kLevelDefault);
ASSERT_TRUE(extractor);
uint32_t system_id;
EXPECT_TRUE(extractor->ExtractSystemId(&system_id));
EXPECT_EQ(system_id, kKeyboxSystemId);
}
TEST_F(SystemIdExtractorTest, KeyboxDevice_NeedsOtaKeyboxProvisioning) {
ExpectProvisioningType(kClientTokenKeybox);
EXPECT_CALL(*crypto_session_, GetTokenFromKeybox(kLevelDefault, NotNull()))