diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_constants.h b/libwvdrmengine/cdm/core/include/wv_cdm_constants.h index c35236aa..8c73a4aa 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_constants.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_constants.h @@ -124,6 +124,8 @@ 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_KEY_DEBUG_BOOT_CERTIFICATE_CHAIN_SIGNATURE = + "DebugBootCertificateChainSignature"; static const std::string QUERY_KEY_DEVICE_INFORMATION = "DeviceInformation"; static const std::string QUERY_VALUE_TRUE = "True"; diff --git a/libwvdrmengine/cdm/core/src/cdm_engine.cpp b/libwvdrmengine/cdm/core/src/cdm_engine.cpp index d0e26d61..424e5755 100644 --- a/libwvdrmengine/cdm/core/src/cdm_engine.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_engine.cpp @@ -903,6 +903,26 @@ CdmResponseType CdmEngine::QueryStatus(RequestedSecurityLevel security_level, LOGE("Failed to extract BCC: status = %d", status.ToInt()); return status; } + if (query_token == QUERY_KEY_DEBUG_BOOT_CERTIFICATE_CHAIN_SIGNATURE) { + std::string bcc_unused; + std::string signature; + const CdmResponseType status = crypto_session->GetBootCertificateChain( + security_level, &bcc_unused, &signature); + if (status == NO_ERROR) { + LOGV("BCC signature length: %zu", signature.size()); + *query_response = std::move(signature); + return CdmResponseType(NO_ERROR); + } + if (status == NOT_IMPLEMENTED_ERROR || + status == PROVISIONING_TYPE_IS_NOT_BOOT_CERTIFICATE_CHAIN_ERROR) { + LOGD("BCC signature not available: %s", status.ToString().c_str()); + *query_response = QUERY_VALUE_NONE; + return CdmResponseType(NO_ERROR); + } + LOGE("Failed to extract BCC signature: status = %s", + status.ToString().c_str()); + return status; + } if (query_token == QUERY_KEY_DEVICE_INFORMATION) { std::string device_info; const CdmResponseType status = diff --git a/libwvdrmengine/cdm/core/src/initialization_data.cpp b/libwvdrmengine/cdm/core/src/initialization_data.cpp index cf87d24a..2c0312ca 100644 --- a/libwvdrmengine/cdm/core/src/initialization_data.cpp +++ b/libwvdrmengine/cdm/core/src/initialization_data.cpp @@ -454,8 +454,7 @@ bool InitializationData::ConstructWidevineInitData( LOGV("Base64 decode of json data failed"); return false; } - std::string json_string((const char*)(&json_init_data[0]), - json_init_data.size()); + const std::string json_string(json_init_data.begin(), json_init_data.end()); // Parse the Json string using jsmn jsmn_parser parser; @@ -513,12 +512,13 @@ bool InitializationData::ConstructWidevineInitData( break; case kContentIdState: if (tokens[i].type == JSMN_STRING) { - std::string base64_content_id(json_string, tokens[i].start, - tokens[i].end - tokens[i].start); - std::vector content_id_data = + const std::string base64_content_id = json_string.substr( + tokens[i].start, tokens[i].end - tokens[i].start); + const std::vector content_id_data = wvutil::Base64Decode(base64_content_id); - content_id.assign(reinterpret_cast(&content_id_data[0]), - content_id_data.size()); + if (!content_id_data.empty()) { + content_id.assign(content_id_data.begin(), content_id_data.end()); + } } state = kParseState; break; diff --git a/libwvdrmengine/cdm/core/test/initialization_data_unittest.cpp b/libwvdrmengine/cdm/core/test/initialization_data_unittest.cpp index 57d2265f..7d072853 100644 --- a/libwvdrmengine/cdm/core/test/initialization_data_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/initialization_data_unittest.cpp @@ -869,4 +869,27 @@ INSTANTIATE_TEST_SUITE_P( HlsAttributeVariant(kHlsAttributeListInvalidIv, HLS_IV_ATTRIBUTE, kHlsTestHexValueWithOddBytes, false))); +TEST_F(HlsParseTest, BadHlsData_InvalidContentId) { + std::ostringstream hls_uri_json_stream; + hls_uri_json_stream << "{"; + hls_uri_json_stream << "\"provider\": \"HlsParseTest.BadHlsData\", "; + // Intentionally bad Base64 content ID. + hls_uri_json_stream << "\"content_id\": \"$$$$\", "; + hls_uri_json_stream << "\"key_ids\": [\"00000000000000000000000000000000\"]"; + hls_uri_json_stream << "}"; + const std::string hls_uri_json = hls_uri_json_stream.str(); + + std::ostringstream hls_stream; + hls_stream << "#EXT-X-KEY:"; + hls_stream << "METHOD=AES-128,"; + hls_stream << "URI=\"data:text/plain;base64," + << wvutil::Base64Encode(hls_uri_json) << "\","; + hls_stream << "IV=0x00000000000000000000000000000000,"; + hls_stream << "KEYFORMAT=\"com.widevine\","; + hls_stream << "KEYFORMATVERSIONS=\"1\""; + const std::string hls_data = hls_stream.str(); + // std::cout << "HLS Data:" << std::endl << hls_data << std::endl; + InitializationData init_data(HLS_INIT_DATA_FORMAT, hls_data); + EXPECT_TRUE(init_data.is_hls()); +} } // namespace wvcdm diff --git a/libwvdrmengine/cdm/test/request_license_test.cpp b/libwvdrmengine/cdm/test/request_license_test.cpp index 6de975d1..b8048085 100644 --- a/libwvdrmengine/cdm/test/request_license_test.cpp +++ b/libwvdrmengine/cdm/test/request_license_test.cpp @@ -5388,6 +5388,12 @@ TEST_F(WvCdmRequestLicenseTest, QueryStatus) { // actual value. EXPECT_FALSE(value.empty()) << "BCC is empty"; EXPECT_NE(value, wvcdm::QUERY_VALUE_NONE) << "BCC is none"; + // BCC signature is optional. Do not validate the actual value. + EXPECT_EQ( + wvcdm::NO_ERROR, + decryptor_->QueryStatus( + kLevelDefault, + wvcdm::QUERY_KEY_DEBUG_BOOT_CERTIFICATE_CHAIN_SIGNATURE, &value)); } else { EXPECT_EQ(value, wvcdm::QUERY_VALUE_NONE); } diff --git a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp index 32d705e7..5ad1bc7b 100644 --- a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp +++ b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp @@ -1296,6 +1296,18 @@ static WvStatus getDeviceSignedCsrPayload( } else { value = StrToVector(boot_certificate_chain); } + } else if (name == "bootCertificateChainSignature" && isCsrAccessAllowed()) { + std::string boot_certificate_chain_signature; + const CdmResponseType res = mCDM->QueryStatus(wvcdm::kLevelDefault, + wvcdm::QUERY_KEY_DEBUG_BOOT_CERTIFICATE_CHAIN_SIGNATURE, + &boot_certificate_chain_signature); + if (res != wvcdm::NO_ERROR) { + ALOGE("Error querying CDM boot certificate chain signature: %d", + static_cast(res)); + status = mapCdmResponseType(res); + } else { + value = StrToVector(boot_certificate_chain_signature); + } } else if (name == "verifiedDeviceInfo" && isCsrAccessAllowed()) { std::string verified_device_info; CdmResponseType res = mCDM->QueryStatus(wvcdm::kLevelDefault, diff --git a/libwvdrmengine/src/WVDrmFactory.cpp b/libwvdrmengine/src/WVDrmFactory.cpp index b33c8442..17caffc2 100644 --- a/libwvdrmengine/src/WVDrmFactory.cpp +++ b/libwvdrmengine/src/WVDrmFactory.cpp @@ -346,6 +346,8 @@ void WVDrmFactory::printCdmProperties(int fd) { // Debug properties. Not exposed to app. {"boot_certificate_chain", wvcdm::QUERY_KEY_DEBUG_BOOT_CERTIFICATE_CHAIN}, + {"boot_certificate_chain_signature", + wvcdm::QUERY_KEY_DEBUG_BOOT_CERTIFICATE_CHAIN_SIGNATURE}, {"device_information", wvcdm::QUERY_KEY_DEVICE_INFORMATION}, }; diff --git a/libwvdrmengine/version.txt b/libwvdrmengine/version.txt index 3ee04453..b9111ff0 100644 --- a/libwvdrmengine/version.txt +++ b/libwvdrmengine/version.txt @@ -1 +1 @@ -AV1A.241002.001 +AV1A.241005.001