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(
|
virtual CdmResponseType QueryOemCryptoSessionId(
|
||||||
const CdmSessionId& session_id, CdmQueryMap* query_response);
|
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.
|
// Generate and return a valid provisioning request.
|
||||||
virtual CdmResponseType GetProvisioningRequest(
|
virtual CdmResponseType GetProvisioningRequest(
|
||||||
CdmCertificateType cert_type, const std::string& cert_authority,
|
CdmCertificateType cert_type, const std::string& cert_authority,
|
||||||
|
|||||||
@@ -196,6 +196,13 @@ class CryptoSession {
|
|||||||
std::string* additional_signature);
|
std::string* additional_signature);
|
||||||
virtual CdmResponseType GetBootCertificateChain(
|
virtual CdmResponseType GetBootCertificateChain(
|
||||||
std::string* bcc, std::string* additional_signature);
|
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(
|
virtual CdmResponseType GenerateCertificateKeyPair(
|
||||||
std::string* public_key, std::string* public_key_signature,
|
std::string* public_key, std::string* public_key_signature,
|
||||||
std::string* wrapped_private_key, CryptoWrappedKey::Type* key_type);
|
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.
|
// Internal query key. Should not be exposed to Android apps.
|
||||||
static const std::string QUERY_KEY_DEBUG_BOOT_CERTIFICATE_CHAIN =
|
static const std::string QUERY_KEY_DEBUG_BOOT_CERTIFICATE_CHAIN =
|
||||||
"DebugBootCertificateChain";
|
"DebugBootCertificateChain";
|
||||||
|
static const std::string QUERY_KEY_DEVICE_INFORMATION = "DeviceInformation";
|
||||||
|
|
||||||
static const std::string QUERY_VALUE_TRUE = "True";
|
static const std::string QUERY_VALUE_TRUE = "True";
|
||||||
static const std::string QUERY_VALUE_FALSE = "False";
|
static const std::string QUERY_VALUE_FALSE = "False";
|
||||||
|
|||||||
@@ -461,6 +461,8 @@ enum CdmResponseEnum : int32_t {
|
|||||||
STORE_ATSC_LICENSE_ERROR = 395,
|
STORE_ATSC_LICENSE_ERROR = 395,
|
||||||
SESSION_NOT_FOUND_GENERIC_CRYPTO = 396,
|
SESSION_NOT_FOUND_GENERIC_CRYPTO = 396,
|
||||||
SESSION_NOT_FOUND_24 = 397,
|
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
|
// Don't forget to add new values to
|
||||||
// * core/src/wv_cdm_types.cpp
|
// * core/src/wv_cdm_types.cpp
|
||||||
// * android/include/mapErrors-inl.h
|
// * android/include/mapErrors-inl.h
|
||||||
|
|||||||
@@ -887,7 +887,7 @@ CdmResponseType CdmEngine::QueryStatus(RequestedSecurityLevel security_level,
|
|||||||
const CdmResponseType status = crypto_session->GetBootCertificateChain(
|
const CdmResponseType status = crypto_session->GetBootCertificateChain(
|
||||||
security_level, &bcc, &signature_unused);
|
security_level, &bcc, &signature_unused);
|
||||||
if (status == NO_ERROR) {
|
if (status == NO_ERROR) {
|
||||||
LOGD("BCC length: %zu", bcc.size());
|
LOGV("BCC length: %zu", bcc.size());
|
||||||
*query_response = std::move(bcc);
|
*query_response = std::move(bcc);
|
||||||
return CdmResponseType(NO_ERROR);
|
return CdmResponseType(NO_ERROR);
|
||||||
}
|
}
|
||||||
@@ -900,6 +900,24 @@ CdmResponseType CdmEngine::QueryStatus(RequestedSecurityLevel security_level,
|
|||||||
LOGE("Failed to extract BCC: status = %d", status.ToInt());
|
LOGE("Failed to extract BCC: status = %d", status.ToInt());
|
||||||
return status;
|
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;
|
CdmResponseType status;
|
||||||
M_TIME(status = crypto_session->Open(security_level),
|
M_TIME(status = crypto_session->Open(security_level),
|
||||||
@@ -1038,6 +1056,34 @@ CdmResponseType CdmEngine::QueryOemCryptoSessionId(
|
|||||||
return session->QueryOemCryptoSessionId(query_response);
|
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
|
// static
|
||||||
bool CdmEngine::IsSecurityLevelSupported(CdmSecurityLevel level) {
|
bool CdmEngine::IsSecurityLevelSupported(CdmSecurityLevel level) {
|
||||||
LOGI("level = %s", CdmSecurityLevelToString(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_);
|
std::unique_lock<std::recursive_mutex> lock(session_map_lock_);
|
||||||
if (!session_map_.FindSession(session_id, &session)) {
|
if (!session_map_.FindSession(session_id, &session)) {
|
||||||
LOGE("Session not found: session_id = %s", IdToString(session_id));
|
LOGE("Session not found: session_id = %s", IdToString(session_id));
|
||||||
CloseSession(session_id);
|
CloseSession(session_id);
|
||||||
return CdmResponseType(SESSION_NOT_FOUND_24);
|
return CdmResponseType(SESSION_NOT_FOUND_24);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1450,6 +1450,100 @@ CdmResponseType CryptoSession::GetBootCertificateChain(
|
|||||||
return CdmResponseType(NO_ERROR);
|
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(
|
CdmResponseType CryptoSession::GenerateCertificateKeyPair(
|
||||||
std::string* public_key, std::string* public_key_signature,
|
std::string* public_key, std::string* public_key_signature,
|
||||||
std::string* wrapped_private_key, CryptoWrappedKey::Type* key_type) {
|
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";
|
return "PROVISIONING_TYPE_IS_NOT_BOOT_CERTIFICATE_CHAIN_ERROR";
|
||||||
case GET_BOOT_CERTIFICATE_CHAIN_ERROR:
|
case GET_BOOT_CERTIFICATE_CHAIN_ERROR:
|
||||||
return "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:
|
case GENERATE_CERTIFICATE_KEY_PAIR_ERROR:
|
||||||
return "GENERATE_CERTIFICATE_KEY_PAIR_ERROR";
|
return "GENERATE_CERTIFICATE_KEY_PAIR_ERROR";
|
||||||
case GENERATE_CERTIFICATE_KEY_PAIR_UNKNOWN_TYPE_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_OEM_CERTIFICATE ||
|
||||||
value == wvcdm::QUERY_VALUE_BOOT_CERTIFICATE_CHAIN);
|
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,
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
||||||
decryptor_->QueryStatus(
|
decryptor_->QueryStatus(
|
||||||
kLevelDefault, wvcdm::QUERY_KEY_DEBUG_BOOT_CERTIFICATE_CHAIN,
|
kLevelDefault, wvcdm::QUERY_KEY_DEBUG_BOOT_CERTIFICATE_CHAIN,
|
||||||
&value));
|
&value));
|
||||||
if (expect_bcc) {
|
if (is_prov4) {
|
||||||
// Expect that the BCC is returned; but do not validate the actual value.
|
// Expect that the BCC is returned for Prov 4; but do not validate the
|
||||||
|
// actual value.
|
||||||
EXPECT_FALSE(value.empty()) << "BCC is empty";
|
EXPECT_FALSE(value.empty()) << "BCC is empty";
|
||||||
EXPECT_NE(value, wvcdm::QUERY_VALUE_NONE) << "BCC is none";
|
EXPECT_NE(value, wvcdm::QUERY_VALUE_NONE) << "BCC is none";
|
||||||
} else {
|
} else {
|
||||||
EXPECT_EQ(value, wvcdm::QUERY_VALUE_NONE);
|
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(
|
EXPECT_EQ(
|
||||||
wvcdm::NO_ERROR,
|
wvcdm::NO_ERROR,
|
||||||
|
|||||||
@@ -346,6 +346,7 @@ void WVDrmFactory::printCdmProperties(int fd) {
|
|||||||
// Debug properties. Not exposed to app.
|
// Debug properties. Not exposed to app.
|
||||||
{"boot_certificate_chain",
|
{"boot_certificate_chain",
|
||||||
wvcdm::QUERY_KEY_DEBUG_BOOT_CERTIFICATE_CHAIN},
|
wvcdm::QUERY_KEY_DEBUG_BOOT_CERTIFICATE_CHAIN},
|
||||||
|
{"device_information", wvcdm::QUERY_KEY_DEVICE_INFORMATION},
|
||||||
};
|
};
|
||||||
|
|
||||||
string value;
|
string value;
|
||||||
|
|||||||
Reference in New Issue
Block a user