From 6327211db6660807ed34d2cee692e886846a015c Mon Sep 17 00:00:00 2001 From: Cong Lin Date: Wed, 19 Jul 2023 11:27:13 -0700 Subject: [PATCH] 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 --- .../include/wv_content_decryption_module.h | 7 +- .../cdm/src/wv_content_decryption_module.cpp | 7 ++ libwvdrmengine/mediadrm/include/WVDrmPlugin.h | 5 +- libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp | 114 ++++++++++++++---- 4 files changed, 110 insertions(+), 23 deletions(-) diff --git a/libwvdrmengine/cdm/include/wv_content_decryption_module.h b/libwvdrmengine/cdm/include/wv_content_decryption_module.h index 5eb9f055..50cb0582 100644 --- a/libwvdrmengine/cdm/include/wv_content_decryption_module.h +++ b/libwvdrmengine/cdm/include/wv_content_decryption_module.h @@ -11,7 +11,7 @@ #include #include -#include +#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); diff --git a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp index 3c313476..b21a075c 100644 --- a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp +++ b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp @@ -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); diff --git a/libwvdrmengine/mediadrm/include/WVDrmPlugin.h b/libwvdrmengine/mediadrm/include/WVDrmPlugin.h index 1dcebcd3..b5e14891 100644 --- a/libwvdrmengine/mediadrm/include/WVDrmPlugin.h +++ b/libwvdrmengine/mediadrm/include/WVDrmPlugin.h @@ -42,7 +42,7 @@ const OEMCrypto_Algorithm kInvalidCryptoAlgorithm = static_cast(-1); class WVDrmPlugin : public ::aidl::android::hardware::drm::BnDrmPlugin, - wvcdm::WvCdmEventListener { + wvcdm::WvCdmEventListener { public: WVDrmPlugin(const android::sp& 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, diff --git a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp index ca45430d..7002f4ae 100644 --- a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp +++ b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp @@ -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& 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 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(res)); + return mapCdmResponseType(res); + } + *csr = signed_csr_payload; + return WvStatus(Status::OK); +} + ::ndk::ScopedAStatus WVDrmPlugin::getPropertyByteArray( const std::string& in_propertyName, vector* _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(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(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 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& sessionId, CdmResponseType res) { notifyOfCdmResponseType(sessionId, res);