From b11890a694f838c881526917da2730740cdf2162 Mon Sep 17 00:00:00 2001 From: Alex Dale Date: Thu, 9 Jun 2022 15:58:18 -0700 Subject: [PATCH] Provide BCC in WVDrmFactory dumpsys. [ Merge of go/wvgerrit/c/cdm/+/165138 ] Enabled the Widevine DRM service on Android to return the raw boot certificate chain via the CDM status query capabilities. This property key is not available for app-level queries. The BCC is dumped by the WVDrmFactory when requested to print all CDM properties via dumpsys. Bug: 234095402 Test: request_license_test Test: adb shell dumpsys android.hardware.drm.IDrmFactory/widevine -p Change-Id: I34695b0655b4c609979577e9986974bc0fbda898 --- .../cdm/core/include/wv_cdm_constants.h | 3 +++ libwvdrmengine/cdm/core/src/cdm_engine.cpp | 19 +++++++++++++ .../cdm/core/src/crypto_session.cpp | 27 +++++++++++-------- .../cdm/test/request_license_test.cpp | 16 ++++++++++- libwvdrmengine/src/WVDrmFactory.cpp | 17 +++++------- 5 files changed, 60 insertions(+), 22 deletions(-) diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_constants.h b/libwvdrmengine/cdm/core/include/wv_cdm_constants.h index 5bd04b81..1e40068a 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_constants.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_constants.h @@ -119,6 +119,9 @@ static const std::string QUERY_KEY_CAN_DISABLE_ANALOG_OUTPUT = "CanDisableAnalogOutput"; static const std::string QUERY_KEY_WATERMARKING_SUPPORT = "WatermarkingSupport"; 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_VALUE_TRUE = "True"; static const std::string QUERY_VALUE_FALSE = "False"; diff --git a/libwvdrmengine/cdm/core/src/cdm_engine.cpp b/libwvdrmengine/cdm/core/src/cdm_engine.cpp index b6723f1a..ffa37ac0 100644 --- a/libwvdrmengine/cdm/core/src/cdm_engine.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_engine.cpp @@ -852,6 +852,25 @@ CdmResponseType CdmEngine::QueryStatus(RequestedSecurityLevel security_level, *query_response = std::to_string(system_id); return CdmResponseType(NO_ERROR); } + if (query_token == QUERY_KEY_DEBUG_BOOT_CERTIFICATE_CHAIN) { + std::string bcc; + std::string signature_unused; + const CdmResponseType status = crypto_session->GetBootCertificateChain( + security_level, &bcc, &signature_unused); + if (status == NO_ERROR) { + LOGD("BCC length: %zu", bcc.size()); + *query_response = std::move(bcc); + return CdmResponseType(NO_ERROR); + } + if (status == NOT_IMPLEMENTED_ERROR || + status == PROVISIONING_TYPE_IS_NOT_BOOT_CERTIFICATE_CHAIN_ERROR) { + LOGD("BCC not available: %d", static_cast(status.Enum())); + *query_response = QUERY_VALUE_NONE; + return CdmResponseType(NO_ERROR); + } + LOGE("Failed to extract BCC: status = %d", static_cast(status.Enum())); + return status; + } CdmResponseType status; M_TIME(status = crypto_session->Open(security_level), diff --git a/libwvdrmengine/cdm/core/src/crypto_session.cpp b/libwvdrmengine/cdm/core/src/crypto_session.cpp index 7d14f428..5d36e53b 100644 --- a/libwvdrmengine/cdm/core/src/crypto_session.cpp +++ b/libwvdrmengine/cdm/core/src/crypto_session.cpp @@ -837,19 +837,17 @@ CdmResponseType CryptoSession::GetProvisioningId(std::string* provisioning_id) { RETURN_IF_NULL(provisioning_id, PARAMETER_NULL); RETURN_IF_NOT_OPEN(CRYPTO_SESSION_NOT_OPEN); - if (pre_provision_token_type_ == kClientTokenOemCert) { - // OEM Cert devices have no provisioning-unique ID embedded in them, so we - // synthesize one by using the External Device-Unique ID and inverting all - // the bits. - CdmResponseType status = GetExternalDeviceUniqueId(provisioning_id); - + if (pre_provision_token_type_ == kClientTokenOemCert || + pre_provision_token_type_ == kClientTokenBootCertChain) { + // OEM Cert and BCC devices have no provisioning-unique ID embedded in + // them, so we synthesize one by using the External Device-Unique ID + // and inverting all the bits. + const CdmResponseType status = GetExternalDeviceUniqueId(provisioning_id); if (status != NO_ERROR) return status; - for (size_t i = 0; i < provisioning_id->size(); ++i) { - char value = (*provisioning_id)[i]; - (*provisioning_id)[i] = ~value; + for (char& c : *provisioning_id) { + c ^= 0xff; } - return CdmResponseType(NO_ERROR); } if (pre_provision_token_type_ == kClientTokenKeybox) { @@ -1383,7 +1381,14 @@ CdmResponseType CryptoSession::GetBootCertificateChain( RETURN_IF_UNINITIALIZED(CRYPTO_SESSION_NOT_INITIALIZED); LOGV("requested_security_level = %s", RequestedSecurityLevelToString(requested_security_level)); - if (pre_provision_token_type_ != kClientTokenBootCertChain) { + 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); } diff --git a/libwvdrmengine/cdm/test/request_license_test.cpp b/libwvdrmengine/cdm/test/request_license_test.cpp index c01981d4..49b7fbeb 100644 --- a/libwvdrmengine/cdm/test/request_license_test.cpp +++ b/libwvdrmengine/cdm/test/request_license_test.cpp @@ -4208,7 +4208,21 @@ TEST_F(WvCdmRequestLicenseTest, QueryStatus) { kLevelDefault, wvcdm::QUERY_KEY_PROVISIONING_MODEL, &value)); // These are the only valid values for Android devices. EXPECT_TRUE(value == wvcdm::QUERY_VALUE_KEYBOX || - value == wvcdm::QUERY_VALUE_OEM_CERTIFICATE); + value == wvcdm::QUERY_VALUE_OEM_CERTIFICATE || + value == wvcdm::QUERY_VALUE_BOOT_CERTIFICATE_CHAIN); + + const bool expect_bcc = (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. + 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, diff --git a/libwvdrmengine/src/WVDrmFactory.cpp b/libwvdrmengine/src/WVDrmFactory.cpp index b8a8844b..2e36b6ca 100644 --- a/libwvdrmengine/src/WVDrmFactory.cpp +++ b/libwvdrmengine/src/WVDrmFactory.cpp @@ -10,6 +10,7 @@ #include "WVDrmFactory.h" #include +#include #include #include @@ -154,19 +155,12 @@ int32_t WVDrmFactory::firstApiLevel() { return ::ndk::ScopedAStatus::ok(); } -string WVDrmFactory::stringToHex(const string& s) { - string input(s.c_str()); - bool toHex = false; - for (const char ch : input) { - if (!isprint(ch)) { - toHex = true; - break; - } +string WVDrmFactory::stringToHex(const string& input) { + if (std::all_of(input.begin(), input.end(), ::isprint)) { + return input; } - if (!toHex) return input; static constexpr char hex[] = "0123456789ABCDEF"; - string output; output.reserve(input.length() * 2); for (const unsigned char ch : input) { @@ -247,6 +241,9 @@ void WVDrmFactory::printCdmProperties(int fd) { wvcdm::QUERY_KEY_CAN_DISABLE_ANALOG_OUTPUT}, {"watermarking_support", wvcdm::QUERY_KEY_WATERMARKING_SUPPORT}, {"production_ready", wvcdm::QUERY_KEY_PRODUCTION_READY}, + // Debug properties. Not exposed to app. + {"boot_certificate_chain", + wvcdm::QUERY_KEY_DEBUG_BOOT_CERTIFICATE_CHAIN}, }; string value;