Source release 19.2.0
This commit is contained in:
@@ -425,3 +425,12 @@ OEMCryptoResult _oecc151(uint8_t* public_cert, size_t* public_cert_length);
|
||||
|
||||
// OEMCrypto_UseSecondaryKey defined in v19.1
|
||||
OEMCryptoResult _oecc152(OEMCrypto_SESSION session_id, bool dual_key);
|
||||
|
||||
// OEMCrypto_WrapClearPrivateKey defined in v19.2
|
||||
OEMCryptoResult _oecc154(const uint8_t* clear_private_key_bytes,
|
||||
size_t clear_private_key_length,
|
||||
uint8_t* wrapped_private_key,
|
||||
size_t* wrapped_private_key_length);
|
||||
|
||||
// OEMCrypto_MarkOfflineSession defined in v19.2
|
||||
OEMCryptoResult _oecc153(OEMCrypto_SESSION session);
|
||||
|
||||
173
oemcrypto/test/extract_bcc_tool.cpp
Normal file
173
oemcrypto/test/extract_bcc_tool.cpp
Normal file
@@ -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 <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#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<std::string, std::string>& 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<uint8_t>* 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<uint8_t> 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<uint8_t>& bcc,
|
||||
const std::string& oemcrypto_build_info,
|
||||
std::string* bcc_record) {
|
||||
std::map<std::string, std::string> 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] << " <output JSON filename>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
const std::string bcc_path = argv[1];
|
||||
|
||||
std::vector<uint8_t> 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;
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
# OEMCRYPTO Fuzzing - Build clustefuzz and run fuzzing
|
||||
|
||||
## Objective
|
||||
|
||||
* Run fuzzing on OEMCrypto public APIs on linux by building open sourced
|
||||
clusterfuzz source code in order to find security vulnerabilities.
|
||||
|
||||
[Clusterfuzz][1]
|
||||
|
||||
* Partners who implement OEMCrypto can follow these instructions to build
|
||||
clusterfuzz, the fuzzing framework and run fuzzing using fuzzer scripts
|
||||
provided by the Widevine team at Google.
|
||||
|
||||
## Glossary
|
||||
|
||||
* Fuzzing - Fuzzing is a methodology where random, interesting, unexpected
|
||||
inputs are fed to APIs in order to crash those, thereby catching any
|
||||
security vulnerabilities with the code.
|
||||
|
||||
* Fuzzing engines - [libfuzzer][4], afl, honggfuzz are the actual fuzzing
|
||||
engines that get the coverage information from API, use that to generate
|
||||
more interesting inputs which can be passed to fuzzer.
|
||||
|
||||
* Seed corpus - Fuzzing engine trying to generate interesting inputs from an
|
||||
empty file is not efficient. Seed corpus is the initial input that a fuzzer
|
||||
can accept and call the API with that. Fuzzing engine can then mutate this
|
||||
seed corpus to generate more inputs to fuzzer.
|
||||
|
||||
* Clusterfuzz - ClusterFuzz is a scalable fuzzing infrastructure that finds
|
||||
security and stability issues in software. Google uses ClusterFuzz to fuzz
|
||||
all Google products. Clusterfuzz provides us with the capability, tools to
|
||||
upload fuzz binaries and make use of the fuzzing engines to run fuzzing,
|
||||
find crashes and organizes the information. Clusterfuzz framework is open
|
||||
sourced, the source code can be downloaded and framework can be built
|
||||
locally or by using google cloud.
|
||||
|
||||
* Fuzzing output - Fuzzing is used to pass random inputs to API in order to
|
||||
ensure that API is crash resistant. We are not testing functionality via
|
||||
fuzzing. Fuzz scripts run continuously until they find a crash with the API
|
||||
under test.
|
||||
|
||||
## Building fuzz scripts
|
||||
|
||||
This section outlines the steps to build fuzz binaries that can be run
|
||||
continuously using clusterfuzz.
|
||||
|
||||
> **Note:** All the directories mentioned below are relative to cdm repository
|
||||
> root directory.
|
||||
|
||||
1. Fuzz scripts for OEMCrypto APIs are provided by the Widevine team at Google
|
||||
located under `oemcrypto/test/fuzz_tests` directory.
|
||||
|
||||
> **Note:** Prerequisites to run the following step are [here][10]. We also need
|
||||
> to install ninja.
|
||||
|
||||
2. Build a static library of your OEMCrypto implementation.
|
||||
* Compile and link your OEMCrypto implementation source with
|
||||
`-fsanitize=address,fuzzer` flag as per these [instructions][9] when
|
||||
building a static library.
|
||||
|
||||
* Run `./oemcrypto/test/fuzz_tests/build_partner_oemcrypto_fuzztests
|
||||
<oemcrypto_static_library_path>` script from cdm repository root
|
||||
directory.
|
||||
|
||||
* This will generate fuzz binaries under the `out/Default` directory.
|
||||
|
||||
|
||||
|
||||
> **Note:** Alternatively, you can use your own build systems, for which you
|
||||
> will need to define your own build files with the OEMCrypto fuzz source files
|
||||
> included. You can find the the fuzz source files in
|
||||
> `oemcrypto/test/fuzz_tests/partner_oemcrypto_fuzztests.gyp` and
|
||||
> `oemcrypto/test/fuzz_tests/partner_oemcrypto_fuzztests.gypi`.
|
||||
|
||||
3. Seed corpus for each fuzz script can be found under
|
||||
`oemcrypto/test/fuzz_tests/corpus` directory. Some fuzzers are simple and do
|
||||
not have seed corpus associated with them.
|
||||
|
||||
4. Create a zip file `oemcrypto_fuzzers_yyyymmddhhmmss.zip` with fuzz binaries
|
||||
and respective seed corpus zip files. Structure of a sample zip file with
|
||||
fuzzer binaries and seed corpus would look like following:
|
||||
|
||||
```
|
||||
* fuzzerA
|
||||
* fuzzerA_seed_corpus.zip
|
||||
* fuzzerB
|
||||
* fuzzerB_seed_corpus.zip
|
||||
* fuzzerC (fuzzerC doesn't have seed corpus associated with it)
|
||||
```
|
||||
|
||||
## Building clusterfuzz
|
||||
|
||||
* OEMCrypto implementation can be fuzzed by building clusterfuzz code which is
|
||||
open sourced and using it to run fuzzing. Use a Linux VM to build
|
||||
clusterfuzz.
|
||||
|
||||
> **Note:** You may see some issues with python modules missing, please install
|
||||
> those modules if you see errors. If you have multiple versions of python on
|
||||
> the VM, then use `python<version> -m pipenv shell` when you are at [this][3]
|
||||
> step.
|
||||
|
||||
* Follow these [instructions][2] in order to download clusterfuzz repository,
|
||||
build it locally or create a continuous fuzz infrastructure setup using
|
||||
google cloud.
|
||||
|
||||
## Running fuzzers on local clusterfuzz instance
|
||||
|
||||
* If you prefer to run fuzzing on a local machine instead of having a
|
||||
production setup using google cloud, then follow these [instructions][6] to
|
||||
add a job to the local clusterfuzz instance.
|
||||
|
||||
> **Note:** Job name should have a fuzzing engine and sanitizer as part of it. A
|
||||
> libfuzzer and asan jobs should have libfuzzer_asan in the job name.
|
||||
|
||||
* Create a job e:g:`libfuzzer_asan_oemcrypto` and upload previously created
|
||||
`oemcrypto_fuzzers_yyyymmddhhmmss.zip` as a custom build. Future uploads of
|
||||
zip file should have a name greater than current name. Following the above
|
||||
naming standard will ensure zip file names are always in ascending order.
|
||||
|
||||
* Once the job is added and clusterfuzz bot is running, fuzzing should be up
|
||||
and running. Results can be monitored as mentioned [here][6].
|
||||
|
||||
* On a local clusterfuzz instance, only one fuzzer is being fuzzed at a time.
|
||||
|
||||
> **Note:** Fuzzing is time consuming. Finding issues as well as clusterfuzz
|
||||
> regressing and fixing the issues can take time. We need fuzzing to run at
|
||||
> least for a couple of weeks to have good coverage.
|
||||
|
||||
## Finding fuzz crashes
|
||||
|
||||
Once the clusterfuzz finds an issue, it logs crash information such as the
|
||||
build, test case and stack trace for the crash.
|
||||
|
||||
* Test cases tab should show the fuzz crash and test case that caused the
|
||||
crash. Run `./fuzz_binary <test_case>` in order to debug the crash locally.
|
||||
|
||||
More information about different types of logs is as below:
|
||||
|
||||
* [Bot logs][7] will show information related to fuzzing, number of crashes
|
||||
that a particular fuzzer finds, number of new crashes, number of known
|
||||
crashes etc.
|
||||
|
||||
* [Local GCS][8] in your clusterfuzz checkout folder will store the fuzz
|
||||
binaries that are being fuzzed, seed corpus etc.
|
||||
|
||||
* `local_gcs/test-fuzz-logs-bucket` will store information related to fuzz
|
||||
crashes if any were found by the fuzzing engine. It will store crash
|
||||
information categorized by fuzzer and by each day. It will also store test
|
||||
case that caused the crash.
|
||||
|
||||
* `/path/to/my-bot/clusterfuzz/log.txt` will have any log information from
|
||||
fuzzer script and OEMCrypto implementation.
|
||||
|
||||
## Fixing issues
|
||||
|
||||
* Once you are able to debug using the crash test case, apply fix to the
|
||||
implementation, create `oemcrypto_fuzzers_yyyymmddhhmmss.zip` with latest
|
||||
fuzz binaries.
|
||||
|
||||
* Upload the latest fuzz binary to the fuzz job that was created earlier.
|
||||
Fuzzer will recognize the fix and mark the crash as fixed in test cases tab
|
||||
once the regression finishes. You do not need to update crashes as fixed,
|
||||
clusterfuzz will do that.
|
||||
|
||||
[1]: https://google.github.io/clusterfuzz/
|
||||
[2]: https://google.github.io/clusterfuzz/getting-started/
|
||||
[3]: https://google.github.io/clusterfuzz/getting-started/prerequisites/#loading-pipenv
|
||||
[4]: https://llvm.org/docs/LibFuzzer.html
|
||||
[5]: https://google.github.io/clusterfuzz/setting-up-fuzzing/libfuzzer-and-afl/
|
||||
[6]: https://google.github.io/clusterfuzz/setting-up-fuzzing/libfuzzer-and-afl/#checking-results
|
||||
[7]: https://google.github.io/clusterfuzz/getting-started/local-instance/#viewing-logs
|
||||
[8]: https://google.github.io/clusterfuzz/getting-started/local-instance/#local-google-cloud-storage
|
||||
[9]: https://google.github.io/clusterfuzz/setting-up-fuzzing/libfuzzer-and-afl/#libfuzzer
|
||||
[10]: https://google.github.io/clusterfuzz/setting-up-fuzzing/libfuzzer-and-afl/#prerequisites
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,32 +0,0 @@
|
||||
// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine
|
||||
// License Agreement.
|
||||
|
||||
#include "FuzzedDataProvider.h"
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "oemcrypto_fuzz_helper.h"
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
wvoec::RedirectStdoutToFile();
|
||||
|
||||
wvoec::SessionFuzz session_fuzz;
|
||||
session_fuzz.Initialize();
|
||||
|
||||
FuzzedDataProvider fuzzed_data(data, size);
|
||||
|
||||
uint32_t key_session;
|
||||
uint32_t* const key_session_ptr =
|
||||
fuzzed_data.ConsumeBool() ? &key_session : nullptr;
|
||||
|
||||
OEMCrypto_CreateEntitledKeySession(session_fuzz.session().session_id(),
|
||||
key_session_ptr);
|
||||
|
||||
if (key_session_ptr == nullptr || fuzzed_data.ConsumeBool()) {
|
||||
key_session = fuzzed_data.ConsumeIntegral<uint32_t>();
|
||||
}
|
||||
|
||||
OEMCrypto_RemoveEntitledKeySession(key_session);
|
||||
|
||||
session_fuzz.Terminate();
|
||||
return 0;
|
||||
}
|
||||
@@ -122,6 +122,8 @@ class OEMCryptoRenewalAPIFuzz {
|
||||
|
||||
void Initialize() { license_api_fuzz_.Initialize(); }
|
||||
|
||||
void LoadLicense() { license_api_fuzz_.LoadLicense(); }
|
||||
|
||||
void Terminate() { license_api_fuzz_.Terminate(); }
|
||||
|
||||
LicenseRoundTrip& license_messages() {
|
||||
|
||||
@@ -43,6 +43,14 @@ struct OEMCrypto_Renewal_Response_Fuzz {
|
||||
// structure.
|
||||
};
|
||||
|
||||
struct OEMCrypto_Release_Response_Fuzz {
|
||||
oemcrypto_core_message::ODK_ReleaseRequest core_request;
|
||||
int64_t seconds_since_license_received;
|
||||
int64_t seconds_since_first_decrypt;
|
||||
// license_release_response is of variable length and not included in this
|
||||
// structure.
|
||||
};
|
||||
|
||||
struct OEMCrypto_Request_Fuzz {
|
||||
// We would like to fuzz computed signature_length, input core_message_length
|
||||
// that ODK parses and actual message buffer to the request APIs.
|
||||
|
||||
38
oemcrypto/test/fuzz_tests/oemcrypto_load_release_fuzz.cc
Normal file
38
oemcrypto/test/fuzz_tests/oemcrypto_load_release_fuzz.cc
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright 2024 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine
|
||||
// License Agreement.
|
||||
|
||||
#include "FuzzedDataProvider.h"
|
||||
#include "oec_session_util.h"
|
||||
#include "oemcrypto_fuzz_helper.h"
|
||||
#include "oemcrypto_fuzz_structs.h"
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
wvoec::RedirectStdoutToFile();
|
||||
|
||||
// Copy input data to OEMCrypto_Release_Response_Fuzz and rest of message
|
||||
// into encrypted license_release_response.
|
||||
wvoec::OEMCrypto_Release_Response_Fuzz fuzzed_structure;
|
||||
if (size < sizeof(fuzzed_structure)) {
|
||||
return 0;
|
||||
}
|
||||
FuzzedDataProvider fuzzed_data(data, size);
|
||||
fuzzed_data.ConsumeData(&fuzzed_structure, sizeof(fuzzed_structure));
|
||||
const std::vector<uint8_t> release_response =
|
||||
fuzzed_data.ConsumeRemainingBytes<uint8_t>();
|
||||
|
||||
wvoec::OEMCryptoLicenseAPIFuzz license_api_fuzz;
|
||||
license_api_fuzz.Initialize();
|
||||
license_api_fuzz.LoadLicense();
|
||||
|
||||
// Call release response API using fuzzed data.
|
||||
wvoec::ReleaseRoundTrip release_messages(
|
||||
&license_api_fuzz.license_messages());
|
||||
release_messages.SignAndVerifyRequest();
|
||||
release_messages.InjectFuzzedResponseData(
|
||||
fuzzed_structure, release_response.data(), release_response.size());
|
||||
release_messages.LoadResponse();
|
||||
|
||||
license_api_fuzz.Terminate();
|
||||
return 0;
|
||||
}
|
||||
@@ -37,6 +37,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
renewal_response_fuzz.renewal_messages().InjectFuzzedResponseData(
|
||||
fuzzed_structure, renewal_response.data(), renewal_response.size());
|
||||
renewal_response_fuzz.renewal_messages().LoadResponse();
|
||||
|
||||
renewal_response_fuzz.Terminate();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -171,6 +171,12 @@
|
||||
'oemcrypto_load_provisioning_fuzz.cc',
|
||||
],
|
||||
},
|
||||
{
|
||||
'target_name': 'oemcrypto_opk_load_release_fuzz',
|
||||
'sources': [
|
||||
'oemcrypto_load_release_fuzz.cc',
|
||||
],
|
||||
},
|
||||
{
|
||||
'target_name': 'oemcrypto_opk_load_renewal_fuzz',
|
||||
'sources': [
|
||||
@@ -207,6 +213,12 @@
|
||||
'oemcrypto_query_key_control_fuzz.cc',
|
||||
],
|
||||
},
|
||||
{
|
||||
'target_name': 'oemcrypto_opk_release_request_fuzz',
|
||||
'sources': [
|
||||
'oemcrypto_release_request_fuzz.cc',
|
||||
],
|
||||
},
|
||||
{
|
||||
'target_name': 'oemcrypto_opk_renewal_request_fuzz',
|
||||
'sources': [
|
||||
|
||||
32
oemcrypto/test/fuzz_tests/oemcrypto_release_request_fuzz.cc
Normal file
32
oemcrypto/test/fuzz_tests/oemcrypto_release_request_fuzz.cc
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright 2024 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine
|
||||
// License Agreement.
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "oec_session_util.h"
|
||||
#include "oemcrypto_fuzz_helper.h"
|
||||
#include "oemcrypto_fuzz_structs.h"
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
wvoec::RedirectStdoutToFile();
|
||||
|
||||
// If input size is less than fuzz data structure, reject the input.
|
||||
if (size < sizeof(wvoec::OEMCrypto_Request_Fuzz)) {
|
||||
return 0;
|
||||
}
|
||||
wvoec::LicenseWithUsageEntryFuzz entry;
|
||||
entry.Initialize();
|
||||
entry.CreateUsageTableHeader();
|
||||
entry.InstallTestDrmKey();
|
||||
entry.session().CreateNewUsageEntry();
|
||||
entry.session().GenerateNonce();
|
||||
std::vector<uint8_t> encrypted_usage_header;
|
||||
entry.session().UpdateUsageEntry(&encrypted_usage_header);
|
||||
entry.LoadLicense();
|
||||
wvoec::ReleaseRoundTrip release_messages(&entry.license_messages());
|
||||
std::vector<uint8_t> input(data, data + size);
|
||||
release_messages.InjectFuzzedRequestData(input.data(), input.size());
|
||||
entry.Terminate();
|
||||
return 0;
|
||||
}
|
||||
@@ -20,6 +20,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
std::vector<uint8_t> input(data, data + size);
|
||||
wvoec::OEMCryptoRenewalAPIFuzz renewal_api_fuzz;
|
||||
renewal_api_fuzz.Initialize();
|
||||
renewal_api_fuzz.LoadLicense();
|
||||
renewal_api_fuzz.renewal_messages().InjectFuzzedRequestData(input.data(),
|
||||
input.size());
|
||||
renewal_api_fuzz.Terminate();
|
||||
|
||||
@@ -148,6 +148,12 @@
|
||||
'oemcrypto_load_provisioning_fuzz.cc',
|
||||
],
|
||||
},
|
||||
{
|
||||
'target_name': 'oemcrypto_load_release_fuzz',
|
||||
'sources': [
|
||||
'oemcrypto_load_release_fuzz.cc',
|
||||
],
|
||||
},
|
||||
{
|
||||
'target_name': 'oemcrypto_load_renewal_fuzz',
|
||||
'sources': [
|
||||
@@ -184,6 +190,12 @@
|
||||
'oemcrypto_query_key_control_fuzz.cc',
|
||||
],
|
||||
},
|
||||
{
|
||||
'target_name': 'oemcrypto_release_request_fuzz',
|
||||
'sources': [
|
||||
'oemcrypto_release_request_fuzz.cc',
|
||||
],
|
||||
},
|
||||
{
|
||||
'target_name': 'oemcrypto_renewal_request_fuzz',
|
||||
'sources': [
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
if (size > 0 && data[0] == 'H')
|
||||
if (size > 1 && data[1] == 'I')
|
||||
if (size > 2 && data[2] == '!')
|
||||
__builtin_trap();
|
||||
return 0;
|
||||
}
|
||||
154
oemcrypto/test/install_prov30_oem_cert_tool.cpp
Normal file
154
oemcrypto/test/install_prov30_oem_cert_tool.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
// Copyright 2024 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine
|
||||
// License Agreement.
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "oec_test_data.h"
|
||||
#include "platform.h"
|
||||
#include "string_conversions.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr size_t kAesBlockSize = 16;
|
||||
|
||||
/*
|
||||
This function concatenates the test Prov30 OEM certificate chain and key to the
|
||||
format below:
|
||||
|
||||
+-----------------------+----------------------+--------------------------+
|
||||
| Cert Chain Length | Certificate Chain | Key Length |
|
||||
+-----------------------+----------------------+--------------------------+
|
||||
| (4 bytes, big-endian) | (DER-encoded PKCS#7) | (4 bytes, big-endian) |
|
||||
+-----------------------+----------------------+--------------------------+
|
||||
| Private Key |
|
||||
+-----------------------+
|
||||
|
||||
|oem_private_key| should be a RSA key in PKCS#8 PrivateKeyInfo format.
|
||||
|oem_public_cert| should be a DER-encoded PKCS#7 certificate chain.
|
||||
|
||||
The output will be consumed by OEMCrypto Prov30 factory functions:
|
||||
1. It is wrapped by OEMCrypto_WrapKeyboxOrOEMCert(), and
|
||||
2. The wrapped root of trust will be installed by
|
||||
OEMCrypto_InstallKeyboxOrOEMCert(). Therefore, the OEMCrypto implementation of
|
||||
the factory functions and the tool must have an agreement on the format above.
|
||||
*/
|
||||
std::vector<uint8_t> PrepareProv30OEMCertAndKey(
|
||||
const uint8_t* oem_public_cert, const size_t oem_public_cert_size,
|
||||
const uint8_t* oem_private_key, const size_t oem_private_key_size) {
|
||||
std::vector<uint8_t> oem_cert_and_key;
|
||||
// Calculate total size
|
||||
size_t total_size = sizeof(uint32_t) + oem_public_cert_size +
|
||||
sizeof(uint32_t) + oem_private_key_size;
|
||||
oem_cert_and_key.resize(total_size);
|
||||
|
||||
// Offset to track where to write in the output vector
|
||||
size_t offset = 0;
|
||||
// 1. Store public cert size (big-endian)
|
||||
uint32_t networkOrderCertSize = htonl((uint32_t)oem_public_cert_size);
|
||||
std::copy(reinterpret_cast<const uint8_t*>(&networkOrderCertSize),
|
||||
reinterpret_cast<const uint8_t*>(&networkOrderCertSize) +
|
||||
sizeof(uint32_t),
|
||||
oem_cert_and_key.begin());
|
||||
offset += sizeof(uint32_t);
|
||||
|
||||
// 2. Store public cert content
|
||||
std::copy(oem_public_cert, oem_public_cert + oem_public_cert_size,
|
||||
oem_cert_and_key.begin() + offset);
|
||||
offset += oem_public_cert_size;
|
||||
|
||||
// 3. Store private key size (big-endian)
|
||||
uint32_t networkOrderKeySize = htonl((uint32_t)oem_private_key_size);
|
||||
std::copy(
|
||||
reinterpret_cast<const uint8_t*>(&networkOrderKeySize),
|
||||
reinterpret_cast<const uint8_t*>(&networkOrderKeySize) + sizeof(uint32_t),
|
||||
oem_cert_and_key.begin() + offset);
|
||||
offset += sizeof(uint32_t);
|
||||
|
||||
// 4. Store private key content
|
||||
std::copy(oem_private_key, oem_private_key + oem_private_key_size,
|
||||
oem_cert_and_key.begin() + offset);
|
||||
return oem_cert_and_key;
|
||||
}
|
||||
|
||||
OEMCryptoResult InstallTestProv30RootOfTrust(
|
||||
const uint8_t* oem_public_cert, const size_t oem_public_cert_size,
|
||||
const uint8_t* oem_private_key, const size_t oem_private_key_size) {
|
||||
if (oem_public_cert == nullptr || oem_private_key == nullptr ||
|
||||
oem_public_cert_size == 0 || oem_private_key_size == 0) {
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
|
||||
// 1. Prepare OEM cert and key.
|
||||
std::vector<uint8_t> oem_cert_and_key =
|
||||
PrepareProv30OEMCertAndKey(oem_public_cert, oem_public_cert_size,
|
||||
oem_private_key, oem_private_key_size);
|
||||
if (oem_cert_and_key.empty()) {
|
||||
std::cerr << "Failed to prepare OEM cert and key" << std::endl;
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
// Add padding.
|
||||
const uint8_t padding =
|
||||
kAesBlockSize - (oem_cert_and_key.size() % kAesBlockSize);
|
||||
for (size_t i = 0; i < padding; i++) {
|
||||
oem_cert_and_key.push_back(padding);
|
||||
}
|
||||
|
||||
// 2: Initialize OEMCrypto.
|
||||
OEMCryptoResult sts = OEMCrypto_Initialize();
|
||||
if (sts != OEMCrypto_SUCCESS) {
|
||||
std::cerr << "Failed to initialize: result = " << sts << std::endl;
|
||||
return sts;
|
||||
}
|
||||
|
||||
// 3: Wrap OEM cert and key before calling install function.
|
||||
const OEMCrypto_ProvisioningMethod method = OEMCrypto_GetProvisioningMethod();
|
||||
if (method != OEMCrypto_OEMCertificate) {
|
||||
std::cerr << "OEMCrypto is not OEMCrypto_OEMCertificate: method = ";
|
||||
std::cerr << method << std::endl;
|
||||
OEMCrypto_Terminate();
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
std::vector<uint8_t> wrapped_oem_cert_and_key;
|
||||
size_t wrapped_oem_cert_and_key_size = 0;
|
||||
sts = OEMCrypto_WrapKeyboxOrOEMCert(
|
||||
oem_cert_and_key.data(), oem_cert_and_key.size(),
|
||||
wrapped_oem_cert_and_key.data(), &wrapped_oem_cert_and_key_size, nullptr,
|
||||
0);
|
||||
if (sts != OEMCrypto_ERROR_SHORT_BUFFER) {
|
||||
OEMCrypto_Terminate();
|
||||
return sts;
|
||||
}
|
||||
wrapped_oem_cert_and_key.resize(wrapped_oem_cert_and_key_size);
|
||||
sts = OEMCrypto_WrapKeyboxOrOEMCert(
|
||||
oem_cert_and_key.data(), oem_cert_and_key.size(),
|
||||
wrapped_oem_cert_and_key.data(), &wrapped_oem_cert_and_key_size, nullptr,
|
||||
0);
|
||||
if (sts != OEMCrypto_SUCCESS) {
|
||||
OEMCrypto_Terminate();
|
||||
return sts;
|
||||
}
|
||||
|
||||
// 4: Install the wrapped OEM cert and key.
|
||||
sts = OEMCrypto_InstallKeyboxOrOEMCert(wrapped_oem_cert_and_key.data(),
|
||||
wrapped_oem_cert_and_key_size);
|
||||
OEMCrypto_Terminate();
|
||||
return sts;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int main() {
|
||||
const OEMCryptoResult result = InstallTestProv30RootOfTrust(
|
||||
wvoec::kTestOEMPublicCertInfo2, sizeof(wvoec::kTestOEMPublicCertInfo2),
|
||||
wvoec::kTestRSAPKCS8PrivateKeyInfo2_2048,
|
||||
sizeof(wvoec::kTestRSAPKCS8PrivateKeyInfo2_2048));
|
||||
if (result != OEMCrypto_SUCCESS) {
|
||||
std::cerr << "Failed to install OEM cert and key with result: " << result
|
||||
<< std::endl;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -65,7 +65,8 @@ void DeviceFeatures::Initialize() {
|
||||
// baked in certificate.
|
||||
loads_certificate = provisioning_method == OEMCrypto_Keybox ||
|
||||
provisioning_method == OEMCrypto_OEMCertificate ||
|
||||
provisioning_method == OEMCrypto_BootCertificateChain;
|
||||
provisioning_method == OEMCrypto_BootCertificateChain ||
|
||||
provisioning_method == OEMCrypto_DrmReprovisioning;
|
||||
printf("loads_certificate = %s.\n", loads_certificate ? "true" : "false");
|
||||
generic_crypto =
|
||||
(OEMCrypto_ERROR_NOT_IMPLEMENTED !=
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509_vfy.h>
|
||||
#include <stdint.h>
|
||||
@@ -359,6 +360,11 @@ void ProvisioningRoundTrip::PrepareSession(
|
||||
session_->LoadOEMCert(true);
|
||||
session_->GenerateRsaSessionKey();
|
||||
encryptor_.set_enc_key(session_->session_key());
|
||||
} else if (global_features.provisioning_method ==
|
||||
OEMCrypto_DrmReprovisioning) {
|
||||
session_->SetTestRsaPublicKey();
|
||||
session_->GenerateRsaSessionKey();
|
||||
encryptor_.set_enc_key(session_->session_key());
|
||||
} else {
|
||||
EXPECT_EQ(global_features.provisioning_method, OEMCrypto_OEMCertificate);
|
||||
session_->LoadOEMCert(true);
|
||||
@@ -371,7 +377,16 @@ void ProvisioningRoundTrip::VerifyRequestSignature(
|
||||
const vector<uint8_t>& data, const vector<uint8_t>& generated_signature,
|
||||
size_t core_message_length) {
|
||||
if (keybox_ == nullptr) {
|
||||
session()->VerifyRsaSignature(data, generated_signature.data(),
|
||||
std::vector<uint8_t> signature_source;
|
||||
if (global_features.provisioning_method == OEMCrypto_DrmReprovisioning) {
|
||||
// DRM Reprovisioning uses protocol 2.2 which computes signatures for the
|
||||
// sha512 hash of the message and not the full message.
|
||||
signature_source.resize(SHA512_DIGEST_LENGTH);
|
||||
SHA512(data.data(), data.size(), signature_source.data());
|
||||
} else {
|
||||
signature_source = data;
|
||||
}
|
||||
session()->VerifyRsaSignature(signature_source, generated_signature.data(),
|
||||
generated_signature.size(), kSign_RSASSA_PSS);
|
||||
} else {
|
||||
// Setup the derived keys using the proto message (ignoring the core
|
||||
@@ -1575,7 +1590,7 @@ void RenewalRoundTrip::EncryptAndSignResponse() {
|
||||
}
|
||||
|
||||
void RenewalRoundTrip::InjectFuzzedResponseData(
|
||||
OEMCrypto_Renewal_Response_Fuzz& fuzzed_data,
|
||||
const OEMCrypto_Renewal_Response_Fuzz& fuzzed_data,
|
||||
const uint8_t* renewal_response, const size_t renewal_response_size) {
|
||||
// TODO(b/191724203): Test renewal server has different version from license
|
||||
// server.
|
||||
@@ -1692,8 +1707,53 @@ void ReleaseRoundTrip::EncryptAndSignResponse() {
|
||||
SetEncryptAndSignResponseLengths();
|
||||
}
|
||||
|
||||
void ReleaseRoundTrip::InjectFuzzedResponseData(
|
||||
const OEMCrypto_Release_Response_Fuzz& fuzzed_data,
|
||||
const uint8_t* release_response, const size_t release_response_size) {
|
||||
ASSERT_NE(license_messages_, nullptr);
|
||||
CoreMessageFeatures features =
|
||||
CoreMessageFeatures::DefaultFeatures(license_messages_->api_version());
|
||||
// Serializing core message.
|
||||
// This call also sets nonce in core response to match with session nonce.
|
||||
oemcrypto_core_message::serialize::CreateCoreReleaseResponse(
|
||||
features, fuzzed_data.core_request,
|
||||
fuzzed_data.seconds_since_license_received,
|
||||
fuzzed_data.seconds_since_first_decrypt, &serialized_core_message_);
|
||||
|
||||
// Copy serialized core message and encrypted response from data and
|
||||
// calculate signature. Now we will have a valid signature for data
|
||||
// generated by fuzzer.
|
||||
encrypted_response_.assign(serialized_core_message_.begin(),
|
||||
serialized_core_message_.end());
|
||||
encrypted_response_.insert(encrypted_response_.end(), release_response,
|
||||
release_response + release_response_size);
|
||||
session()->key_deriver().ServerSignBuffer(encrypted_response_.data(),
|
||||
encrypted_response_.size(),
|
||||
&response_signature_);
|
||||
}
|
||||
|
||||
OEMCryptoResult ReleaseRoundTrip::LoadResponse(Session* session) {
|
||||
// TODO(vickymin): Write corpus for oemcrypto_load_release_fuzz.
|
||||
// Write corpus for oemcrypto_load_renewal_fuzz. Fuzz script expects
|
||||
// encrypted response from Renewal server as input corpus data.
|
||||
// Data will be signed again explicitly by fuzzer script after mutations.
|
||||
if (ShouldGenerateCorpus()) {
|
||||
const std::string file_name =
|
||||
GetFileName("oemcrypto_load_release_fuzz_seed_corpus");
|
||||
// Corpus for release response fuzzer should be in the format:
|
||||
// OEMCrypto_Release_Response_Fuzz + license_release_response.
|
||||
OEMCrypto_Release_Response_Fuzz release_response_fuzz;
|
||||
release_response_fuzz.core_request = core_request_;
|
||||
release_response_fuzz.seconds_since_license_received =
|
||||
seconds_since_license_received_;
|
||||
release_response_fuzz.seconds_since_first_decrypt =
|
||||
seconds_since_first_decrypt_;
|
||||
AppendToFile(file_name,
|
||||
reinterpret_cast<const char*>(&release_response_fuzz),
|
||||
sizeof(release_response_fuzz));
|
||||
AppendToFile(file_name,
|
||||
reinterpret_cast<const char*>(&encrypted_response_data_),
|
||||
sizeof(encrypted_response_data_));
|
||||
}
|
||||
VerifyEncryptAndSignResponseLengths();
|
||||
return OEMCrypto_LoadRelease(
|
||||
session->session_id(), encrypted_response_.data(),
|
||||
@@ -2309,6 +2369,9 @@ void WriteRequestApiCorpus(size_t signature_length, size_t core_message_length,
|
||||
} else if (std::is_same<CoreRequest,
|
||||
oemcrypto_core_message::ODK_RenewalRequest>::value) {
|
||||
file_name = GetFileName("oemcrypto_renewal_request_fuzz_seed_corpus");
|
||||
} else if (std::is_same<CoreRequest,
|
||||
oemcrypto_core_message::ODK_ReleaseRequest>::value) {
|
||||
file_name = GetFileName("oemcrypto_release_request_fuzz_seed_corpus");
|
||||
} else {
|
||||
LOGE("Invalid CoreRequest type while writing request api corups.");
|
||||
}
|
||||
|
||||
@@ -583,9 +583,9 @@ class RenewalRoundTrip
|
||||
is_release_(false) {}
|
||||
void CreateDefaultResponse() override;
|
||||
void EncryptAndSignResponse() override;
|
||||
void InjectFuzzedResponseData(OEMCrypto_Renewal_Response_Fuzz& fuzzed_data,
|
||||
const uint8_t* renewal_response,
|
||||
size_t renewal_response_size);
|
||||
void InjectFuzzedResponseData(
|
||||
const OEMCrypto_Renewal_Response_Fuzz& fuzzed_data,
|
||||
const uint8_t* renewal_response, size_t renewal_response_size);
|
||||
OEMCryptoResult LoadResponse() override { return LoadResponse(session_); }
|
||||
OEMCryptoResult LoadResponse(Session* session) override;
|
||||
uint64_t renewal_duration_seconds() const {
|
||||
@@ -623,6 +623,9 @@ class ReleaseRoundTrip
|
||||
license_messages_(license_messages) {}
|
||||
void CreateDefaultResponse() override;
|
||||
void EncryptAndSignResponse() override;
|
||||
void InjectFuzzedResponseData(
|
||||
const OEMCrypto_Release_Response_Fuzz& fuzzed_data,
|
||||
const uint8_t* release_response, size_t release_response_size);
|
||||
OEMCryptoResult LoadResponse() override { return LoadResponse(session_); }
|
||||
OEMCryptoResult LoadResponse(Session* session) override;
|
||||
int64_t seconds_since_license_received() const {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#define CDM_OEC_TEST_DATA_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "oemcrypto_types.h"
|
||||
@@ -193,6 +194,206 @@ static const uint8_t kTestRSAPKCS8PrivateKeyInfo2_2048[] = {
|
||||
0x72, 0x2c, 0xf7, 0xc1, 0x22, 0x36, 0xd9, 0x18, 0x56, 0xfe, 0x39, 0x28,
|
||||
0x33, 0xe0, 0xdb, 0x03};
|
||||
|
||||
// Counterpart of kTestRSAPKCS8PrivateKeyInfo2_2048[]
|
||||
static const uint8_t kTestOEMPublicCertInfo2[] = {
|
||||
0x30, 0x82, 0x09, 0x2d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
|
||||
0x01, 0x07, 0x02, 0xa0, 0x82, 0x09, 0x1e, 0x30, 0x82, 0x09, 0x1a, 0x02,
|
||||
0x01, 0x01, 0x31, 0x00, 0x30, 0x0f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
|
||||
0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x02, 0x04, 0x00, 0xa0, 0x82, 0x08,
|
||||
0xfe, 0x30, 0x82, 0x03, 0x71, 0x30, 0x82, 0x02, 0x59, 0xa0, 0x03, 0x02,
|
||||
0x01, 0x02, 0x02, 0x11, 0x00, 0xc2, 0x8d, 0x20, 0x22, 0x82, 0x8b, 0x9e,
|
||||
0x63, 0x9d, 0x15, 0x89, 0x2c, 0xa9, 0x8f, 0xd9, 0x5d, 0x30, 0x0d, 0x06,
|
||||
0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
|
||||
0x30, 0x6b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
|
||||
0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08,
|
||||
0x0c, 0x02, 0x57, 0x41, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
|
||||
0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31,
|
||||
0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f,
|
||||
0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
|
||||
0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31,
|
||||
0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x73, 0x79,
|
||||
0x73, 0x74, 0x65, 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x39, 0x31,
|
||||
0x33, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x31, 0x31, 0x31, 0x31,
|
||||
0x33, 0x32, 0x36, 0x32, 0x32, 0x5a, 0x17, 0x0d, 0x33, 0x38, 0x30, 0x31,
|
||||
0x30, 0x36, 0x31, 0x33, 0x32, 0x36, 0x32, 0x32, 0x5a, 0x30, 0x65, 0x31,
|
||||
0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x09, 0x37, 0x39,
|
||||
0x31, 0x33, 0x2d, 0x6c, 0x65, 0x61, 0x66, 0x31, 0x0b, 0x30, 0x09, 0x06,
|
||||
0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09,
|
||||
0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x02, 0x57, 0x41, 0x31, 0x11, 0x30,
|
||||
0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b,
|
||||
0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04,
|
||||
0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30,
|
||||
0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65,
|
||||
0x76, 0x69, 0x6e, 0x65, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09,
|
||||
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
|
||||
0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01,
|
||||
0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a, 0x40,
|
||||
0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd, 0xde, 0xa7,
|
||||
0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e, 0x56,
|
||||
0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d, 0xb4, 0x4e,
|
||||
0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3, 0x34,
|
||||
0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f, 0xce, 0x31,
|
||||
0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb, 0x3e,
|
||||
0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73, 0x9e, 0x39,
|
||||
0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4, 0xf2,
|
||||
0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13, 0x8b, 0x54,
|
||||
0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda, 0xb3,
|
||||
0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57, 0x54, 0x71,
|
||||
0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03, 0x96,
|
||||
0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06, 0x51, 0x5a,
|
||||
0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b, 0x4c,
|
||||
0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8, 0x12, 0x7f,
|
||||
0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01, 0xca,
|
||||
0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b, 0x3a, 0x77,
|
||||
0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed, 0x27,
|
||||
0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d, 0xdb, 0x9c,
|
||||
0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb, 0x2c,
|
||||
0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x16,
|
||||
0x30, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6,
|
||||
0x79, 0x04, 0x01, 0x01, 0x04, 0x04, 0x02, 0x02, 0x1e, 0xe9, 0x30, 0x0d,
|
||||
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05,
|
||||
0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x88, 0x95, 0xec, 0xcd, 0x8b, 0xa7,
|
||||
0x51, 0xda, 0x74, 0x81, 0xa5, 0x39, 0x62, 0x1a, 0x0e, 0x2e, 0xde, 0x3c,
|
||||
0x37, 0xea, 0xad, 0x7c, 0xee, 0x9b, 0x26, 0x8e, 0xe2, 0xd6, 0x34, 0xcd,
|
||||
0xb7, 0x70, 0xba, 0xbf, 0xa0, 0xa3, 0xfe, 0xb3, 0x4b, 0xbc, 0xf4, 0x1c,
|
||||
0x72, 0x66, 0x81, 0xd5, 0x09, 0x33, 0x78, 0x0c, 0x61, 0x21, 0xa8, 0xf1,
|
||||
0xe2, 0xc9, 0xe2, 0x83, 0xc2, 0x19, 0x02, 0xf2, 0xe8, 0xab, 0x17, 0x36,
|
||||
0x3a, 0x0b, 0x20, 0xaf, 0x0f, 0xae, 0x2e, 0x73, 0x68, 0xac, 0x15, 0xee,
|
||||
0x9c, 0xc0, 0x92, 0x03, 0x7e, 0x95, 0x63, 0xaa, 0xad, 0x15, 0x96, 0x43,
|
||||
0x20, 0x3b, 0xe5, 0x9b, 0x1f, 0xca, 0x02, 0xba, 0xf0, 0x07, 0x76, 0x80,
|
||||
0xd7, 0xa3, 0x1a, 0xeb, 0xc8, 0xdb, 0x03, 0x7b, 0x43, 0x56, 0xe5, 0x96,
|
||||
0x6b, 0x86, 0xfe, 0x08, 0x58, 0x8a, 0x84, 0xbd, 0xe9, 0x47, 0x18, 0xee,
|
||||
0xb2, 0xa8, 0x05, 0x7b, 0xf0, 0xfd, 0xaa, 0xb9, 0x85, 0xcd, 0x7a, 0x0e,
|
||||
0x6b, 0x6c, 0x9f, 0xc6, 0x75, 0xd2, 0x2a, 0xfe, 0x5b, 0xf3, 0xb7, 0x31,
|
||||
0x6c, 0xac, 0xe3, 0x00, 0x9f, 0xe7, 0xdd, 0xe3, 0x81, 0xc1, 0x36, 0xc3,
|
||||
0x1c, 0x5f, 0xdf, 0xf2, 0xc3, 0x5e, 0xfa, 0x55, 0x32, 0xd8, 0x5c, 0xa8,
|
||||
0xe5, 0xcc, 0xb6, 0x4a, 0xe9, 0xe2, 0xcc, 0x38, 0x44, 0x07, 0x46, 0x59,
|
||||
0x34, 0x84, 0x79, 0xf9, 0xee, 0x3c, 0x4b, 0x48, 0x90, 0xab, 0x73, 0xb0,
|
||||
0xa1, 0x92, 0xc3, 0xd6, 0x83, 0x87, 0x81, 0xca, 0x12, 0x81, 0xd6, 0x5d,
|
||||
0xf7, 0x6f, 0x7a, 0x35, 0x5e, 0x4f, 0x02, 0x66, 0x8a, 0x47, 0x88, 0x82,
|
||||
0xab, 0xf0, 0x12, 0x1d, 0xb9, 0x75, 0x3b, 0x7b, 0xa8, 0x36, 0x15, 0xef,
|
||||
0xa8, 0x12, 0x0e, 0x53, 0xb4, 0x83, 0x78, 0x53, 0xc0, 0x52, 0xae, 0xa6,
|
||||
0x0a, 0xa0, 0x53, 0xdc, 0x1c, 0x15, 0x22, 0xdd, 0x17, 0x98, 0x30, 0x82,
|
||||
0x05, 0x85, 0x30, 0x82, 0x03, 0x6d, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
|
||||
0x10, 0x03, 0xb1, 0xf7, 0x58, 0xdf, 0x1d, 0xe3, 0x25, 0x00, 0x0b, 0x10,
|
||||
0x3d, 0xd5, 0xe6, 0xe4, 0x64, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
|
||||
0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x7e, 0x31, 0x0b,
|
||||
0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
|
||||
0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61,
|
||||
0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f,
|
||||
0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c,
|
||||
0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a,
|
||||
0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f,
|
||||
0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76,
|
||||
0x69, 0x6e, 0x65, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x03,
|
||||
0x0c, 0x1a, 0x77, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63,
|
||||
0x6f, 0x6d, 0x2f, 0x6f, 0x65, 0x6d, 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x2d,
|
||||
0x70, 0x72, 0x6f, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x31, 0x31,
|
||||
0x31, 0x38, 0x30, 0x31, 0x31, 0x33, 0x33, 0x35, 0x5a, 0x17, 0x0d, 0x32,
|
||||
0x37, 0x31, 0x31, 0x31, 0x38, 0x30, 0x31, 0x31, 0x33, 0x31, 0x33, 0x5a,
|
||||
0x30, 0x6b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
|
||||
0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08,
|
||||
0x0c, 0x02, 0x57, 0x41, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
|
||||
0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31,
|
||||
0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f,
|
||||
0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
|
||||
0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31,
|
||||
0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x73, 0x79,
|
||||
0x73, 0x74, 0x65, 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x39, 0x31,
|
||||
0x33, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
|
||||
0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f,
|
||||
0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xae, 0xc8,
|
||||
0x71, 0xae, 0x08, 0x0c, 0x06, 0x06, 0x2d, 0x81, 0x7c, 0xa9, 0x8b, 0xb3,
|
||||
0xd6, 0x66, 0xe4, 0xf6, 0x08, 0x5e, 0x5a, 0x75, 0xe8, 0x74, 0x61, 0x7a,
|
||||
0x88, 0xca, 0x85, 0x14, 0x0d, 0x58, 0xa4, 0x09, 0x19, 0x6c, 0x60, 0xc9,
|
||||
0xad, 0x91, 0x1c, 0xbf, 0x04, 0xb3, 0x47, 0x10, 0x63, 0x7f, 0x02, 0x58,
|
||||
0xc2, 0x1e, 0xbd, 0xcc, 0x07, 0x77, 0xaa, 0x7e, 0x14, 0xa8, 0xc2, 0x01,
|
||||
0xcd, 0xe8, 0x46, 0x60, 0x53, 0x6f, 0x2f, 0xda, 0x17, 0x2d, 0x4d, 0x9d,
|
||||
0x0e, 0x5d, 0xb5, 0x50, 0x95, 0xae, 0xab, 0x6e, 0x43, 0xe3, 0xb0, 0x00,
|
||||
0x12, 0xb4, 0x05, 0x82, 0x4a, 0x2b, 0x14, 0x63, 0x0d, 0x1f, 0x06, 0x12,
|
||||
0xaa, 0xe1, 0x9d, 0xe7, 0xba, 0xda, 0xe3, 0xfc, 0x7c, 0x6c, 0x73, 0xae,
|
||||
0x56, 0xf8, 0xab, 0xf7, 0x51, 0x93, 0x31, 0xef, 0x8f, 0xe4, 0xb6, 0x01,
|
||||
0x2c, 0xeb, 0x7b, 0xe4, 0xd8, 0xb3, 0xea, 0x70, 0x37, 0x89, 0x05, 0xa9,
|
||||
0x51, 0x57, 0x72, 0x98, 0x9e, 0xa8, 0x46, 0xdb, 0xeb, 0x7a, 0x38, 0x2b,
|
||||
0x2f, 0xc0, 0x27, 0xb7, 0xc2, 0xe1, 0x9a, 0x17, 0xdf, 0xf5, 0xd6, 0x9c,
|
||||
0xd5, 0x8c, 0xb8, 0x66, 0x42, 0xd5, 0x04, 0x1e, 0x7c, 0x36, 0x4c, 0x1e,
|
||||
0x3e, 0x45, 0x51, 0x4d, 0x41, 0x72, 0x22, 0x53, 0x3d, 0xf4, 0x57, 0x7c,
|
||||
0x6c, 0x33, 0x34, 0x24, 0x45, 0xdf, 0x84, 0x87, 0x4a, 0xa6, 0xcb, 0x7c,
|
||||
0x03, 0xa3, 0xaa, 0x8e, 0x2d, 0x82, 0x01, 0x27, 0x87, 0x74, 0x82, 0x1a,
|
||||
0xbc, 0x0f, 0x76, 0x69, 0xab, 0xe0, 0x4e, 0x70, 0xbe, 0x37, 0xfc, 0xc8,
|
||||
0x2c, 0x91, 0x17, 0x4f, 0xd5, 0x26, 0x3b, 0x7b, 0x90, 0xb5, 0x2d, 0x64,
|
||||
0xba, 0xf7, 0xd2, 0x8a, 0xb4, 0x8f, 0x38, 0x9d, 0x8e, 0xba, 0xe7, 0x5c,
|
||||
0x52, 0xf1, 0x0a, 0xb8, 0xc0, 0x1b, 0xb6, 0xb1, 0x70, 0x7e, 0x47, 0x59,
|
||||
0x94, 0x59, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x10, 0x30,
|
||||
0x82, 0x01, 0x0c, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
|
||||
0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30,
|
||||
0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03,
|
||||
0x02, 0x02, 0x04, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
|
||||
0x04, 0x14, 0x4b, 0xcb, 0xdf, 0xaa, 0x02, 0xde, 0x8d, 0xc3, 0xe7, 0xe5,
|
||||
0x85, 0xdb, 0x2e, 0x8a, 0xbe, 0x75, 0x6b, 0x8a, 0x67, 0x58, 0x30, 0x81,
|
||||
0xb2, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0xaa, 0x30, 0x81, 0xa7,
|
||||
0x80, 0x14, 0x04, 0x94, 0x66, 0xaa, 0xf9, 0x61, 0x89, 0xb6, 0xdb, 0xb5,
|
||||
0xf7, 0x13, 0x38, 0x3d, 0x62, 0x84, 0xb8, 0x18, 0x0a, 0x8f, 0xa1, 0x81,
|
||||
0x83, 0xa4, 0x81, 0x80, 0x30, 0x7e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
|
||||
0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06,
|
||||
0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e,
|
||||
0x67, 0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
|
||||
0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31,
|
||||
0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f,
|
||||
0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
|
||||
0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31,
|
||||
0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1a, 0x77, 0x69,
|
||||
0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f,
|
||||
0x65, 0x6d, 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x70, 0x72, 0x6f, 0x64,
|
||||
0x82, 0x09, 0x00, 0xdf, 0x86, 0x05, 0x31, 0x01, 0xbe, 0x9a, 0x9a, 0x30,
|
||||
0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x04, 0x01,
|
||||
0x01, 0x04, 0x04, 0x02, 0x02, 0x1e, 0xe9, 0x30, 0x0d, 0x06, 0x09, 0x2a,
|
||||
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82,
|
||||
0x02, 0x01, 0x00, 0x61, 0x3f, 0x2f, 0x43, 0xe4, 0xbe, 0x66, 0x34, 0xef,
|
||||
0x92, 0x06, 0xe9, 0x88, 0xba, 0x6a, 0x1d, 0x4f, 0x54, 0x5a, 0x97, 0xb1,
|
||||
0x75, 0xd7, 0x93, 0xf8, 0x45, 0xc6, 0x83, 0x92, 0x36, 0xfd, 0x55, 0xa9,
|
||||
0x21, 0x0b, 0xdc, 0xf6, 0xae, 0x11, 0xdc, 0x62, 0x21, 0x44, 0xbd, 0x04,
|
||||
0x1d, 0x58, 0x2c, 0x03, 0xf8, 0xe4, 0xe2, 0x1e, 0xba, 0xe6, 0xdd, 0x19,
|
||||
0xdd, 0x56, 0xfd, 0xce, 0x06, 0x73, 0x5f, 0x94, 0x1e, 0xb6, 0x03, 0xdb,
|
||||
0x3d, 0x7b, 0xab, 0xab, 0x72, 0x64, 0x7b, 0xde, 0x7d, 0x4d, 0xcf, 0x7e,
|
||||
0xf0, 0x91, 0x29, 0xc1, 0x77, 0x13, 0xc2, 0x6f, 0x80, 0xab, 0x7a, 0xa8,
|
||||
0xce, 0xb0, 0x1c, 0x2a, 0xc5, 0x9c, 0xfb, 0x0b, 0xe5, 0x9f, 0x9c, 0x1b,
|
||||
0xc9, 0x4b, 0x58, 0xdf, 0x96, 0x18, 0xf7, 0x67, 0x67, 0x89, 0xa4, 0xe9,
|
||||
0x14, 0x48, 0xac, 0xfa, 0x9d, 0x86, 0x2a, 0xeb, 0x75, 0x2c, 0x2b, 0xbf,
|
||||
0x63, 0x7d, 0xc7, 0x4e, 0x7e, 0xad, 0x39, 0x2d, 0xb4, 0x7c, 0x07, 0xa5,
|
||||
0x5a, 0xe8, 0x3a, 0xd4, 0xf5, 0x0c, 0x4f, 0xf3, 0xa2, 0x9c, 0x3c, 0x32,
|
||||
0xed, 0x9d, 0x4b, 0x49, 0x05, 0xbc, 0x1f, 0xa0, 0x13, 0xe6, 0xdd, 0x82,
|
||||
0x79, 0x06, 0x31, 0x3b, 0xc6, 0x97, 0xec, 0x8d, 0xaa, 0x4f, 0xef, 0x14,
|
||||
0x3c, 0x21, 0xf6, 0x72, 0xb2, 0x09, 0x42, 0xc7, 0x74, 0xfe, 0xef, 0x70,
|
||||
0xbd, 0xe9, 0x85, 0x41, 0x30, 0x0b, 0xb3, 0x6b, 0x59, 0x0c, 0x0f, 0x11,
|
||||
0x75, 0xd4, 0xbb, 0xb1, 0xdf, 0xb1, 0xdf, 0xb3, 0xfa, 0xb3, 0x3a, 0x43,
|
||||
0x17, 0x7d, 0x8a, 0x82, 0xae, 0xa2, 0x07, 0xf8, 0x83, 0x51, 0xfb, 0x16,
|
||||
0xfb, 0x64, 0xb6, 0x46, 0xda, 0xbe, 0x32, 0x2b, 0xc0, 0xee, 0x78, 0x2a,
|
||||
0x84, 0xa9, 0x54, 0x0a, 0xf9, 0x2d, 0x61, 0x65, 0xde, 0xa5, 0x97, 0x66,
|
||||
0x79, 0x02, 0xf8, 0x97, 0x17, 0xe2, 0xd4, 0x9f, 0x9e, 0xac, 0xcc, 0xae,
|
||||
0x99, 0x9a, 0x03, 0x04, 0xbb, 0x45, 0xfe, 0xb2, 0xf5, 0x80, 0xba, 0xbf,
|
||||
0xdd, 0x24, 0xe5, 0xe6, 0x1e, 0x5d, 0x36, 0xa5, 0x87, 0x0c, 0xdf, 0x60,
|
||||
0x81, 0x6f, 0xb7, 0x5f, 0xb9, 0x1f, 0xca, 0x75, 0x3c, 0x1a, 0x63, 0xb0,
|
||||
0xeb, 0xe6, 0x95, 0x86, 0x0d, 0xae, 0xa6, 0xc9, 0x2a, 0x94, 0xf1, 0xd0,
|
||||
0xbe, 0x75, 0xc8, 0xf8, 0x07, 0xd7, 0x88, 0xff, 0xec, 0xf9, 0xcd, 0x49,
|
||||
0xc6, 0xfe, 0x4d, 0x7f, 0x44, 0x1e, 0xd8, 0xaf, 0xa9, 0x72, 0x27, 0x98,
|
||||
0xe2, 0x5a, 0x08, 0xea, 0x55, 0xd3, 0xb3, 0xea, 0xdc, 0x76, 0x69, 0x51,
|
||||
0x10, 0x01, 0x46, 0x7d, 0x33, 0x94, 0x9c, 0x94, 0xef, 0xfe, 0x76, 0x1c,
|
||||
0xc6, 0xd7, 0x15, 0x53, 0x3e, 0x8d, 0x3d, 0x29, 0x9a, 0x58, 0x6a, 0xf1,
|
||||
0x75, 0x9e, 0xea, 0x1b, 0x4c, 0xf0, 0x47, 0x76, 0xac, 0xc6, 0xa2, 0x32,
|
||||
0x44, 0x40, 0xdf, 0xfe, 0xff, 0x9d, 0xf4, 0xe2, 0xc2, 0xfa, 0xa1, 0x5f,
|
||||
0x2e, 0x66, 0xe9, 0x97, 0xcb, 0x27, 0x26, 0x6e, 0x53, 0xe4, 0xe8, 0x86,
|
||||
0x2c, 0xea, 0xd3, 0x69, 0x6c, 0x61, 0x4f, 0xfe, 0xc1, 0xc9, 0x8b, 0x05,
|
||||
0x92, 0x6f, 0x47, 0x96, 0xce, 0xf0, 0x33, 0xfa, 0x7c, 0x78, 0x24, 0x9b,
|
||||
0xd7, 0x8d, 0x36, 0x56, 0x37, 0x86, 0xbc, 0x72, 0x5a, 0xf9, 0xb9, 0xb0,
|
||||
0x93, 0xf0, 0x81, 0x78, 0x10, 0xf2, 0xb0, 0xc2, 0x79, 0x91, 0x5e, 0xcf,
|
||||
0xbc, 0x8c, 0xf2, 0x32, 0x0f, 0xf7, 0x2d, 0x30, 0xd8, 0x13, 0x77, 0x4f,
|
||||
0x78, 0x9e, 0x40, 0x8d, 0xe6, 0x3a, 0x98, 0xb2, 0xaa, 0x13, 0x4d, 0x25,
|
||||
0x49, 0x34, 0x6c, 0x80, 0x9e, 0x19, 0x03, 0xdb, 0xcd, 0xf5, 0xb1, 0x54,
|
||||
0x74, 0x1b, 0x67, 0x3c, 0x46, 0xac, 0x3e, 0x5d, 0xa2, 0xd9, 0x13, 0x83,
|
||||
0x30, 0xeb, 0x82, 0x3b, 0x06, 0xab, 0x3c, 0x39, 0x7d, 0xd0, 0x68, 0x31,
|
||||
0x00};
|
||||
|
||||
// A 3072 bit RSA key in PKCS#8 PrivateKeyInfo format
|
||||
// Used to verify the functions that manipulate RSA keys.
|
||||
static const uint8_t kTestRSAPKCS8PrivateKeyInfo3_3072[] = {
|
||||
|
||||
@@ -180,7 +180,7 @@ TEST_F(OEMCryptoClientTest, FreeUnallocatedSecureBufferNoFailure) {
|
||||
*/
|
||||
TEST_F(OEMCryptoClientTest, VersionNumber) {
|
||||
const std::string log_message =
|
||||
"OEMCrypto unit tests for API 19.1. Tests last updated 2024-03-25";
|
||||
"OEMCrypto unit tests for API 19.2. Tests last updated 2024-06-24";
|
||||
cout << " " << log_message << "\n";
|
||||
cout << " "
|
||||
<< "These tests are part of Android U."
|
||||
@@ -189,7 +189,7 @@ TEST_F(OEMCryptoClientTest, VersionNumber) {
|
||||
// If any of the following fail, then it is time to update the log message
|
||||
// above.
|
||||
EXPECT_EQ(ODK_MAJOR_VERSION, 19);
|
||||
EXPECT_EQ(ODK_MINOR_VERSION, 1);
|
||||
EXPECT_EQ(ODK_MINOR_VERSION, 2);
|
||||
EXPECT_EQ(kCurrentAPI, static_cast<unsigned>(ODK_MAJOR_VERSION));
|
||||
OEMCrypto_Security_Level level = OEMCrypto_SecurityLevel();
|
||||
EXPECT_GT(level, OEMCrypto_Level_Unknown);
|
||||
|
||||
@@ -544,7 +544,7 @@ TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptZeroSizeSubSample) {
|
||||
ASSERT_NO_FATAL_FAILURE(LoadLicense());
|
||||
ASSERT_NO_FATAL_FAILURE(MakeBuffers());
|
||||
ASSERT_NO_FATAL_FAILURE(EncryptData());
|
||||
ASSERT_NO_FATAL_FAILURE(TestDecryptCENC());
|
||||
ASSERT_NO_FATAL_FAILURE(DecryptCENC());
|
||||
}
|
||||
|
||||
// There are probably no frames this small, but we should handle them anyway.
|
||||
|
||||
@@ -213,7 +213,7 @@ TEST_P(OEMCryptoLicenseTest, LoadKeyNoNonceTwiceAPI16) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||
// A second load, should NOT succeed.
|
||||
ASSERT_EQ(OEMCrypto_ERROR_LICENSE_RELOAD, license_messages_.LoadResponse());
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||
}
|
||||
|
||||
// Verify that a second license may not be loaded in a session.
|
||||
@@ -223,7 +223,7 @@ TEST_P(OEMCryptoLicenseTest, LoadKeyWithNonceTwiceAPI16) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||
// A second load, should NOT succeed.
|
||||
ASSERT_EQ(OEMCrypto_ERROR_LICENSE_RELOAD, license_messages_.LoadResponse());
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||
}
|
||||
|
||||
// This tests load license with an 8k license response.
|
||||
@@ -496,7 +496,7 @@ TEST_P(OEMCryptoLicenseTest, LoadLicenseAgainFailureAPI16) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||
ASSERT_EQ(OEMCrypto_ERROR_LICENSE_RELOAD, license_messages_.LoadResponse());
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoLicenseTest, LoadKeysBadSignatureAPI16) {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "bcc_validator.h"
|
||||
#include "device_info_validator.h"
|
||||
#include "log.h"
|
||||
#include "oec_device_features.h"
|
||||
#include "platform.h"
|
||||
#include "signed_csr_payload_validator.h"
|
||||
#include "test_sleep.h"
|
||||
@@ -786,6 +787,12 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange1_API16) {
|
||||
if (global_features.provisioning_method == OEMCrypto_BootCertificateChain) {
|
||||
GTEST_SKIP() << "Test for non Prov 4.0 devices only.";
|
||||
}
|
||||
// DRM Reprovisioning CDMs have embedded certificates and do not support
|
||||
// key rewrapping.
|
||||
if (global_features.provisioning_method == OEMCrypto_DrmReprovisioning) {
|
||||
GTEST_SKIP() << "Test for non DRM Reprovisioning devices.";
|
||||
}
|
||||
|
||||
Session s;
|
||||
ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_);
|
||||
provisioning_messages.PrepareSession(keybox_);
|
||||
@@ -808,6 +815,11 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange2_API16) {
|
||||
if (global_features.provisioning_method == OEMCrypto_BootCertificateChain) {
|
||||
GTEST_SKIP() << "Test for non Prov 4.0 devices only.";
|
||||
}
|
||||
// DRM Reprovisioning CDMs have embedded certificates and do not support
|
||||
// key rewrapping.
|
||||
if (global_features.provisioning_method == OEMCrypto_DrmReprovisioning) {
|
||||
GTEST_SKIP() << "Test for non DRM Reprovisioning devices.";
|
||||
}
|
||||
Session s;
|
||||
ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_);
|
||||
provisioning_messages.PrepareSession(keybox_);
|
||||
@@ -830,6 +842,11 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange3_API16) {
|
||||
if (global_features.provisioning_method == OEMCrypto_BootCertificateChain) {
|
||||
GTEST_SKIP() << "Test for non Prov 4.0 devices only.";
|
||||
}
|
||||
// DRM Reprovisioning CDMs have embedded certificates and do not support
|
||||
// key rewrapping.
|
||||
if (global_features.provisioning_method == OEMCrypto_DrmReprovisioning) {
|
||||
GTEST_SKIP() << "Test for non DRM Reprovisioning devices.";
|
||||
}
|
||||
Session s;
|
||||
ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_);
|
||||
provisioning_messages.PrepareSession(keybox_);
|
||||
@@ -854,6 +871,11 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange4_API16) {
|
||||
if (global_features.provisioning_method == OEMCrypto_BootCertificateChain) {
|
||||
GTEST_SKIP() << "Test for non Prov 4.0 devices only.";
|
||||
}
|
||||
// DRM Reprovisioning CDMs have embedded certificates and do not support
|
||||
// key rewrapping.
|
||||
if (global_features.provisioning_method == OEMCrypto_DrmReprovisioning) {
|
||||
GTEST_SKIP() << "Test for non DRM Reprovisioning devices.";
|
||||
}
|
||||
Session s;
|
||||
ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_);
|
||||
provisioning_messages.PrepareSession(keybox_);
|
||||
@@ -881,6 +903,11 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange5Prov30_API16) {
|
||||
if (global_features.provisioning_method != OEMCrypto_OEMCertificate) {
|
||||
GTEST_SKIP() << "Test for Prov 3.0 devices only.";
|
||||
}
|
||||
// DRM Reprovisioning CDMs have embedded certificates and do not support
|
||||
// key rewrapping.
|
||||
if (global_features.provisioning_method == OEMCrypto_DrmReprovisioning) {
|
||||
GTEST_SKIP() << "Test for non DRM Reprovisioning devices.";
|
||||
}
|
||||
Session s;
|
||||
ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_);
|
||||
provisioning_messages.PrepareSession(keybox_);
|
||||
@@ -931,6 +958,11 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadNonce_API16) {
|
||||
if (global_features.provisioning_method == OEMCrypto_BootCertificateChain) {
|
||||
GTEST_SKIP() << "Test for non Prov 4.0 devices only.";
|
||||
}
|
||||
// DRM Reprovisioning CDMs have embedded certificates and do not support
|
||||
// key rewrapping.
|
||||
if (global_features.provisioning_method == OEMCrypto_DrmReprovisioning) {
|
||||
GTEST_SKIP() << "Test for non DRM Reprovisioning devices.";
|
||||
}
|
||||
Session s;
|
||||
ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_);
|
||||
provisioning_messages.PrepareSession(keybox_);
|
||||
@@ -950,6 +982,11 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRSAKey) {
|
||||
if (global_features.provisioning_method == OEMCrypto_BootCertificateChain) {
|
||||
GTEST_SKIP() << "Test for non Prov 4.0 devices only.";
|
||||
}
|
||||
// DRM Reprovisioning CDMs have embedded certificates and do not support
|
||||
// key rewrapping.
|
||||
if (global_features.provisioning_method == OEMCrypto_DrmReprovisioning) {
|
||||
GTEST_SKIP() << "Test for non DRM Reprovisioning devices.";
|
||||
}
|
||||
Session s;
|
||||
ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_);
|
||||
provisioning_messages.PrepareSession(keybox_);
|
||||
@@ -1119,6 +1156,10 @@ TEST_F(OEMCryptoLoadsCertificate, TestMultipleRSAKeys) {
|
||||
if (global_features.provisioning_method == OEMCrypto_BootCertificateChain) {
|
||||
GTEST_SKIP() << "Test for non Prov 4.0 devices only.";
|
||||
}
|
||||
// DRM Reprovisioning CDMs have embedded certificates.
|
||||
if (global_features.provisioning_method == OEMCrypto_DrmReprovisioning) {
|
||||
GTEST_SKIP() << "Test for non DRM Reprovisioning devices.";
|
||||
}
|
||||
ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey());
|
||||
Session s1; // Session s1 loads the default rsa key, but doesn't use it
|
||||
// until after s2 uses its key.
|
||||
@@ -1160,6 +1201,10 @@ TEST_F(OEMCryptoLoadsCertificate, TestMaxDRMKeys) {
|
||||
if (global_features.provisioning_method == OEMCrypto_BootCertificateChain) {
|
||||
GTEST_SKIP() << "Test for non Prov 4.0 devices only.";
|
||||
}
|
||||
// DRM Reprovisioning CDMs have embedded certificates.
|
||||
if (global_features.provisioning_method == OEMCrypto_DrmReprovisioning) {
|
||||
GTEST_SKIP() << "Test for non DRM Reprovisioning devices.";
|
||||
}
|
||||
const size_t max_total_keys = GetResourceValue(kMaxTotalDRMPrivateKeys);
|
||||
std::vector<std::unique_ptr<Session>> sessions;
|
||||
std::vector<std::unique_ptr<LicenseRoundTrip>> licenses;
|
||||
|
||||
@@ -44,7 +44,7 @@ class SessionUtil {
|
||||
// Create a new DRM Cert. Only for provisioning 4.0
|
||||
void CreateProv4DRMKey();
|
||||
|
||||
void CreateProv4CastKey(Session *s, bool load_drm_before_prov_req);
|
||||
void CreateProv4CastKey(Session* s, bool load_drm_before_prov_req);
|
||||
|
||||
// Used by prov2.0, prov3.0, and prov 4.0
|
||||
std::vector<uint8_t> encoded_rsa_key_;
|
||||
|
||||
@@ -635,6 +635,9 @@ TEST_P(OEMCryptoLicenseTest, EntitledKeySessionsAPI17) {
|
||||
if (wvoec::global_features.api_version < 17) {
|
||||
GTEST_SKIP() << "Test for versions 17 and up only.";
|
||||
}
|
||||
if (!global_features.supports_cas) {
|
||||
GTEST_SKIP() << "OEMCrypto does not support CAS";
|
||||
}
|
||||
license_messages_.set_license_type(OEMCrypto_EntitlementLicense);
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
|
||||
Reference in New Issue
Block a user