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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user