From 1fd5a8bf371bfb07995fbff2004ef4b9a901d6cb Mon Sep 17 00:00:00 2001 From: Cong Lin Date: Thu, 15 Feb 2024 15:18:21 -0800 Subject: [PATCH] Add BCC extract tool for BCC uploading test Extract BCC and build info from oemcrypto, construct BCC uploading record and dumps it out a JSON file. The BCC uploader will pick up the output file later. Bug: 312787974 Change-Id: Ie8ef6a75408e8ef8355b1c0de14532de0ae83732 --- .../oemcrypto/test/extract_bcc_tool.cpp | 173 ++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 libwvdrmengine/oemcrypto/test/extract_bcc_tool.cpp diff --git a/libwvdrmengine/oemcrypto/test/extract_bcc_tool.cpp b/libwvdrmengine/oemcrypto/test/extract_bcc_tool.cpp new file mode 100644 index 00000000..a469ea6a --- /dev/null +++ b/libwvdrmengine/oemcrypto/test/extract_bcc_tool.cpp @@ -0,0 +1,173 @@ +// Copyright 2024 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. +// This tool extracts BCC by calling OEMCrypto APIs and generates a CSR file in +// JSON format, which can be handled by CE CDM wv_upload_tool.py. +#include +#include +#include +#include +#include +#include + +#include "OEMCryptoCENC.h" +#include "string_conversions.h" + +namespace { +// Make and Model for system ID resolution. +const std::string kDeviceMake = "widevine_test"; +const std::string kDeviceModel = "prov4"; + +// Informative fields. +const std::string kDeviceArchitecture = "x86_64"; +const std::string kDeviceName = "prov40 test client"; +const std::string kDeviceProduct = "prov40 test"; +const std::string kDeviceBuildInfo = "prov40 test build"; + +// == Utils == + +std::string StringMapToJson( + const std::map& string_map) { + std::string json = "{"; + for (const auto& value_pair : string_map) { + std::string escaped_value = + std::regex_replace(value_pair.second, std::regex("\""), "\\\""); + json.append("\"" + value_pair.first + "\": " + "\"" + escaped_value + + "\","); + } + json.resize(json.size() - 1); // Remove the last comma. + json.append("}"); + return json; +} + +// == Primary == + +bool GetBccAndBuildInfo(std::vector* bcc, + std::string* oemcrypto_build_info) { + // Step 1: Initialize. + OEMCryptoResult result = OEMCrypto_Initialize(); + if (result != OEMCrypto_SUCCESS) { + std::cerr << "Failed to initialize: result = " << result << std::endl; + return false; + } + + // Step 2: Get BCC. + const OEMCrypto_ProvisioningMethod method = OEMCrypto_GetProvisioningMethod(); + if (method != OEMCrypto_BootCertificateChain) { + std::cerr << "ProvisioningMethod is not BCC type: method = "; + std::cerr << method << std::endl; + OEMCrypto_Terminate(); + return false; + } + + bcc->resize(0); + size_t bcc_size = 0; + std::vector additional_signature; // It should be empty. + size_t additional_signature_size = 0; + result = OEMCrypto_GetBootCertificateChain(bcc->data(), &bcc_size, + additional_signature.data(), + &additional_signature_size); + if (additional_signature_size != 0) { + std::cerr << "The additional_signature_size required by OEMCrypto is " + << additional_signature_size + << ", while it is expected to be zero." << std::endl; + OEMCrypto_Terminate(); + return false; + } + if (result == OEMCrypto_ERROR_SHORT_BUFFER) { + bcc->resize(bcc_size); + additional_signature.resize(additional_signature_size); + result = OEMCrypto_GetBootCertificateChain(bcc->data(), &bcc_size, + additional_signature.data(), + &additional_signature_size); + } + if (result != OEMCrypto_SUCCESS) { + std::cerr << "Failed to get BCC: result = " << result << std::endl; + OEMCrypto_Terminate(); + return false; + } + bcc->resize(bcc_size); + + // Step 3: Get oemcrypto build info. + oemcrypto_build_info->resize(0); + size_t oemcrypto_build_info_size = 0; + result = OEMCrypto_BuildInformation(oemcrypto_build_info->data(), + &oemcrypto_build_info_size); + if (result == OEMCrypto_ERROR_SHORT_BUFFER) { + oemcrypto_build_info->resize(oemcrypto_build_info_size); + result = OEMCrypto_BuildInformation(oemcrypto_build_info->data(), + &oemcrypto_build_info_size); + } + if (result != OEMCrypto_SUCCESS) { + std::cerr << "Failed to get build information: result = " << result + << std::endl; + OEMCrypto_Terminate(); + return false; + } + oemcrypto_build_info->resize(oemcrypto_build_info_size); + + // Step 4: Cleanup. + result = OEMCrypto_Terminate(); + if (result != OEMCrypto_SUCCESS) { + std::cerr << "Failed to terminate: result = " << result << std::endl; + return false; + } + return true; +} + +bool GenerateBccRecord(const std::vector& bcc, + const std::string& oemcrypto_build_info, + std::string* bcc_record) { + std::map record; + record["company"] = kDeviceMake; + record["model"] = kDeviceModel; + + record["architecture"] = kDeviceArchitecture; + record["name"] = kDeviceName; + record["product"] = kDeviceProduct; + record["build_info"] = kDeviceBuildInfo; + record["bcc"] = wvutil::Base64Encode(bcc); + record["oemcrypto_build_info"] = oemcrypto_build_info; + + const std::string record_json = StringMapToJson(record); + bcc_record->assign(record_json.begin(), record_json.end()); + return true; +} + +bool OutputBccRecord(const std::string& path, const std::string& record) { + std::cout << "Writing BCC record to file " << path << std::endl; + std::cout << record << std::endl; + std::ofstream out(path); + if (out) out << record; + if (out.bad()) { + std::cerr << "Failed to write BCC record to file " << path << std::endl; + return false; + } + return true; +} +} // namespace + +int main(int argc, char** argv) { + if (argc != 2) { + std::cerr << "Usage: " << argv[0] << " " << std::endl; + return 1; + } + const std::string bcc_path = argv[1]; + + std::vector bcc; + std::string oemcrypto_build_info; + if (!GetBccAndBuildInfo(&bcc, &oemcrypto_build_info)) { + std::cerr << "Failed to get BCC or OEMCrypto build info" << std::endl; + return 1; + } + std::string bcc_record; + if (!GenerateBccRecord(bcc, oemcrypto_build_info, &bcc_record)) { + std::cerr << "Failed to generate BCC record" << std::endl; + return 1; + } + if (!OutputBccRecord(bcc_path, bcc_record)) { + std::cerr << "Failed to output BCC record" << std::endl; + return 1; + } + return 0; +}