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

@@ -18,16 +18,22 @@ constexpr size_t kKeyboxSystemIdOffset = 4;
// Index of certificate within cerificate chain which contains the
// system ID (0 = leaf/device cert, 1 = intermediate/device family cert).
constexpr size_t kOemCertSystemIdIndex = 1;
// OID of X.509 certificate extension containing the Widevine system ID.
// OID of X.509 TBSCertificate extension containing the Widevine
// system ID.
const char kWidevineSystemIdExtensionOid[] = "1.3.6.1.4.1.11129.4.1.1";
constexpr size_t kSystemIdLength = sizeof(uint32_t);
constexpr bool IsSupportedSecurityLevel(CdmSecurityLevel security_level) {
constexpr bool IsSupportedCdmSecurityLevel(CdmSecurityLevel security_level) {
return security_level == kSecurityLevelL1 ||
security_level == kSecurityLevelL2 ||
security_level == kSecurityLevelL3;
}
constexpr bool IsSupportedRequestedSecurityLevel(
RequestedSecurityLevel security_level) {
return security_level == kLevelDefault || security_level == kLevel3;
}
} // namespace
SystemIdExtractor::SystemIdExtractor(RequestedSecurityLevel security_level,
@@ -45,15 +51,21 @@ bool SystemIdExtractor::ExtractSystemId(uint32_t* system_id) {
LOGE("Output |system_id| is null");
return false;
}
if (crypto_session_->GetCachedSystemId(system_id)) {
if (!VerifySecurityLevelExpectations()) {
// VerifySecurityLevelExpectations() will log details.
return false;
}
if (crypto_session_->IsOpen() &&
crypto_session_->GetCachedSystemId(system_id)) {
return true;
}
CdmClientTokenType type = kClientTokenUninitialized;
const CdmResponseType status =
crypto_session_->GetProvisioningMethod(security_level_, &type);
if (status != NO_ERROR) {
LOGE("Failed to get provisioning method: security_level = %s, status = %d",
RequestedSecurityLevelToString(security_level_), status.ToInt());
LOGE("Failed to get provisioning method: security_level = %s, status = %s",
RequestedSecurityLevelToString(security_level_),
status.ToString().c_str());
return false;
}
bool success = false;
@@ -90,7 +102,10 @@ bool SystemIdExtractor::ExtractSystemId(uint32_t* system_id) {
// static
bool SystemIdExtractor::ExtractSystemIdFromKeyboxData(
const std::string& key_data, uint32_t* system_id) {
if (system_id == nullptr) return false;
if (system_id == nullptr) {
LOGE("Output |system_id| is null");
return false;
}
if (key_data.size() < (kKeyboxSystemIdOffset + kSystemIdLength)) {
LOGE("Keybox data does not contain system ID: key_data_size = %zu",
key_data.size());
@@ -106,7 +121,10 @@ bool SystemIdExtractor::ExtractSystemIdFromKeyboxData(
// static
bool SystemIdExtractor::ExtractSystemIdFromOemCert(const std::string& oem_cert,
uint32_t* system_id) {
if (system_id == nullptr) return false;
if (system_id == nullptr) {
LOGE("Output |system_id| is null");
return false;
}
return ExtractExtensionValueFromCertificate(oem_cert,
kWidevineSystemIdExtensionOid,
kOemCertSystemIdIndex, system_id);
@@ -122,8 +140,9 @@ bool SystemIdExtractor::ExtractSystemIdProv20(uint32_t* system_id) {
return true;
}
if (status != NO_ERROR) {
LOGE("Failed to get keybox data: security_level = %s, status = %d",
RequestedSecurityLevelToString(security_level_), status.ToInt());
LOGE("Failed to get keybox data: security_level = %s, status = %s",
RequestedSecurityLevelToString(security_level_),
status.ToString().c_str());
return false;
}
if (!ExtractSystemIdFromKeyboxData(key_data, system_id)) {
@@ -138,8 +157,9 @@ bool SystemIdExtractor::ExtractSystemIdProv30(uint32_t* system_id) {
const CdmResponseType status =
crypto_session_->GetTokenFromOemCert(security_level_, &oem_cert);
if (status != NO_ERROR) {
LOGE("Failed to get OEM certificate: security_level = %s, status = %d",
RequestedSecurityLevelToString(security_level_), status.ToInt());
LOGE("Failed to get OEM certificate: security_level = %s, status = %s",
RequestedSecurityLevelToString(security_level_),
status.ToString().c_str());
return false;
}
if (!ExtractSystemIdFromOemCert(oem_cert, system_id)) {
@@ -152,7 +172,7 @@ bool SystemIdExtractor::ExtractSystemIdProv30(uint32_t* system_id) {
bool SystemIdExtractor::ExtractSystemIdProv40(uint32_t* system_id) {
const CdmSecurityLevel security_level =
crypto_session_->GetSecurityLevel(security_level_);
if (!IsSupportedSecurityLevel(security_level)) {
if (!IsSupportedCdmSecurityLevel(security_level)) {
LOGE("Unsupported security level: %s",
CdmSecurityLevelToString(security_level));
return false;
@@ -160,7 +180,7 @@ bool SystemIdExtractor::ExtractSystemIdProv40(uint32_t* system_id) {
DeviceFiles real_device_files(fs_);
// Mock DeviceFiles for testing.
DeviceFiles& device_files =
(test_device_files_ ? *test_device_files_ : real_device_files);
(test_device_files_ != nullptr ? *test_device_files_ : real_device_files);
if (!device_files.Init(security_level)) {
LOGE("Failed to initialize device files: security_level = %s",
CdmSecurityLevelToString(security_level));
@@ -190,4 +210,48 @@ bool SystemIdExtractor::ExtractSystemIdProv40(uint32_t* system_id) {
}
return true;
}
bool SystemIdExtractor::VerifySecurityLevelExpectations() {
if (!IsSupportedRequestedSecurityLevel(security_level_)) {
LOGE("Unsupported requested extractor security level: %d",
static_cast<int>(security_level_));
return false;
}
if (!crypto_session_->IsOpen()) {
// Any other issues with the security level should be caught and
// handled by the respective extractor methods.
return true;
}
// The SystemIdExtractor is intended to work with unopened
// CryptoSessions, but does not restrict this.
// If the crypto session is open, it is already tied to a
// security level; for the extractor work as expected the
// session's security level must be the same as extractor's
// requested security level.
const CdmSecurityLevel session_security_level =
crypto_session_->GetSecurityLevel();
if (!IsSupportedCdmSecurityLevel(session_security_level)) {
LOGE("Failed to get session security level: %s",
CdmSecurityLevelToString(session_security_level));
return false;
}
const CdmSecurityLevel extractor_security_level =
crypto_session_->GetSecurityLevel(security_level_);
if (!IsSupportedCdmSecurityLevel(extractor_security_level)) {
LOGE("Failed to get extractor security level: %s",
CdmSecurityLevelToString(extractor_security_level));
return false;
}
if (session_security_level != extractor_security_level) {
LOGE(
"Extractor and session security levels do not match: "
"session_security_level = %s, extractor_security_level = %s, "
"requested_security_level = %s",
CdmSecurityLevelToString(session_security_level),
CdmSecurityLevelToString(extractor_security_level),
RequestedSecurityLevelToString(security_level_));
return false;
}
return true;
}
} // namespace wvcdm