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:
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -346,6 +346,7 @@ void WVDrmFactory::printCdmProperties(int fd) {
|
||||
// Debug properties. Not exposed to app.
|
||||
{"boot_certificate_chain",
|
||||
wvcdm::QUERY_KEY_DEBUG_BOOT_CERTIFICATE_CHAIN},
|
||||
{"device_information", wvcdm::QUERY_KEY_DEVICE_INFORMATION},
|
||||
};
|
||||
|
||||
string value;
|
||||
|
||||
Reference in New Issue
Block a user