Address failures when provisioning methods differ
[ Merge of http://go/wvgerrit/46907 ] The WV client supports root of trusts as keyboxes or OEM certificates. Devices with keyboxes use provisioning 2.0 protocol to provision while those with OEM certificates use 3.0. L3 provisioning failures occur if the L1 and L3 root of trusts differ. The provisioning method is now retrieved and cached when the security level is known, when the session is opened. Earlier it was retrieved and cached at initialization time and always set to the value of L1 OEMCrypto (if present). This led to provisioning failures. A case of acquiring a lock while one was held in GetProvisioningId() has also fixed. Bug: 77606913 Test: WV unit/integration tests Change-Id: I2d66ee2cf64f846cec4a37fbccb554447c8a0e1d
This commit is contained in:
@@ -199,7 +199,8 @@ class CryptoSession {
|
|||||||
private:
|
private:
|
||||||
friend class CryptoSessionForTest;
|
friend class CryptoSessionForTest;
|
||||||
|
|
||||||
bool GetProvisioningMethod(CdmClientTokenType* token_type);
|
CdmResponseType GetProvisioningMethod(SecurityLevel requested_security_level,
|
||||||
|
CdmClientTokenType* token_type);
|
||||||
void Init();
|
void Init();
|
||||||
void Terminate();
|
void Terminate();
|
||||||
bool GetTokenFromKeybox(std::string* token);
|
bool GetTokenFromKeybox(std::string* token);
|
||||||
|
|||||||
@@ -324,6 +324,7 @@ enum CdmResponseType {
|
|||||||
REMOVE_USAGE_INFO_ERROR_1 = 282,
|
REMOVE_USAGE_INFO_ERROR_1 = 282,
|
||||||
REMOVE_USAGE_INFO_ERROR_2 = 283,
|
REMOVE_USAGE_INFO_ERROR_2 = 283,
|
||||||
REMOVE_USAGE_INFO_ERROR_3 = 284,
|
REMOVE_USAGE_INFO_ERROR_3 = 284,
|
||||||
|
GET_PROVISIONING_METHOD_ERROR = 285,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum CdmKeyStatus {
|
enum CdmKeyStatus {
|
||||||
@@ -397,7 +398,8 @@ enum CdmSigningAlgorithm {
|
|||||||
enum CdmClientTokenType {
|
enum CdmClientTokenType {
|
||||||
kClientTokenKeybox,
|
kClientTokenKeybox,
|
||||||
kClientTokenDrmCert,
|
kClientTokenDrmCert,
|
||||||
kClientTokenOemCert
|
kClientTokenOemCert,
|
||||||
|
kClientTokenUninitialized,
|
||||||
};
|
};
|
||||||
|
|
||||||
// kNonSecureUsageSupport - TEE does not provide any support for usage
|
// kNonSecureUsageSupport - TEE does not provide any support for usage
|
||||||
|
|||||||
@@ -757,6 +757,7 @@ CdmResponseType CdmEngine::QueryOemCryptoSessionId(
|
|||||||
CdmResponseType CdmEngine::GetProvisioningRequest(
|
CdmResponseType CdmEngine::GetProvisioningRequest(
|
||||||
CdmCertificateType cert_type, const std::string& cert_authority,
|
CdmCertificateType cert_type, const std::string& cert_authority,
|
||||||
CdmProvisioningRequest* request, std::string* default_url) {
|
CdmProvisioningRequest* request, std::string* default_url) {
|
||||||
|
LOGI("CdmEngine::GetProvisioningRequest");
|
||||||
if (!request) {
|
if (!request) {
|
||||||
LOGE("CdmEngine::GetProvisioningRequest: invalid output parameters");
|
LOGE("CdmEngine::GetProvisioningRequest: invalid output parameters");
|
||||||
return INVALID_PROVISIONING_REQUEST_PARAM_1;
|
return INVALID_PROVISIONING_REQUEST_PARAM_1;
|
||||||
@@ -794,6 +795,7 @@ CdmResponseType CdmEngine::GetProvisioningRequest(
|
|||||||
CdmResponseType CdmEngine::HandleProvisioningResponse(
|
CdmResponseType CdmEngine::HandleProvisioningResponse(
|
||||||
const CdmProvisioningResponse& response, std::string* cert,
|
const CdmProvisioningResponse& response, std::string* cert,
|
||||||
std::string* wrapped_key) {
|
std::string* wrapped_key) {
|
||||||
|
LOGI("CdmEngine::HandleProvisioningResponse");
|
||||||
if (response.empty()) {
|
if (response.empty()) {
|
||||||
LOGE("CdmEngine::HandleProvisioningResponse: Empty provisioning response.");
|
LOGE("CdmEngine::HandleProvisioningResponse: Empty provisioning response.");
|
||||||
cert_provisioning_.reset(NULL);
|
cert_provisioning_.reset(NULL);
|
||||||
|
|||||||
@@ -138,6 +138,7 @@ CryptoSession::CryptoSession(metrics::CryptoMetrics* metrics)
|
|||||||
: metrics_(metrics),
|
: metrics_(metrics),
|
||||||
system_id_(-1),
|
system_id_(-1),
|
||||||
open_(false),
|
open_(false),
|
||||||
|
pre_provision_token_type_(kClientTokenUninitialized),
|
||||||
update_usage_table_after_close_session_(false),
|
update_usage_table_after_close_session_(false),
|
||||||
is_destination_buffer_type_valid_(false),
|
is_destination_buffer_type_valid_(false),
|
||||||
requested_security_level_(kLevelDefault),
|
requested_security_level_(kLevelDefault),
|
||||||
@@ -160,9 +161,11 @@ CryptoSession::~CryptoSession() {
|
|||||||
M_RECORD(metrics_, crypto_session_life_span_, life_span_.AsMs());
|
M_RECORD(metrics_, crypto_session_life_span_, life_span_.AsMs());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CryptoSession::GetProvisioningMethod(CdmClientTokenType* token_type) {
|
CdmResponseType CryptoSession::GetProvisioningMethod(
|
||||||
|
SecurityLevel requested_security_level,
|
||||||
|
CdmClientTokenType* token_type) {
|
||||||
OEMCrypto_ProvisioningMethod method =
|
OEMCrypto_ProvisioningMethod method =
|
||||||
OEMCrypto_GetProvisioningMethod(requested_security_level_);
|
OEMCrypto_GetProvisioningMethod(requested_security_level);
|
||||||
metrics_->oemcrypto_provisioning_method_.Record(method);
|
metrics_->oemcrypto_provisioning_method_.Record(method);
|
||||||
CdmClientTokenType type;
|
CdmClientTokenType type;
|
||||||
switch (method) {
|
switch (method) {
|
||||||
@@ -179,10 +182,10 @@ bool CryptoSession::GetProvisioningMethod(CdmClientTokenType* token_type) {
|
|||||||
default:
|
default:
|
||||||
LOGE("OEMCrypto_GetProvisioningMethod failed. %d", method);
|
LOGE("OEMCrypto_GetProvisioningMethod failed. %d", method);
|
||||||
metrics_->oemcrypto_provisioning_method_.SetError(method);
|
metrics_->oemcrypto_provisioning_method_.SetError(method);
|
||||||
return false;
|
return GET_PROVISIONING_METHOD_ERROR;
|
||||||
}
|
}
|
||||||
*token_type = type;
|
*token_type = type;
|
||||||
return true;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CryptoSession::Init() {
|
void CryptoSession::Init() {
|
||||||
@@ -198,9 +201,6 @@ void CryptoSession::Init() {
|
|||||||
}
|
}
|
||||||
initialized_ = true;
|
initialized_ = true;
|
||||||
}
|
}
|
||||||
if (!GetProvisioningMethod(&pre_provision_token_type_)) {
|
|
||||||
initialized_ = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CryptoSession::Terminate() {
|
void CryptoSession::Terminate() {
|
||||||
@@ -594,10 +594,12 @@ bool CryptoSession::GetProvisioningId(std::string* provisioning_id) {
|
|||||||
uint8_t buf[KEYBOX_KEY_DATA_SIZE];
|
uint8_t buf[KEYBOX_KEY_DATA_SIZE];
|
||||||
size_t buf_size = sizeof(buf);
|
size_t buf_size = sizeof(buf);
|
||||||
|
|
||||||
LOGV("CryptoSession::GetProvisioningId: Lock");
|
{
|
||||||
AutoLock auto_lock(crypto_lock_);
|
LOGV("CryptoSession::GetProvisioningId: Lock");
|
||||||
if (!initialized_) {
|
AutoLock auto_lock(crypto_lock_);
|
||||||
return false;
|
if (!initialized_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pre_provision_token_type_ == kClientTokenOemCert) {
|
if (pre_provision_token_type_ == kClientTokenOemCert) {
|
||||||
@@ -614,6 +616,8 @@ bool CryptoSession::GetProvisioningId(std::string* provisioning_id) {
|
|||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
OEMCryptoResult sts;
|
OEMCryptoResult sts;
|
||||||
|
LOGV("CryptoSession::GetProvisioningId: Lock");
|
||||||
|
AutoLock auto_lock(crypto_lock_);
|
||||||
M_TIME(
|
M_TIME(
|
||||||
sts = OEMCrypto_GetKeyData(buf, &buf_size, requested_security_level_),
|
sts = OEMCrypto_GetKeyData(buf, &buf_size, requested_security_level_),
|
||||||
metrics_, oemcrypto_get_key_data_, sts, metrics::Pow2Bucket(buf_size));
|
metrics_, oemcrypto_get_key_data_, sts, metrics::Pow2Bucket(buf_size));
|
||||||
@@ -633,14 +637,23 @@ uint8_t CryptoSession::GetSecurityPatchLevel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
|
CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
|
||||||
LOGD("CryptoSession::Open: Lock: requested_security_level: %s",
|
{
|
||||||
requested_security_level == kLevel3
|
LOGD("CryptoSession::Open: Lock: requested_security_level: %s",
|
||||||
? QUERY_VALUE_SECURITY_LEVEL_L3.c_str()
|
requested_security_level == kLevel3
|
||||||
: QUERY_VALUE_SECURITY_LEVEL_DEFAULT.c_str());
|
? QUERY_VALUE_SECURITY_LEVEL_L3.c_str()
|
||||||
AutoLock auto_lock(crypto_lock_);
|
: QUERY_VALUE_SECURITY_LEVEL_DEFAULT.c_str());
|
||||||
if (!initialized_) return UNKNOWN_ERROR;
|
AutoLock auto_lock(crypto_lock_);
|
||||||
if (open_) return NO_ERROR;
|
if (!initialized_) return UNKNOWN_ERROR;
|
||||||
|
if (open_) return NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
CdmResponseType result =
|
||||||
|
GetProvisioningMethod(requested_security_level,
|
||||||
|
&pre_provision_token_type_);
|
||||||
|
if (result != NO_ERROR) return result;
|
||||||
|
|
||||||
|
LOGV("CryptoSession::Open: Lock");
|
||||||
|
AutoLock auto_lock(crypto_lock_);
|
||||||
OEMCrypto_SESSION sid;
|
OEMCrypto_SESSION sid;
|
||||||
requested_security_level_ = requested_security_level;
|
requested_security_level_ = requested_security_level;
|
||||||
OEMCryptoResult sts = OEMCrypto_OpenSession(&sid, requested_security_level);
|
OEMCryptoResult sts = OEMCrypto_OpenSession(&sid, requested_security_level);
|
||||||
@@ -679,7 +692,7 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CdmUsageSupportType usage_support_type;
|
CdmUsageSupportType usage_support_type;
|
||||||
CdmResponseType result = GetUsageSupportType(&usage_support_type);
|
result = GetUsageSupportType(&usage_support_type);
|
||||||
if (result == NO_ERROR) {
|
if (result == NO_ERROR) {
|
||||||
metrics_->oemcrypto_usage_table_support_.Record(usage_support_type);
|
metrics_->oemcrypto_usage_table_support_.Record(usage_support_type);
|
||||||
if (usage_support_type == kUsageEntrySupport) {
|
if (usage_support_type == kUsageEntrySupport) {
|
||||||
|
|||||||
@@ -581,6 +581,8 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
|
|||||||
break;
|
break;
|
||||||
case REMOVE_USAGE_INFO_ERROR_3: *os << "REMOVE_USAGE_INFO_ERROR_3";
|
case REMOVE_USAGE_INFO_ERROR_3: *os << "REMOVE_USAGE_INFO_ERROR_3";
|
||||||
break;
|
break;
|
||||||
|
case GET_PROVISIONING_METHOD_ERROR: *os << "GET_PROVISIONING_METHOD_ERROR";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
*os << "Unknown CdmResponseType";
|
*os << "Unknown CdmResponseType";
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1620,8 +1620,39 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
|
|||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(WvCdmRequestLicenseTest, ProvisioningTest) {
|
TEST_F(WvCdmRequestLicenseTest, ProvisioningTest) {
|
||||||
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
Unprovision();
|
||||||
&session_id_);
|
EXPECT_EQ(NEED_PROVISIONING,
|
||||||
|
decryptor_.OpenSession(g_key_system, NULL,
|
||||||
|
kDefaultCdmIdentifier, NULL,
|
||||||
|
&session_id_));
|
||||||
|
std::string provisioning_server;
|
||||||
|
CdmCertificateType cert_type = kCertificateWidevine;
|
||||||
|
std::string cert_authority, cert, wrapped_key;
|
||||||
|
|
||||||
|
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.GetProvisioningRequest(
|
||||||
|
cert_type, cert_authority,
|
||||||
|
kDefaultCdmIdentifier, &key_msg_,
|
||||||
|
&provisioning_server));
|
||||||
|
EXPECT_EQ(provisioning_server, g_config->provisioning_server());
|
||||||
|
|
||||||
|
std::string response =
|
||||||
|
GetCertRequestResponse(g_config->provisioning_server());
|
||||||
|
EXPECT_NE(0, static_cast<int>(response.size()));
|
||||||
|
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.HandleProvisioningResponse(
|
||||||
|
kDefaultCdmIdentifier, response, &cert,
|
||||||
|
&wrapped_key));
|
||||||
|
EXPECT_EQ(0, static_cast<int>(cert.size()));
|
||||||
|
EXPECT_EQ(0, static_cast<int>(wrapped_key.size()));
|
||||||
|
decryptor_.CloseSession(session_id_);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WvCdmRequestLicenseTest, L3ProvisioningTest) {
|
||||||
|
TestWvCdmClientPropertySet property_set_L3;
|
||||||
|
property_set_L3.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3);
|
||||||
|
EXPECT_EQ(NEED_PROVISIONING,
|
||||||
|
decryptor_.OpenSession(g_key_system, &property_set_L3,
|
||||||
|
kDefaultCdmIdentifier, NULL,
|
||||||
|
&session_id_));
|
||||||
std::string provisioning_server;
|
std::string provisioning_server;
|
||||||
CdmCertificateType cert_type = kCertificateWidevine;
|
CdmCertificateType cert_type = kCertificateWidevine;
|
||||||
std::string cert_authority, cert, wrapped_key;
|
std::string cert_authority, cert, wrapped_key;
|
||||||
@@ -3764,7 +3795,8 @@ TEST_F(WvCdmRequestLicenseTest, QueryStatus) {
|
|||||||
EXPECT_EQ(wvcdm::NO_ERROR,
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
||||||
decryptor_.QueryStatus(kLevelDefault,
|
decryptor_.QueryStatus(kLevelDefault,
|
||||||
wvcdm::QUERY_KEY_PROVISIONING_ID, &value));
|
wvcdm::QUERY_KEY_PROVISIONING_ID, &value));
|
||||||
EXPECT_EQ(16u, value.size());
|
EXPECT_TRUE(16u == value.size() || 32u == value.size())
|
||||||
|
<< "provisioning id size: " << value.size();
|
||||||
|
|
||||||
EXPECT_EQ(wvcdm::NO_ERROR,
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
||||||
decryptor_.QueryStatus(
|
decryptor_.QueryStatus(
|
||||||
@@ -3866,7 +3898,8 @@ TEST_F(WvCdmRequestLicenseTest, QueryStatusL3) {
|
|||||||
EXPECT_EQ(wvcdm::NO_ERROR,
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
||||||
decryptor_.QueryStatus(kLevel3, wvcdm::QUERY_KEY_PROVISIONING_ID,
|
decryptor_.QueryStatus(kLevel3, wvcdm::QUERY_KEY_PROVISIONING_ID,
|
||||||
&value));
|
&value));
|
||||||
EXPECT_EQ(16u, value.size());
|
EXPECT_TRUE(16u == value.size() || 32u == value.size())
|
||||||
|
<< "provisioning id size: " << value.size();
|
||||||
|
|
||||||
EXPECT_EQ(wvcdm::NO_ERROR,
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
||||||
decryptor_.QueryStatus(kLevel3, wvcdm::QUERY_KEY_CURRENT_HDCP_LEVEL,
|
decryptor_.QueryStatus(kLevel3, wvcdm::QUERY_KEY_CURRENT_HDCP_LEVEL,
|
||||||
|
|||||||
@@ -263,10 +263,11 @@ enum {
|
|||||||
kRemoveUsageInfoError1 = ERROR_DRM_VENDOR_MIN + 274,
|
kRemoveUsageInfoError1 = ERROR_DRM_VENDOR_MIN + 274,
|
||||||
kRemoveUsageInfoError2 = ERROR_DRM_VENDOR_MIN + 275,
|
kRemoveUsageInfoError2 = ERROR_DRM_VENDOR_MIN + 275,
|
||||||
kRemoveUsageInfoError3 = ERROR_DRM_VENDOR_MIN + 276,
|
kRemoveUsageInfoError3 = ERROR_DRM_VENDOR_MIN + 276,
|
||||||
|
kGetProvisioningError = ERROR_DRM_VENDOR_MIN + 277,
|
||||||
|
|
||||||
// This should always follow the last error code.
|
// This should always follow the last error code.
|
||||||
// The offset value should be updated each time a new error code is added.
|
// The offset value should be updated each time a new error code is added.
|
||||||
kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 276,
|
kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 277,
|
||||||
|
|
||||||
// Used by crypto test mode
|
// Used by crypto test mode
|
||||||
kErrorTestMode = ERROR_DRM_VENDOR_MAX,
|
kErrorTestMode = ERROR_DRM_VENDOR_MAX,
|
||||||
|
|||||||
@@ -507,6 +507,8 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) {
|
|||||||
return kRemoveUsageInfoError2;
|
return kRemoveUsageInfoError2;
|
||||||
case wvcdm::REMOVE_USAGE_INFO_ERROR_3:
|
case wvcdm::REMOVE_USAGE_INFO_ERROR_3:
|
||||||
return kRemoveUsageInfoError3;
|
return kRemoveUsageInfoError3;
|
||||||
|
case wvcdm::GET_PROVISIONING_METHOD_ERROR:
|
||||||
|
return kGetProvisioningError;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return here instead of as a default case so that the compiler will warn
|
// Return here instead of as a default case so that the compiler will warn
|
||||||
|
|||||||
@@ -290,6 +290,7 @@ static Status mapCdmResponseType(wvcdm::CdmResponseType res) {
|
|||||||
case wvcdm::REMOVE_USAGE_INFO_ERROR_1:
|
case wvcdm::REMOVE_USAGE_INFO_ERROR_1:
|
||||||
case wvcdm::REMOVE_USAGE_INFO_ERROR_2:
|
case wvcdm::REMOVE_USAGE_INFO_ERROR_2:
|
||||||
case wvcdm::REMOVE_USAGE_INFO_ERROR_3:
|
case wvcdm::REMOVE_USAGE_INFO_ERROR_3:
|
||||||
|
case wvcdm::GET_PROVISIONING_METHOD_ERROR:
|
||||||
ALOGW("Returns UNKNOWN error for legacy status: %d", res);
|
ALOGW("Returns UNKNOWN error for legacy status: %d", res);
|
||||||
return Status::ERROR_DRM_UNKNOWN;
|
return Status::ERROR_DRM_UNKNOWN;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user