WVDrmPlugin changes to query device CSR payload for prov 4

Plugin to provide getPropertyByteArray("deviceSignedCsrPayload")
which returns the signed CSR payload for device registration. It
queries both BCC and device info to be set in plugin before calling this
getPropertyByteArray("deviceSignedCsrPayload") method. The returned csr
payload will be used by assemble the device CSR by the caller for device
registration.

Bug: 286556950
Test: build WV DRM plugin
Merged from https://widevine-internal-review.googlesource.com/178891

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

Change-Id: I65d89ed998dd292fc656af2f91f4472c1b5ec33c
This commit is contained in:
Cong Lin
2023-07-19 11:27:13 -07:00
committed by Robert Shih
parent a0f6b99cbe
commit 6327211db6
4 changed files with 110 additions and 23 deletions

View File

@@ -11,7 +11,7 @@
#include <memory>
#include <mutex>
#include <utils/RefBase.h>
#include "utils/RefBase.h"
#include "cdm_identifier.h"
#include "disallow_copy_and_assign.h"
@@ -135,6 +135,11 @@ class WvContentDecryptionModule : public android::RefBase, public TimerHandler {
virtual CdmResponseType QueryKeyStatus(const CdmSessionId& session_id,
CdmQueryMap* key_info);
// Query device CSR information for Provisioning 4.0
virtual CdmResponseType QueryDeviceSignedCsrPayload(
const std::string& challenge, const std::string& device_info,
std::string* value);
// Query OEMCrypto session ID
virtual CdmResponseType QueryOemCryptoSessionId(
const CdmSessionId& session_id, CdmQueryMap* response);

View File

@@ -305,6 +305,13 @@ CdmResponseType WvContentDecryptionModule::QueryOemCryptoSessionId(
return cdm_engine->QueryOemCryptoSessionId(session_id, response);
}
CdmResponseType WvContentDecryptionModule::QueryDeviceSignedCsrPayload(
const std::string& challenge, const std::string& device_info,
std::string* value) {
CdmEngine* cdm_engine = EnsureCdmForIdentifier(kDefaultCdmIdentifier);
return cdm_engine->QueryDeviceSignedCsrPayload(challenge, device_info, value);
}
bool WvContentDecryptionModule::IsSecurityLevelSupported(
CdmSecurityLevel level) {
return CdmEngine::IsSecurityLevelSupported(level);

View File

@@ -42,7 +42,7 @@ const OEMCrypto_Algorithm kInvalidCryptoAlgorithm =
static_cast<OEMCrypto_Algorithm>(-1);
class WVDrmPlugin : public ::aidl::android::hardware::drm::BnDrmPlugin,
wvcdm::WvCdmEventListener {
wvcdm::WvCdmEventListener {
public:
WVDrmPlugin(const android::sp<WvContentDecryptionModule>& cdm,
const std::string& appPackageName,
@@ -462,6 +462,9 @@ class WVDrmPlugin : public ::aidl::android::hardware::drm::BnDrmPlugin,
std::string mAppPackageName;
std::string mCertificateSigningRequestChallenge;
std::string mDeviceInfo;
::ndk::SpAIBinder createBinder() override;
WvStatus queryProperty(const std::string& property,

View File

@@ -4,7 +4,7 @@
// Agreement.
//
//#define LOG_NDEBUG 0
// #define LOG_NDEBUG 0
#define LOG_TAG "WVCdm"
#include "WVDrmPlugin.h"
@@ -154,6 +154,12 @@ HdcpLevel mapHdcpLevel(const std::string& level) {
}
}
bool isRootOrShell() {
const uid_t AID_ROOT = 0, AID_SHELL = 2000;
const uid_t uid = AIBinder_getCallingUid();
return (uid == AID_ROOT || uid == AID_SHELL);
}
} // namespace
WVDrmPlugin::WVDrmPlugin(const android::sp<WvContentDecryptionModule>& cdm,
@@ -759,7 +765,8 @@ Status WVDrmPlugin::unprovisionDevice() {
}
drm_metrics::WvCdmMetrics proto_metrics;
const CdmResponseType result = mCDM->GetCurrentMetrics(identifier, &proto_metrics);
const CdmResponseType result =
mCDM->GetCurrentMetrics(identifier, &proto_metrics);
if (result != wvcdm::NO_ERROR) {
return toNdkScopedAStatus(mapCdmResponseType(result));
}
@@ -1066,7 +1073,8 @@ Status WVDrmPlugin::unprovisionDevice() {
value = info->name;
} else {
auto err = info.error();
ALOGW("apex info error %d: %s", err.code().value(), err.message().c_str());
ALOGW("apex info error %d: %s", err.code().value(),
err.message().c_str());
value = "Google";
}
#else
@@ -1165,6 +1173,26 @@ Status WVDrmPlugin::unprovisionDevice() {
return toNdkScopedAStatus(status);
}
static WvStatus getDeviceSignedCsrPayload(
android::sp<wvcdm::WvContentDecryptionModule> const cdm,
std::string& certificate_signing_request_challenge,
std::string& device_info, std::string* csr) {
if (certificate_signing_request_challenge.empty() || device_info.empty()) {
ALOGW("CSR challenge or device info is empty.");
return WvStatus(Status::BAD_VALUE);
}
std::string signed_csr_payload;
CdmResponseType res = cdm->QueryDeviceSignedCsrPayload(
certificate_signing_request_challenge, device_info, &signed_csr_payload);
if (res != wvcdm::NO_ERROR) {
ALOGE("Error querying CDM device_signed_csr_payload: %d",
static_cast<int>(res));
return mapCdmResponseType(res);
}
*csr = signed_csr_payload;
return WvStatus(Status::OK);
}
::ndk::ScopedAStatus WVDrmPlugin::getPropertyByteArray(
const std::string& in_propertyName, vector<uint8_t>* _aidl_return) {
WvStatus status(Status::OK);
@@ -1210,6 +1238,42 @@ Status WVDrmPlugin::unprovisionDevice() {
value = StrToVector(serialized_metrics);
}
}
} else if (name == "bootCertificateChain" && isRootOrShell()) {
std::string boot_certificate_chain;
CdmResponseType res = mCDM->QueryStatus(
wvcdm::kLevelDefault, wvcdm::QUERY_KEY_DEBUG_BOOT_CERTIFICATE_CHAIN,
&boot_certificate_chain);
if (res != wvcdm::NO_ERROR) {
ALOGE("Error querying CDM boot certificate chain: %d",
static_cast<int>(res));
status = mapCdmResponseType(res);
} else {
value = StrToVector(boot_certificate_chain);
}
} else if (name == "verifiedDeviceInfo" && isRootOrShell()) {
std::string verified_device_info;
CdmResponseType res = mCDM->QueryStatus(wvcdm::kLevelDefault,
wvcdm::QUERY_KEY_DEVICE_INFORMATION,
&verified_device_info);
if (res != wvcdm::NO_ERROR) {
ALOGE("Error querying CDM verified device info: %d",
static_cast<int>(res));
status = mapCdmResponseType(res);
} else {
value = StrToVector(verified_device_info);
}
} else if (name == "deviceSignedCsrPayload" && isRootOrShell()) {
std::string signed_csr_payload;
status =
getDeviceSignedCsrPayload(mCDM, mCertificateSigningRequestChallenge,
mDeviceInfo, &signed_csr_payload);
if (status != Status::OK) {
ALOGE("Error querying CDM signed CSR payload: %d", status.get());
} else {
value = StrToVector(signed_csr_payload);
}
mCertificateSigningRequestChallenge.clear();
mDeviceInfo.clear();
} else {
ALOGE("App requested unknown byte array property %s", name.c_str());
status = WvStatus(Status::ERROR_DRM_CANNOT_HANDLE);
@@ -1349,8 +1413,9 @@ Status WVDrmPlugin::unprovisionDevice() {
}
} else if (name == "storeAtscLicense") {
if (!mCdmIdentifierBuilder.is_sealed()) {
ALOGE("Cdm identifier builder is not sealed. Storing ATSC license "
"prohibited");
ALOGE(
"Cdm identifier builder is not sealed. Storing ATSC license "
"prohibited");
return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
}
if (!mPropertySet.use_atsc_mode()) {
@@ -1366,8 +1431,7 @@ Status WVDrmPlugin::unprovisionDevice() {
}
std::string key_set_id, license_data;
status = parseAtscLicenseData(_value, &key_set_id, &license_data);
if (status != Status::OK)
return toNdkScopedAStatus(status);
if (status != Status::OK) return toNdkScopedAStatus(status);
const CdmResponseType res = mCDM->StoreAtscLicense(
identifier, getRequestedSecurityLevel(), key_set_id, license_data);
@@ -1400,6 +1464,11 @@ Status WVDrmPlugin::unprovisionDevice() {
} else {
return toNdkScopedAStatus(Status::BAD_VALUE);
}
} else if (name == "certificateSigningRequestChallenge" && isRootOrShell()) {
mCertificateSigningRequestChallenge =
std::string(_value.begin(), _value.end());
} else if (name == "deviceInfo" && isRootOrShell()) {
mDeviceInfo = std::string(_value.begin(), _value.end());
} else {
ALOGE("App set unknown byte array property %s", name.c_str());
return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
@@ -1830,8 +1899,7 @@ bool WVDrmPlugin::isProvisioned(wvcdm::CdmSecurityLevel securityLevel,
}
WvStatus WVDrmPlugin::parseAtscLicenseData(
const std::string& in_value,
std::string* key_set_id,
const std::string& in_value, std::string* key_set_id,
std::string* serialized_license_data) {
if (key_set_id == nullptr) {
ALOGE("key_set_id null");
@@ -1843,34 +1911,39 @@ WvStatus WVDrmPlugin::parseAtscLicenseData(
return WvStatus(Status::ERROR_DRM_CANNOT_HANDLE);
}
if (in_value.compare(0,
strlen(wvcdm::ATSC_KEY_SET_ID_PREFIX),
if (in_value.compare(0, strlen(wvcdm::ATSC_KEY_SET_ID_PREFIX),
&wvcdm::ATSC_KEY_SET_ID_PREFIX[0]) != 0) {
ALOGE("ATSC license input does not conform to expectations. Key set does "
"not have a valid ATSC Key set prefix %s", in_value.c_str());
ALOGE(
"ATSC license input does not conform to expectations. Key set does "
"not have a valid ATSC Key set prefix %s",
in_value.c_str());
return WvStatus(Status::BAD_VALUE);
}
const char kColon = ':';
const size_t pos = in_value.find(kColon);
if (pos == std::string::npos) {
ALOGE("ATSC license input does not conform to expectations. Missing colon "
"= %s", in_value.c_str());
ALOGE(
"ATSC license input does not conform to expectations. Missing colon "
"= %s",
in_value.c_str());
return WvStatus(Status::BAD_VALUE);
}
if (pos == in_value.length()) {
ALOGE("ATSC license input does not conform to expectations. No data after "
"colon");
ALOGE(
"ATSC license input does not conform to expectations. No data after "
"colon");
return WvStatus(Status::BAD_VALUE);
}
*key_set_id = in_value.substr(0, pos);
const std::vector<uint8_t> license_data_binary =
wvutil::Base64Decode(in_value.substr(pos+1));
wvutil::Base64Decode(in_value.substr(pos + 1));
if (license_data_binary.empty()) {
ALOGE("ATSC license input does not conform to expectations. License data "
"failed to decode from Base64");
ALOGE(
"ATSC license input does not conform to expectations. License data "
"failed to decode from Base64");
return WvStatus(Status::BAD_VALUE);
}
serialized_license_data->assign(license_data_binary.begin(),
@@ -1879,7 +1952,6 @@ WvStatus WVDrmPlugin::parseAtscLicenseData(
return WvStatus(Status::OK);
}
WvStatus WVDrmPlugin::mapAndNotifyOfCdmResponseType(
const vector<uint8_t>& sessionId, CdmResponseType res) {
notifyOfCdmResponseType(sessionId, res);