Re-purpose internal factory upload tool for AOSP

This tool was supposed to be used for internal debugging purpose on
Android devices. It already supports RKP uploading CSR format.

Extend this tool to support  Widevine uploading format: JSON csr
and make this format as default output for AOSP (non-GMS) partners.

A later change will move it to its own aosp/ directory.

Test: run "wv_factory_extraction_tool json_csr" on Pixel 9
Bug: 414642286
Change-Id: I9cf4e9696d32201cc1ad70b6bee7932f7126a4ba
This commit is contained in:
conglin
2025-06-09 23:25:13 +00:00
parent cbcb2124d0
commit 1f77085571
5 changed files with 168 additions and 43 deletions

View File

@@ -26,6 +26,9 @@ cc_binary {
"liblog",
"libutils",
],
static_libs: [
"libwv_cdm_utils",
],
srcs: [
"cli.cpp",
"src/log.cpp",

View File

@@ -160,29 +160,82 @@ std::unique_ptr<cppbor::Array> getCsrV3(
return composeCertificateRequestV3(csr);
}
int main(int argc, char** argv) {
if (argc < 2) {
fprintf(stderr, "%s <bcc|bcc_str|device_info|csr|csr_v3>\n", argv[0]);
return 0;
void printHelp(const char* tool_name) {
fprintf(stdout, "Widevine Factory Extraction Tool for AOSP\n\n");
fprintf(stdout, "Usage: %s [command]\n\n", tool_name);
fprintf(stdout,
"This tool extracts BCC and device information and generates CSR "
"required for Widevine Provisioning 4.0 factory uploading.\n\n");
fprintf(stdout, "Commands:\n");
fprintf(stdout, " json_csr (default)\n");
fprintf(stdout,
" Generates and prints a JSON-formatted "
"Certificate Signing\n");
fprintf(stdout,
" Request (CSR) to be uploaded to the "
"Widevine provisioning server.\n\n");
fprintf(stdout, " bcc\n");
fprintf(stdout,
" Outputs the raw binary Bootloader "
"Certificate Chain (BCC).\n\n");
fprintf(stdout, " bcc_str\n");
fprintf(stdout,
" Outputs a human-readable, parsed string "
"representation of the BCC.\n\n");
fprintf(stdout, " device_info\n");
fprintf(
stdout,
" Outputs the raw binary device information blob.\n\n");
fprintf(stdout, " csr\n");
fprintf(stdout,
" Generates and outputs a legacy format Certificate "
"Signing Request (CSR) to be uploaded to RKP backend.\n\n");
fprintf(stdout, " csr_v3\n");
fprintf(stdout,
" Generates and outputs a V3 format Certificate "
"Signing Request (CSR) to be uploaded to RKP backend.\n\n");
fprintf(stdout, " help\n");
fprintf(stdout, " Displays this help message.\n");
}
int main(int argc, char** argv) {
widevine::WidevineProvisioner provisioner;
if (!std::strcmp(argv[1], "bcc")) {
// Default to Widevine uploading request format "json_csr" if no arguments are
// provided.
const char* command = (argc > 1) ? argv[1] : "json_csr";
if (!std::strcmp(command, "json_csr")) {
std::string request;
if (provisioner.GenerateWidevineUploadRequest(request)) {
std::copy(request.begin(), request.end(),
std::ostream_iterator<char>(std::cout));
} else {
fprintf(stderr,
"Failed to generate Widevine uploading request json CSR.\n");
return 1;
}
} else if (!std::strcmp(command, "help")) {
printHelp(argv[0]);
} else if (!std::strcmp(command, "bcc")) {
auto bcc = provisioner.GetBcc();
fwrite(bcc.data(), 1, bcc.size(), stdout);
fflush(stdout);
} else if (!std::strcmp(argv[1], "bcc_str")) {
} else if (!std::strcmp(command, "bcc_str")) {
auto bcc = provisioner.GetBcc();
widevine::BccParser bcc_parser;
std::string parsed_bcc = bcc_parser.Parse(bcc);
std::copy(parsed_bcc.begin(), parsed_bcc.end(),
std::ostream_iterator<char>(std::cout));
} else if (!std::strcmp(argv[1], "device_info")) {
} else if (!std::strcmp(command, "device_info")) {
std::vector<uint8_t> deviceInfo;
if (provisioner.GetDeviceInfo(deviceInfo)) {
fwrite(deviceInfo.data(), 1, deviceInfo.size(), stdout);
fflush(stdout);
} else {
fprintf(stderr, "Failed to get device info.\n");
return 1;
}
} else if (!std::strcmp(argv[1], "csr")) {
} else if (!std::strcmp(command, "csr")) {
auto csr = getCsr(provisioner);
auto bytes = csr.encode();
std::copy(bytes.begin(), bytes.end(),
@@ -193,7 +246,14 @@ int main(int argc, char** argv) {
auto bytes = csr->encode();
std::copy(bytes.begin(), bytes.end(),
std::ostream_iterator<char>(std::cout));
} else {
fprintf(stderr, "Failed to generate CSR V3.\n");
return 1;
}
} else {
fprintf(stderr, "Error: Unknown command '%s'\n\n", command);
printHelp(argv[0]);
return 1;
}
return 0;
}

View File

@@ -9,6 +9,7 @@
#include <cstddef>
#include <cstdint>
#include <map>
#include <memory>
#include <string>
#include <vector>
@@ -32,6 +33,7 @@ class WidevineProvisioner {
bool GenerateCertificateRequestV2(const std::vector<uint8_t>& challenge,
std::vector<uint8_t>* csr);
bool GetDeviceInfo(std::vector<uint8_t>& device_info);
bool GenerateWidevineUploadRequest(std::string& request);
private:
bool GenerateProtectedData(
@@ -48,6 +50,9 @@ class WidevineProvisioner {
bool GetDeviceInfoCommon(cppbor::Map& device_info_map);
bool TryAddVerifiedDeviceInfo(cppbor::Map& device_info_map);
bool GetDeviceInfoV2(cppbor::Map& device_info_map);
void PopulateDeviceInfoFromCborMap(
const cppbor::Map& device_info_map,
std::map<std::string, std::string>& request_map);
std::unique_ptr<OEMCryptoInterface> crypto_interface_;
};

View File

@@ -7,8 +7,6 @@
#include <dlfcn.h>
#include "OEMCryptoCENC.h"
#include "clock.h"
#include "file_store.h"
#include "log.h"
// These macros lookup the obfuscated name used for OEMCrypto.
@@ -24,38 +22,6 @@
#define LOAD_SYM_IF_EXIST(name) \
name = reinterpret_cast<name##_t>(LOOKUP(handle_, OEMCrypto_##name));
// These are implementations required by OEMCrypto Reference Implementation
// and/or the Testbed, but not needed in this package.
namespace wvutil {
int64_t Clock::GetCurrentTime() { return 0; }
class FileImpl final : public File {
public:
FileImpl() {}
ssize_t Read(char*, size_t) override { return 0; }
ssize_t Write(const char*, size_t) override { return 0; }
};
class FileSystem::Impl {
public:
Impl() {}
};
FileSystem::FileSystem() {}
FileSystem::FileSystem(const std::string&, void*) {}
FileSystem::~FileSystem() {}
std::unique_ptr<File> FileSystem::Open(const std::string&, int) {
return std::unique_ptr<File>(new FileImpl());
}
bool FileSystem::Exists(const std::string&) { return false; }
bool FileSystem::Remove(const std::string&) { return false; }
ssize_t FileSystem::FileSize(const std::string&) { return false; }
bool FileSystem::List(const std::string&, std::vector<std::string>*) {
return false;
}
} // namespace wvutil
namespace widevine {
OEMCryptoInterface::~OEMCryptoInterface() {

View File

@@ -22,6 +22,7 @@
#include "WidevineOemcryptoInterface.h"
#include "log.h"
#include "properties.h"
#include "string_conversions.h"
namespace widevine {
@@ -31,6 +32,51 @@ const std::vector<std::vector<uint8_t>> kAuthorizedEekRoots = {
0x62, 0xDC, 0x3E, 0x61, 0xAB, 0x57, 0x48, 0x7D, 0x75, 0x37, 0x29,
0xAD, 0x76, 0x80, 0x32, 0xD2, 0xB3, 0xCB, 0x63, 0x58, 0xD9},
};
std::string EscapeJson(const std::string& input) {
std::string result;
for (std::string::const_iterator c = input.begin(); c != input.end(); ++c) {
switch (*c) {
case '\"':
result += "\\\"";
break;
case '\\':
result += "\\\\";
break;
case '\b':
result += "\\b";
break;
case '\f':
result += "\\f";
break;
case '\n':
result += "\\n";
break;
case '\r':
result += "\\r";
break;
case '\t':
result += "\\t";
break;
default:
result += *c;
break;
}
}
return result;
}
std::string StringMapToJson(
const std::map<std::string, std::string>& string_map) {
std::string json = "{";
for (const auto& value_pair : string_map) {
json.append("\"" + value_pair.first + "\": " + "\"" + value_pair.second +
"\",");
}
json.resize(json.size() - 1); // Remove the last comma.
json.append("}");
return json;
}
} // namespace
WidevineProvisioner::WidevineProvisioner() {
@@ -107,7 +153,8 @@ bool WidevineProvisioner::TryAddVerifiedDeviceInfo(
}
bool WidevineProvisioner::GetDeviceInfoCommon(cppbor::Map& device_info_map) {
if (!TryAddVerifiedDeviceInfo(device_info_map)) return false;
// Best effort to populate device info from TEE first
TryAddVerifiedDeviceInfo(device_info_map);
// Add device information from OS properties if the verified device info is
// not present
if (device_info_map.get("brand") == nullptr ||
@@ -390,6 +437,50 @@ bool WidevineProvisioner::GenerateCertificateRequestV2(
return true;
}
// Caller ensures the validity of `device_info_map` as a `cppbor::Map&`.
void WidevineProvisioner::PopulateDeviceInfoFromCborMap(
const cppbor::Map& device_info_map,
std::map<std::string, std::string>& request_map) {
if (device_info_map.get("manufacturer")) {
request_map["company"] =
device_info_map.get("manufacturer")->asTstr()->value();
}
if (device_info_map.get("device")) {
request_map["name"] = device_info_map.get("device")->asTstr()->value();
}
if (device_info_map.get("architecture")) {
request_map["architecture"] =
device_info_map.get("architecture")->asTstr()->value();
}
if (device_info_map.get("model")) {
request_map["model"] = device_info_map.get("model")->asTstr()->value();
}
if (device_info_map.get("product")) {
request_map["product"] = device_info_map.get("product")->asTstr()->value();
}
if (device_info_map.get("fingerprint")) {
request_map["build_info"] =
device_info_map.get("fingerprint")->asTstr()->value();
}
if (device_info_map.get("oemcrypto_build_info")) {
request_map["oemcrypto_build_info"] = EscapeJson(
device_info_map.get("oemcrypto_build_info")->asTstr()->value());
}
}
bool WidevineProvisioner::GenerateWidevineUploadRequest(std::string& request) {
std::map<std::string, std::string> request_map;
auto bcc = GetBcc();
request_map["bcc"] = wvutil::Base64Encode(bcc);
auto device_info_map = cppbor::Map();
if (!GetDeviceInfoCommon(device_info_map)) return false;
PopulateDeviceInfoFromCborMap(device_info_map, request_map);
request = StringMapToJson(request_map);
return true;
}
void WidevineProvisioner::InitializeCryptoInterface() {
std::string oemcrypto_path;
if (!wvcdm::Properties::GetOEMCryptoPath(&oemcrypto_path)) {