Cdm to expose GetDeviceInformation() and GetDeviceSignedCsrPayload()

GetDeviceInformation() and GetDeviceSignedCsrPayload() are added to
cdm_engine and crypto_session, so that they can be queried by DRM
plugin. This is to allow the wv drm HAL to be able to extract BCC and
CSR payload to build CSR for prov 4 device registration, such that we
don't need a separate RKP HAL to do this job.

Changes to the DRM plugin to use the exposed methods will be in the
coming CL.

Bug: 286556950
Test: request_license_test
Merged from https://widevine-internal-review.googlesource.com/178890

Merged from https://widevine-internal-review.googlesource.com/179730

Change-Id: Ibafa3a58c99fbb8f1f25f8951d3749110bd32176
This commit is contained in:
Cong Lin
2023-07-19 11:17:12 -07:00
committed by Robert Shih
parent c600ccb741
commit 30669a7b67
9 changed files with 179 additions and 7 deletions

View File

@@ -180,6 +180,11 @@ class CdmEngine {
virtual CdmResponseType QueryOemCryptoSessionId(
const CdmSessionId& session_id, CdmQueryMap* query_response);
// Query Signed CSR payload for Prov 4 device
virtual CdmResponseType QueryDeviceSignedCsrPayload(
const std::string& challenge, const std::string& device_info,
std::string* query_response);
// Generate and return a valid provisioning request.
virtual CdmResponseType GetProvisioningRequest(
CdmCertificateType cert_type, const std::string& cert_authority,

View File

@@ -196,6 +196,13 @@ class CryptoSession {
std::string* additional_signature);
virtual CdmResponseType GetBootCertificateChain(
std::string* bcc, std::string* additional_signature);
virtual CdmResponseType GetDeviceInformation(
RequestedSecurityLevel requested_security_level,
std::string* device_info);
virtual CdmResponseType GetDeviceSignedCsrPayload(
RequestedSecurityLevel requested_security_level,
const std::string& challenge, const std::string& device_info,
std::string* signed_csr_payload);
virtual CdmResponseType GenerateCertificateKeyPair(
std::string* public_key, std::string* public_key_signature,
std::string* wrapped_private_key, CryptoWrappedKey::Type* key_type);

View File

@@ -124,6 +124,7 @@ static const std::string QUERY_KEY_PRODUCTION_READY = "ProductionReady";
// Internal query key. Should not be exposed to Android apps.
static const std::string QUERY_KEY_DEBUG_BOOT_CERTIFICATE_CHAIN =
"DebugBootCertificateChain";
static const std::string QUERY_KEY_DEVICE_INFORMATION = "DeviceInformation";
static const std::string QUERY_VALUE_TRUE = "True";
static const std::string QUERY_VALUE_FALSE = "False";

View File

@@ -461,6 +461,8 @@ enum CdmResponseEnum : int32_t {
STORE_ATSC_LICENSE_ERROR = 395,
SESSION_NOT_FOUND_GENERIC_CRYPTO = 396,
SESSION_NOT_FOUND_24 = 397,
GET_DEVICE_INFORMATION_ERROR = 398,
GET_DEVICE_SIGNED_CSR_PAYLOAD_ERROR = 399,
// Don't forget to add new values to
// * core/src/wv_cdm_types.cpp
// * android/include/mapErrors-inl.h

View File

@@ -887,7 +887,7 @@ CdmResponseType CdmEngine::QueryStatus(RequestedSecurityLevel security_level,
const CdmResponseType status = crypto_session->GetBootCertificateChain(
security_level, &bcc, &signature_unused);
if (status == NO_ERROR) {
LOGD("BCC length: %zu", bcc.size());
LOGV("BCC length: %zu", bcc.size());
*query_response = std::move(bcc);
return CdmResponseType(NO_ERROR);
}
@@ -900,6 +900,24 @@ CdmResponseType CdmEngine::QueryStatus(RequestedSecurityLevel security_level,
LOGE("Failed to extract BCC: status = %d", status.ToInt());
return status;
}
if (query_token == QUERY_KEY_DEVICE_INFORMATION) {
std::string device_info;
const CdmResponseType status =
crypto_session->GetDeviceInformation(security_level, &device_info);
if (status == NO_ERROR) {
LOGV("device_info length: %zu", device_info.size());
*query_response = std::move(device_info);
return CdmResponseType(NO_ERROR);
}
if (status == NOT_IMPLEMENTED_ERROR ||
status == PROVISIONING_TYPE_IS_NOT_BOOT_CERTIFICATE_CHAIN_ERROR) {
LOGV("device_info not available: %s", status.ToString().c_str());
*query_response = QUERY_VALUE_NONE;
return CdmResponseType(NO_ERROR);
}
LOGE("Failed to extract device_info: %s", status.ToString().c_str());
return status;
}
CdmResponseType status;
M_TIME(status = crypto_session->Open(security_level),
@@ -1038,6 +1056,34 @@ CdmResponseType CdmEngine::QueryOemCryptoSessionId(
return session->QueryOemCryptoSessionId(query_response);
}
CdmResponseType CdmEngine::QueryDeviceSignedCsrPayload(
const std::string& challenge, const std::string& device_info,
std::string* query_response) {
if (query_response == nullptr) {
LOGE("Output |query_response| is null");
return CdmResponseType(PARAMETER_NULL);
}
std::unique_ptr<CryptoSession> crypto_session(
CryptoSession::MakeCryptoSession(metrics_->GetCryptoMetrics()));
std::string signed_csr_payload;
const CdmResponseType status = crypto_session->GetDeviceSignedCsrPayload(
kLevelDefault, challenge, device_info, &signed_csr_payload);
if (status == NO_ERROR) {
LOGV("signed_csr_payload length: %zu", signed_csr_payload.size());
*query_response = std::move(signed_csr_payload);
return CdmResponseType(NO_ERROR);
}
if (status == NOT_IMPLEMENTED_ERROR ||
status == PROVISIONING_TYPE_IS_NOT_BOOT_CERTIFICATE_CHAIN_ERROR) {
LOGD("signed_csr_payload not available: %s", status.ToString().c_str());
*query_response = QUERY_VALUE_NONE;
return CdmResponseType(NO_ERROR);
}
LOGE("Failed to extract signed_csr_payload: %s", status.ToString().c_str());
return status;
}
// static
bool CdmEngine::IsSecurityLevelSupported(CdmSecurityLevel level) {
LOGI("level = %s", CdmSecurityLevelToString(level));
@@ -2358,9 +2404,9 @@ CdmResponseType CdmEngine::SignRsa(const std::string& wrapped_key,
{
std::unique_lock<std::recursive_mutex> lock(session_map_lock_);
if (!session_map_.FindSession(session_id, &session)) {
LOGE("Session not found: session_id = %s", IdToString(session_id));
CloseSession(session_id);
return CdmResponseType(SESSION_NOT_FOUND_24);
LOGE("Session not found: session_id = %s", IdToString(session_id));
CloseSession(session_id);
return CdmResponseType(SESSION_NOT_FOUND_24);
}
}

View File

@@ -1450,6 +1450,100 @@ CdmResponseType CryptoSession::GetBootCertificateChain(
return CdmResponseType(NO_ERROR);
}
CdmResponseType CryptoSession::GetDeviceInformation(
RequestedSecurityLevel requested_security_level, std::string* device_info) {
RETURN_IF_NULL(device_info, PARAMETER_NULL);
RETURN_IF_UNINITIALIZED(CRYPTO_SESSION_NOT_INITIALIZED);
if (GetSecurityLevel(requested_security_level) != kSecurityLevelL1) {
LOGE("CDM only supports L1 device_info");
return CdmResponseType(NOT_IMPLEMENTED_ERROR);
}
CdmClientTokenType token_type = kClientTokenUninitialized;
const CdmResponseType status =
GetProvisioningMethod(requested_security_level, &token_type);
if (status != NO_ERROR) {
LOGE("Failed to get token type");
return status;
}
if (token_type != kClientTokenBootCertChain) {
return CdmResponseType(
PROVISIONING_TYPE_IS_NOT_BOOT_CERTIFICATE_CHAIN_ERROR);
}
size_t device_info_length = 0;
OEMCryptoResult sts = WithOecReadLock("GetDeviceInformation Attempt 1", [&] {
return OEMCrypto_GetDeviceInformation(nullptr, &device_info_length);
});
if (sts == OEMCrypto_ERROR_SHORT_BUFFER) {
device_info->resize(device_info_length);
sts = WithOecReadLock("GetDeviceInformation Attempt 2", [&] {
return OEMCrypto_GetDeviceInformation(
MutableStringDataPointer(device_info), &device_info_length);
});
}
if (sts != OEMCrypto_SUCCESS) {
LOGE("OEMCrypto_GetDeviceInformation failed: status = %d",
static_cast<int>(sts));
device_info->clear();
return MapOEMCryptoResult(sts, GET_DEVICE_INFORMATION_ERROR,
"GetDeviceInformation");
}
device_info->resize(device_info_length);
return CdmResponseType(NO_ERROR);
}
CdmResponseType CryptoSession::GetDeviceSignedCsrPayload(
RequestedSecurityLevel requested_security_level,
const std::string& challenge, const std::string& device_info,
std::string* signed_csr_payload) {
RETURN_IF_NULL(signed_csr_payload, PARAMETER_NULL);
RETURN_IF_UNINITIALIZED(CRYPTO_SESSION_NOT_INITIALIZED);
if (GetSecurityLevel(requested_security_level) != kSecurityLevelL1) {
LOGE("CDM only supports L1 CSR payload");
return CdmResponseType(NOT_IMPLEMENTED_ERROR);
}
CdmClientTokenType token_type = kClientTokenUninitialized;
const CdmResponseType status =
GetProvisioningMethod(requested_security_level, &token_type);
if (status != NO_ERROR) {
LOGE("Failed to get token type");
return status;
}
if (token_type != kClientTokenBootCertChain) {
return CdmResponseType(
PROVISIONING_TYPE_IS_NOT_BOOT_CERTIFICATE_CHAIN_ERROR);
}
size_t signed_csr_payload_length = 0;
OEMCryptoResult sts =
WithOecReadLock("GetDeviceSignedCsrPayload Attempt 1", [&] {
return OEMCrypto_GetDeviceSignedCsrPayload(
reinterpret_cast<const uint8_t*>(challenge.data()),
challenge.size(),
reinterpret_cast<const uint8_t*>(device_info.data()),
device_info.size(), nullptr, &signed_csr_payload_length);
});
if (sts == OEMCrypto_ERROR_SHORT_BUFFER) {
signed_csr_payload->resize(signed_csr_payload_length);
sts = WithOecReadLock("GetDeviceSignedCsrPayload Attempt 2", [&] {
return OEMCrypto_GetDeviceSignedCsrPayload(
reinterpret_cast<const uint8_t*>(challenge.data()), challenge.size(),
reinterpret_cast<const uint8_t*>(device_info.data()),
device_info.size(), MutableStringDataPointer(signed_csr_payload),
&signed_csr_payload_length);
});
}
if (sts != OEMCrypto_SUCCESS) {
LOGE("OEMCrypto_GetDeviceSignedCsrPayload failed: status = %d",
static_cast<int>(sts));
signed_csr_payload->clear();
return MapOEMCryptoResult(sts, GET_DEVICE_SIGNED_CSR_PAYLOAD_ERROR,
"GetDeviceSignedCsrPayload");
}
signed_csr_payload->resize(signed_csr_payload_length);
return CdmResponseType(NO_ERROR);
}
CdmResponseType CryptoSession::GenerateCertificateKeyPair(
std::string* public_key, std::string* public_key_signature,
std::string* wrapped_private_key, CryptoWrappedKey::Type* key_type) {

View File

@@ -819,6 +819,10 @@ const char* CdmResponseEnumToString(CdmResponseEnum cdm_response_enum) {
return "PROVISIONING_TYPE_IS_NOT_BOOT_CERTIFICATE_CHAIN_ERROR";
case GET_BOOT_CERTIFICATE_CHAIN_ERROR:
return "GET_BOOT_CERTIFICATE_CHAIN_ERROR";
case GET_DEVICE_INFORMATION_ERROR:
return "GET_DEVICE_INFORMATION_ERROR";
case GET_DEVICE_SIGNED_CSR_PAYLOAD_ERROR:
return "GET_DEVICE_SIGNED_CSR_PAYLOAD_ERROR";
case GENERATE_CERTIFICATE_KEY_PAIR_ERROR:
return "GENERATE_CERTIFICATE_KEY_PAIR_ERROR";
case GENERATE_CERTIFICATE_KEY_PAIR_UNKNOWN_TYPE_ERROR:

View File

@@ -5348,18 +5348,30 @@ TEST_F(WvCdmRequestLicenseTest, QueryStatus) {
value == wvcdm::QUERY_VALUE_OEM_CERTIFICATE ||
value == wvcdm::QUERY_VALUE_BOOT_CERTIFICATE_CHAIN);
const bool expect_bcc = (value == wvcdm::QUERY_VALUE_BOOT_CERTIFICATE_CHAIN);
const bool is_prov4 = (value == wvcdm::QUERY_VALUE_BOOT_CERTIFICATE_CHAIN);
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_->QueryStatus(
kLevelDefault, wvcdm::QUERY_KEY_DEBUG_BOOT_CERTIFICATE_CHAIN,
&value));
if (expect_bcc) {
// Expect that the BCC is returned; but do not validate the actual value.
if (is_prov4) {
// Expect that the BCC is returned for Prov 4; but do not validate the
// actual value.
EXPECT_FALSE(value.empty()) << "BCC is empty";
EXPECT_NE(value, wvcdm::QUERY_VALUE_NONE) << "BCC is none";
} else {
EXPECT_EQ(value, wvcdm::QUERY_VALUE_NONE);
}
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_->QueryStatus(
kLevelDefault, wvcdm::QUERY_KEY_DEVICE_INFORMATION, &value));
if (is_prov4) {
// Expect that the device info is returned for Prov 4; but do not validate
// the actual value.
EXPECT_FALSE(value.empty()) << "Device info is empty";
EXPECT_NE(value, wvcdm::QUERY_VALUE_NONE) << "Device info is none";
} else {
EXPECT_EQ(value, wvcdm::QUERY_VALUE_NONE);
}
EXPECT_EQ(
wvcdm::NO_ERROR,