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);