Adjust provisioning retry
Merge from Widevine repo of http://go/wvgerrit/94243 When generating a second provisioning request, a new session should be opened because a session can only have one nonce for v16. For Provisioning 3.0 devices, the OEM Cert's private key must be loaded in the new session. Test: WvCdmRequestLicenseTest.ProvisioningInterposedRetryTest Bug: 135288420 Nonce reuse Bug: 141655126 Cert reload Change-Id: I8a96566142c4d4380e2bdd571e8d363a7a1f74d4
This commit is contained in:
@@ -199,6 +199,7 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequest(
|
|||||||
|
|
||||||
default_url->assign(kProvisioningServerUrl);
|
default_url->assign(kProvisioningServerUrl);
|
||||||
|
|
||||||
|
if (crypto_session_->IsOpen()) crypto_session_->Close();
|
||||||
CdmResponseType status = crypto_session_->Open(requested_security_level);
|
CdmResponseType status = crypto_session_->Open(requested_security_level);
|
||||||
if (NO_ERROR != status) {
|
if (NO_ERROR != status) {
|
||||||
LOGE("Failed to create a crypto session: status = %d",
|
LOGE("Failed to create a crypto session: status = %d",
|
||||||
|
|||||||
@@ -359,14 +359,6 @@ CdmResponseType CryptoSession::GetTokenFromOemCert(std::string* token) {
|
|||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(b/141655126): This function can be optimized to not load private
|
|
||||||
// key when it isn't needed.
|
|
||||||
status = OEMCrypto_LoadOEMPrivateKey(oec_session_id_);
|
|
||||||
if (status != OEMCrypto_SUCCESS) {
|
|
||||||
return MapOEMCryptoResult(status, GET_TOKEN_FROM_OEM_CERT_ERROR,
|
|
||||||
"GetTokenFromOemCert");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string temp_buffer(CERTIFICATE_DATA_SIZE, '\0');
|
std::string temp_buffer(CERTIFICATE_DATA_SIZE, '\0');
|
||||||
bool retrying = false;
|
bool retrying = false;
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -1089,6 +1081,15 @@ CdmResponseType CryptoSession::PrepareAndSignProvisioningRequest(
|
|||||||
if (pre_provision_token_type_ == kClientTokenKeybox) {
|
if (pre_provision_token_type_ == kClientTokenKeybox) {
|
||||||
const CdmResponseType status = GenerateDerivedKeys(message);
|
const CdmResponseType status = GenerateDerivedKeys(message);
|
||||||
if (status != NO_ERROR) return status;
|
if (status != NO_ERROR) return status;
|
||||||
|
} else if (pre_provision_token_type_ == kClientTokenOemCert) {
|
||||||
|
const OEMCryptoResult status = OEMCrypto_LoadOEMPrivateKey(oec_session_id_);
|
||||||
|
if (status != OEMCrypto_SUCCESS) {
|
||||||
|
return MapOEMCryptoResult(status, GET_TOKEN_FROM_OEM_CERT_ERROR,
|
||||||
|
"GetTokenFromOemCert");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOGE("Unknown method %d", pre_provision_token_type_);
|
||||||
|
return UNKNOWN_CLIENT_TOKEN_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
OEMCryptoResult sts;
|
OEMCryptoResult sts;
|
||||||
|
|||||||
@@ -2303,6 +2303,7 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningInterposedRetryTest) {
|
|||||||
kEmptyServiceCertificate, &key_msg2, &provisioning_server));
|
kEmptyServiceCertificate, &key_msg2, &provisioning_server));
|
||||||
EXPECT_EQ(provisioning_server, kDefaultProvisioningServerUrl);
|
EXPECT_EQ(provisioning_server, kDefaultProvisioningServerUrl);
|
||||||
|
|
||||||
|
// Second message should succeed.
|
||||||
key_msg_ = key_msg2;
|
key_msg_ = key_msg2;
|
||||||
std::string response = GetCertRequestResponse(config_.provisioning_server());
|
std::string response = GetCertRequestResponse(config_.provisioning_server());
|
||||||
EXPECT_NE(0, static_cast<int>(response.size()));
|
EXPECT_NE(0, static_cast<int>(response.size()));
|
||||||
@@ -2312,6 +2313,7 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningInterposedRetryTest) {
|
|||||||
EXPECT_EQ(0, static_cast<int>(cert.size()));
|
EXPECT_EQ(0, static_cast<int>(cert.size()));
|
||||||
EXPECT_EQ(0, static_cast<int>(wrapped_key.size()));
|
EXPECT_EQ(0, static_cast<int>(wrapped_key.size()));
|
||||||
|
|
||||||
|
// First message is ignored because second already succeeded.
|
||||||
key_msg_ = key_msg1;
|
key_msg_ = key_msg1;
|
||||||
response = GetCertRequestResponse(config_.provisioning_server());
|
response = GetCertRequestResponse(config_.provisioning_server());
|
||||||
EXPECT_NE(0, static_cast<int>(response.size()));
|
EXPECT_NE(0, static_cast<int>(response.size()));
|
||||||
@@ -2330,60 +2332,32 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningInterspersedRetryTest) {
|
|||||||
CdmCertificateType cert_type = kCertificateWidevine;
|
CdmCertificateType cert_type = kCertificateWidevine;
|
||||||
std::string cert_authority, cert, wrapped_key;
|
std::string cert_authority, cert, wrapped_key;
|
||||||
|
|
||||||
std::string provisioning_model;
|
CdmKeyMessage key_msg1, key_msg2;
|
||||||
|
|
||||||
EXPECT_EQ(wvcdm::NO_ERROR,
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
||||||
decryptor_->QueryStatus(kLevelDefault,
|
|
||||||
wvcdm::QUERY_KEY_PROVISIONING_MODEL,
|
|
||||||
&provisioning_model));
|
|
||||||
|
|
||||||
std::string value;
|
|
||||||
EXPECT_EQ(wvcdm::NO_ERROR,
|
|
||||||
decryptor_->QueryStatus(
|
|
||||||
kLevelDefault, wvcdm::QUERY_KEY_OEMCRYPTO_API_VERSION, &value));
|
|
||||||
std::istringstream ss(value);
|
|
||||||
uint32_t api_version;
|
|
||||||
ss >> api_version;
|
|
||||||
ASSERT_FALSE(ss.fail());
|
|
||||||
EXPECT_TRUE(ss.eof());
|
|
||||||
|
|
||||||
if (provisioning_model == wvcdm::QUERY_VALUE_KEYBOX ||
|
|
||||||
(provisioning_model == wvcdm::QUERY_VALUE_OEM_CERTIFICATE &&
|
|
||||||
api_version >= 15)) {
|
|
||||||
// From OEMCrypto v15.2 onwards, the nonce table size is fixed. We can't
|
|
||||||
// test this for API versions before that if they use OEM certificates.
|
|
||||||
std::vector<std::string> key_msgs;
|
|
||||||
|
|
||||||
// TODO(b/135288420): There can be only one request per OEMCrypto session.
|
|
||||||
// This code must change.
|
|
||||||
wvcdm::CdmResponseType first_request_error;
|
|
||||||
// For keyboxes we use derived keys as part of the provisioning request.
|
|
||||||
// These get updated each request, therefore any request before the latest
|
|
||||||
// fails, so we only need 2 requests.
|
|
||||||
key_msgs.resize(2);
|
|
||||||
first_request_error = wvcdm::REWRAP_DEVICE_RSA_KEY_ERROR;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < key_msgs.size(); i++) {
|
|
||||||
EXPECT_EQ(
|
|
||||||
wvcdm::NO_ERROR,
|
|
||||||
decryptor_->GetProvisioningRequest(
|
decryptor_->GetProvisioningRequest(
|
||||||
cert_type, cert_authority, kDefaultCdmIdentifier,
|
cert_type, cert_authority, kDefaultCdmIdentifier,
|
||||||
kEmptyServiceCertificate, &key_msgs[i], &provisioning_server));
|
kEmptyServiceCertificate, &key_msg1, &provisioning_server));
|
||||||
EXPECT_EQ(provisioning_server, kDefaultProvisioningServerUrl);
|
EXPECT_EQ(provisioning_server, kDefaultProvisioningServerUrl);
|
||||||
}
|
|
||||||
|
|
||||||
// First request that we expect to fail.
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
||||||
key_msg_ = key_msgs[0];
|
decryptor_->GetProvisioningRequest(
|
||||||
std::string response =
|
cert_type, cert_authority, kDefaultCdmIdentifier,
|
||||||
GetCertRequestResponse(config_.provisioning_server());
|
kEmptyServiceCertificate, &key_msg2, &provisioning_server));
|
||||||
|
EXPECT_EQ(provisioning_server, kDefaultProvisioningServerUrl);
|
||||||
|
|
||||||
|
// First request expected to fail, because only one message may be active.
|
||||||
|
key_msg_ = key_msg1;
|
||||||
|
std::string response = GetCertRequestResponse(config_.provisioning_server());
|
||||||
EXPECT_NE(0, static_cast<int>(response.size()));
|
EXPECT_NE(0, static_cast<int>(response.size()));
|
||||||
EXPECT_EQ(first_request_error,
|
EXPECT_EQ(LOAD_PROVISIONING_ERROR,
|
||||||
decryptor_->HandleProvisioningResponse(
|
decryptor_->HandleProvisioningResponse(
|
||||||
kDefaultCdmIdentifier, response, &cert, &wrapped_key));
|
kDefaultCdmIdentifier, response, &cert, &wrapped_key));
|
||||||
EXPECT_EQ(0, static_cast<int>(cert.size()));
|
EXPECT_EQ(0, static_cast<int>(cert.size()));
|
||||||
EXPECT_EQ(0, static_cast<int>(wrapped_key.size()));
|
EXPECT_EQ(0, static_cast<int>(wrapped_key.size()));
|
||||||
|
|
||||||
// Second request that we expect to succeed.
|
// Second message should succeed.
|
||||||
key_msg_ = key_msgs[1];
|
key_msg_ = key_msg2;
|
||||||
response = GetCertRequestResponse(config_.provisioning_server());
|
response = GetCertRequestResponse(config_.provisioning_server());
|
||||||
EXPECT_NE(0, static_cast<int>(response.size()));
|
EXPECT_NE(0, static_cast<int>(response.size()));
|
||||||
EXPECT_EQ(wvcdm::NO_ERROR,
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
||||||
@@ -2391,7 +2365,6 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningInterspersedRetryTest) {
|
|||||||
kDefaultCdmIdentifier, response, &cert, &wrapped_key));
|
kDefaultCdmIdentifier, response, &cert, &wrapped_key));
|
||||||
EXPECT_EQ(0, static_cast<int>(cert.size()));
|
EXPECT_EQ(0, static_cast<int>(cert.size()));
|
||||||
EXPECT_EQ(0, static_cast<int>(wrapped_key.size()));
|
EXPECT_EQ(0, static_cast<int>(wrapped_key.size()));
|
||||||
}
|
|
||||||
|
|
||||||
decryptor_->CloseSession(session_id_);
|
decryptor_->CloseSession(session_id_);
|
||||||
}
|
}
|
||||||
@@ -3981,7 +3954,7 @@ TEST_F(WvCdmRequestLicenseTest, RemoveCorruptedUsageInfoTest) {
|
|||||||
CdmSecurityLevel security_level = GetDefaultSecurityLevel();
|
CdmSecurityLevel security_level = GetDefaultSecurityLevel();
|
||||||
FileSystem file_system;
|
FileSystem file_system;
|
||||||
DeviceFiles handle(&file_system);
|
DeviceFiles handle(&file_system);
|
||||||
EXPECT_TRUE(handle.Init(security_level));
|
ASSERT_TRUE(handle.Init(security_level));
|
||||||
std::vector<std::string> psts;
|
std::vector<std::string> psts;
|
||||||
EXPECT_TRUE(handle.DeleteAllUsageInfoForApp(
|
EXPECT_TRUE(handle.DeleteAllUsageInfoForApp(
|
||||||
DeviceFiles::GetUsageInfoFileName(""), &psts));
|
DeviceFiles::GetUsageInfoFileName(""), &psts));
|
||||||
|
|||||||
Reference in New Issue
Block a user