491 lines
21 KiB
C++
491 lines
21 KiB
C++
// Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary
|
|
// source code may only be used and distributed under the Widevine License
|
|
// Agreement.
|
|
|
|
#include "message_dumper.h"
|
|
|
|
#include <iomanip>
|
|
|
|
#include "core_message_deserialize.h"
|
|
#include "license_request.h"
|
|
#include "odk.h"
|
|
#include "odk_message.h"
|
|
#include "odk_serialize.h"
|
|
#include "odk_structs.h"
|
|
#include "odk_structs_priv.h"
|
|
#include "oec_device_features.h"
|
|
#include "test_base.h"
|
|
|
|
using video_widevine::License;
|
|
using video_widevine::LicenseRequest;
|
|
using video_widevine::SignedMessage;
|
|
using video_widevine::SignedProvisioningMessage;
|
|
|
|
namespace wvcdm {
|
|
namespace {
|
|
void DumpHeader(std::ofstream* out, const std::string& type) {
|
|
const ::testing::TestInfo* const test_info =
|
|
::testing::UnitTest::GetInstance()->current_test_info();
|
|
const std::string suite = test_info->test_case_name();
|
|
const std::string name = test_info->name();
|
|
std::string new_test_name = suite + "_" + name;
|
|
// Replace the slashes with underscores so we can use it as a name again.
|
|
std::replace(new_test_name.begin(), new_test_name.end(), '/', '_');
|
|
*out << "\nTEST_F(ODKGolden" << type << "V" << ODK_MAJOR_VERSION << ", "
|
|
<< new_test_name << ") {\n";
|
|
}
|
|
|
|
void DumpHex(std::ofstream* out, const std::string& name,
|
|
const std::string& value) {
|
|
const auto out_flags = out->flags();
|
|
*out << "const uint8_t " << name << "_raw[] = {\n";
|
|
*out << " ";
|
|
for (size_t i = 0; i < value.length(); i++) {
|
|
if ((i > 0) && (i % 10 == 0)) *out << "\n ";
|
|
uint8_t c = value[i];
|
|
*out << "0x" << std::hex << std::setw(2) << std::setfill('0') << int(c)
|
|
<< ", ";
|
|
}
|
|
*out << "\n};\n";
|
|
*out << name << "_ = std::string (\n"
|
|
<< " reinterpret_cast<const char *>(" << name << "_raw), \n"
|
|
<< " sizeof(" << name << "_raw));\n";
|
|
out->flags(out_flags); // Restore flags when we're done.
|
|
}
|
|
|
|
void LogTimer(const char* field, bool set, int64_t time) {
|
|
long long total_seconds = static_cast<long long>(time);
|
|
char sign = ' ';
|
|
if (total_seconds < 0) {
|
|
total_seconds = -total_seconds;
|
|
sign = '-';
|
|
}
|
|
const unsigned long long seconds = total_seconds % 60;
|
|
unsigned long long minutes = total_seconds / 60;
|
|
unsigned long long hours = minutes / 60;
|
|
minutes = minutes % 60;
|
|
unsigned long long days = hours / 24;
|
|
hours = hours % 24;
|
|
if (set) {
|
|
LOGD("%25.25s: %c%llu seconds = %llu day %02llu:%02llu:%02llu HMS", field,
|
|
sign, total_seconds, days, hours, minutes, seconds);
|
|
} else {
|
|
LOGD("%25.25s: %llu seconds (unset)", field, total_seconds);
|
|
}
|
|
}
|
|
|
|
void PrintRequestProto(const char* label,
|
|
const video_widevine::LicenseRequest& request) {
|
|
switch (request.type()) {
|
|
case video_widevine::LicenseRequest_RequestType_NEW:
|
|
LOGD("%s type: NEW", label);
|
|
break;
|
|
case video_widevine::LicenseRequest_RequestType_RENEWAL:
|
|
LOGD("%s type: RENEWAL", label);
|
|
break;
|
|
case video_widevine::LicenseRequest_RequestType_RELEASE:
|
|
LOGD("%s type: RELEASE", label);
|
|
break;
|
|
}
|
|
}
|
|
void PrintLicenseProto(const char* label,
|
|
const video_widevine::License& license) {
|
|
LOGD("%s: can_play = %s, can_persist = %s, can_renew = %s", label,
|
|
license.policy().can_play() ? "true" : "false",
|
|
license.policy().can_persist() ? "true" : "false",
|
|
license.policy().can_renew() ? "true" : "false");
|
|
#define QUOTE_DEFINE(A) #A
|
|
#define QUOTE(A) QUOTE_DEFINE(A)
|
|
#define LOG_TIMER(NAME) \
|
|
LogTimer(QUOTE(NAME), license.policy().has_##NAME(), license.policy().NAME())
|
|
LOG_TIMER(rental_duration_seconds);
|
|
LOG_TIMER(playback_duration_seconds);
|
|
LOG_TIMER(license_duration_seconds);
|
|
LOG_TIMER(renewal_recovery_duration_seconds);
|
|
LOG_TIMER(renewal_delay_seconds);
|
|
LOG_TIMER(renewal_retry_interval_seconds);
|
|
LOGD("renewal_server_url: %s", license.policy().renewal_server_url().c_str());
|
|
LOGD("renew_with_usage: %s",
|
|
license.policy().renew_with_usage() ? "true" : "false");
|
|
LOG_TIMER(play_start_grace_period_seconds);
|
|
}
|
|
} // namespace
|
|
|
|
std::ofstream MessageDumper::license_file;
|
|
std::ofstream MessageDumper::renewal_file;
|
|
std::ofstream MessageDumper::provision_file;
|
|
|
|
void MessageDumper::SetUp() {
|
|
LOGD("Creating golden data files for ODK golden data tests.");
|
|
license_file.open("license_data.cpp");
|
|
if (!license_file) LOGE("Could not open dump file license_data.cpp");
|
|
renewal_file.open("renewal_data.cpp");
|
|
if (!renewal_file) LOGE("Could not open dump file renewal_data.cpp");
|
|
provision_file.open("provision_data.cpp");
|
|
if (!provision_file) LOGE("Could not open dump file provision_data.cpp");
|
|
}
|
|
|
|
void MessageDumper::TearDown() {
|
|
LOGD("Closing golden data files.");
|
|
license_file.close();
|
|
renewal_file.close();
|
|
provision_file.close();
|
|
}
|
|
|
|
void MessageDumper::PrintLicenseRequest(const CdmKeyRequest& request) {
|
|
SignedMessage signed_message;
|
|
ASSERT_TRUE(signed_message.ParseFromString(request.message));
|
|
if (wvoec::global_features.api_version >= wvoec::kCoreMessagesAPI) {
|
|
ASSERT_TRUE(signed_message.has_oemcrypto_core_message());
|
|
const std::string& core_request = signed_message.oemcrypto_core_message();
|
|
oemcrypto_core_message::ODK_LicenseRequest core_request_data;
|
|
ASSERT_TRUE(
|
|
oemcrypto_core_message::deserialize::CoreLicenseRequestFromMessage(
|
|
core_request, &core_request_data));
|
|
|
|
// Print core message information for the license request.
|
|
std::cout << std::endl << "License Request Information:" << std::endl;
|
|
std::cout << " License Request Core Version = "
|
|
<< core_request_data.api_major_version << "."
|
|
<< core_request_data.api_minor_version << std::endl;
|
|
std::cout << " Nonce = " << core_request_data.nonce << std::endl;
|
|
std::cout << " Session ID = " << core_request_data.session_id << std::endl;
|
|
}
|
|
}
|
|
|
|
void MessageDumper::PrintLicenseResponse(const std::string& response) {
|
|
SignedMessage signed_response;
|
|
ASSERT_TRUE(signed_response.ParseFromString(response));
|
|
if (wvoec::global_features.api_version >= wvoec::kCoreMessagesAPI) {
|
|
ASSERT_TRUE(signed_response.has_oemcrypto_core_message());
|
|
video_widevine::License license;
|
|
ASSERT_TRUE(license.ParseFromString(signed_response.msg()));
|
|
|
|
std::string message =
|
|
signed_response.oemcrypto_core_message() + signed_response.msg();
|
|
ODK_Message odk_msg = ODK_Message_Create(
|
|
reinterpret_cast<uint8_t*>(const_cast<char*>(message.c_str())),
|
|
message.length());
|
|
ODK_Message_SetSize(&odk_msg,
|
|
signed_response.oemcrypto_core_message().length());
|
|
ODK_ParsedLicense odk_parsed_license = {};
|
|
ODK_LicenseResponse odk_license_response = {};
|
|
odk_license_response.parsed_license = &odk_parsed_license;
|
|
Unpack_ODK_LicenseResponse(&odk_msg, &odk_license_response);
|
|
ASSERT_EQ(ODK_Message_GetStatus(&odk_msg), MESSAGE_STATUS_OK);
|
|
|
|
// Print core message information for the license response.
|
|
std::cout << std::endl << "License Response Information:" << std::endl;
|
|
std::cout
|
|
<< " License Response Core Version = "
|
|
<< odk_license_response.core_message.nonce_values.api_major_version
|
|
<< "."
|
|
<< odk_license_response.core_message.nonce_values.api_minor_version
|
|
<< std::endl;
|
|
std::cout << " Nonce = "
|
|
<< odk_license_response.core_message.nonce_values.nonce
|
|
<< std::endl;
|
|
std::cout << " Session ID = "
|
|
<< odk_license_response.core_message.nonce_values.session_id
|
|
<< std::endl;
|
|
}
|
|
}
|
|
|
|
void MessageDumper::DumpLicenseRequest(const CdmKeyRequest& request) {
|
|
SignedMessage signed_message;
|
|
DumpHeader(&license_file, "License");
|
|
EXPECT_TRUE(signed_message.ParseFromString(request.message));
|
|
if (wvoec::global_features.api_version >= wvoec::kCoreMessagesAPI) {
|
|
EXPECT_TRUE(signed_message.has_oemcrypto_core_message());
|
|
DumpHex(&license_file, "core_request",
|
|
signed_message.oemcrypto_core_message());
|
|
}
|
|
// Since this is run within a test, we can also verify that the
|
|
// request is valid.
|
|
video_widevine::LicenseRequest license_request;
|
|
EXPECT_TRUE(license_request.ParseFromString(signed_message.msg()));
|
|
// TODO(fredgc): figure out if we can build tests with full protobufs
|
|
// instead of proto lite, so that we can use TextFormat.
|
|
PrintRequestProto("License Request", license_request);
|
|
}
|
|
|
|
void MessageDumper::DumpLicense(const std::string& response) {
|
|
SignedMessage signed_response;
|
|
EXPECT_TRUE(signed_response.ParseFromString(response));
|
|
if (wvoec::global_features.api_version >= wvoec::kCoreMessagesAPI) {
|
|
EXPECT_TRUE(signed_response.has_oemcrypto_core_message());
|
|
DumpHex(&license_file, "core_response",
|
|
signed_response.oemcrypto_core_message());
|
|
}
|
|
|
|
video_widevine::License license;
|
|
EXPECT_TRUE(license.ParseFromString(signed_response.msg()));
|
|
PrintLicenseProto("License", license);
|
|
DumpHex(&license_file, "serialized_license", signed_response.msg());
|
|
|
|
std::string message =
|
|
signed_response.oemcrypto_core_message() + signed_response.msg();
|
|
if (wvoec::global_features.api_version >= wvoec::kCoreMessagesAPI) {
|
|
ODK_Message odk_msg = ODK_Message_Create(
|
|
reinterpret_cast<uint8_t*>(const_cast<char*>(message.c_str())),
|
|
message.length());
|
|
ODK_Message_SetSize(&odk_msg,
|
|
signed_response.oemcrypto_core_message().length());
|
|
ODK_ParsedLicense odk_parsed_license = {};
|
|
ODK_LicenseResponse odk_license_response = {};
|
|
odk_license_response.parsed_license = &odk_parsed_license;
|
|
Unpack_ODK_LicenseResponse(&odk_msg, &odk_license_response);
|
|
EXPECT_EQ(ODK_Message_GetStatus(&odk_msg), MESSAGE_STATUS_OK);
|
|
// Valid hash is only needed for v16 messages.
|
|
std::string hash(ODK_SHA256_HASH_SIZE, ' ');
|
|
DumpHex(&license_file, "core_request_sha256", hash);
|
|
license_file << " nonce_required_ = "
|
|
<< (odk_parsed_license.nonce_required ? "true" : "false")
|
|
<< ";\n";
|
|
}
|
|
license_file << " RunTest();\n";
|
|
license_file << "}\n\n";
|
|
}
|
|
|
|
void MessageDumper::DumpRenewalRequest(const CdmKeyRequest& request) {
|
|
DumpHeader(&renewal_file, "Renewal");
|
|
SignedMessage signed_message;
|
|
EXPECT_TRUE(signed_message.ParseFromString(request.message));
|
|
if (wvoec::global_features.api_version >= wvoec::kCoreMessagesAPI) {
|
|
EXPECT_TRUE(signed_message.has_oemcrypto_core_message());
|
|
DumpHex(&renewal_file, "core_request",
|
|
signed_message.oemcrypto_core_message());
|
|
}
|
|
video_widevine::LicenseRequest renewal_request;
|
|
EXPECT_TRUE(renewal_request.ParseFromString(signed_message.msg()));
|
|
PrintRequestProto("Renewal Request", renewal_request);
|
|
}
|
|
|
|
void MessageDumper::DumpRenewal(const std::string& response) {
|
|
SignedMessage signed_response;
|
|
EXPECT_TRUE(signed_response.ParseFromString(response))
|
|
<< "Response = " << wvutil::b2a_hex(response);
|
|
if (wvoec::global_features.api_version >= wvoec::kCoreMessagesAPI) {
|
|
EXPECT_TRUE(signed_response.has_oemcrypto_core_message());
|
|
DumpHex(&renewal_file, "core_response",
|
|
signed_response.oemcrypto_core_message());
|
|
}
|
|
video_widevine::License renewal;
|
|
EXPECT_TRUE(renewal.ParseFromString(signed_response.msg()));
|
|
PrintLicenseProto("Renewal", renewal);
|
|
DumpHex(&renewal_file, "renewal", signed_response.msg());
|
|
|
|
if (wvoec::global_features.api_version >= wvoec::kCoreMessagesAPI) {
|
|
std::string message =
|
|
signed_response.oemcrypto_core_message() + signed_response.msg();
|
|
ODK_Message odk_msg = ODK_Message_Create(
|
|
reinterpret_cast<uint8_t*>(const_cast<char*>(message.c_str())),
|
|
message.length());
|
|
ODK_Message_SetSize(&odk_msg,
|
|
signed_response.oemcrypto_core_message().length());
|
|
ODK_RenewalResponse odk_renewal_response = {};
|
|
Unpack_ODK_RenewalResponse(&odk_msg, &odk_renewal_response);
|
|
EXPECT_EQ(ODK_Message_GetStatus(&odk_msg), MESSAGE_STATUS_OK);
|
|
renewal_file << " renewal_duration_seconds_ = "
|
|
<< odk_renewal_response.renewal_duration_seconds << ";\n";
|
|
}
|
|
renewal_file << " RunTest();\n";
|
|
renewal_file << "}\n\n";
|
|
}
|
|
|
|
void MessageDumper::PrintProvisioningRequest(
|
|
const CdmProvisioningRequest& request) {
|
|
SignedProvisioningMessage signed_message;
|
|
ASSERT_TRUE(signed_message.ParseFromString(request));
|
|
if (wvoec::global_features.api_version >= wvoec::kCoreMessagesAPI) {
|
|
ASSERT_TRUE(signed_message.has_oemcrypto_core_message());
|
|
const std::string& core_request = signed_message.oemcrypto_core_message();
|
|
oemcrypto_core_message::ODK_ProvisioningRequest core_request_data;
|
|
ASSERT_TRUE(
|
|
oemcrypto_core_message::deserialize::CoreProvisioningRequestFromMessage(
|
|
core_request, &core_request_data));
|
|
|
|
// Print core message information for the provisioning request.
|
|
if (wvoec::global_features.derive_key_method ==
|
|
wvoec::DeviceFeatures::TEST_PROVISION_40) {
|
|
std::cout << std::endl
|
|
<< "Provisioning 4.0 Request Information:" << std::endl;
|
|
std::cout << " Provisioning 4.0 Request Core Version = "
|
|
<< core_request_data.api_major_version << "."
|
|
<< core_request_data.api_minor_version << std::endl;
|
|
} else {
|
|
std::cout << std::endl
|
|
<< "Provisioning Request Information:" << std::endl;
|
|
std::cout << " Provisioning Request Core Version = "
|
|
<< core_request_data.api_major_version << "."
|
|
<< core_request_data.api_minor_version << std::endl;
|
|
}
|
|
std::cout << " Nonce = " << core_request_data.nonce << std::endl;
|
|
std::cout << " Session ID = " << core_request_data.session_id << std::endl;
|
|
}
|
|
}
|
|
|
|
void MessageDumper::PrintProvisioningResponse(
|
|
const CdmProvisioningResponse& response) {
|
|
if (wvoec::global_features.derive_key_method ==
|
|
wvoec::DeviceFeatures::TEST_PROVISION_40) {
|
|
std::cout << " Provisioning 4.0 does not have a response. " << std::endl;
|
|
return;
|
|
}
|
|
SignedProvisioningMessage signed_response;
|
|
if (!signed_response.ParseFromString(response)) {
|
|
// A binary provisioning response is buried within a json structure.
|
|
std::string extracted_message;
|
|
ASSERT_TRUE(CertificateProvisioning::ExtractAndDecodeSignedMessage(
|
|
response, &extracted_message));
|
|
ASSERT_TRUE(signed_response.ParseFromString(extracted_message));
|
|
}
|
|
if (wvoec::global_features.api_version >= wvoec::kCoreMessagesAPI) {
|
|
ASSERT_TRUE(signed_response.has_oemcrypto_core_message());
|
|
std::string message =
|
|
signed_response.oemcrypto_core_message() + signed_response.message();
|
|
ODK_Message odk_msg = ODK_Message_Create(
|
|
reinterpret_cast<uint8_t*>(const_cast<char*>(message.c_str())),
|
|
message.length());
|
|
ODK_Message_SetSize(&odk_msg,
|
|
signed_response.oemcrypto_core_message().length());
|
|
|
|
ODK_ParsedProvisioning odk_parsed_provisioning;
|
|
// For v17 and earlier, we use a special v16/v17 provisioning response type.
|
|
// So need to separate the way we unpack the provisioning response into
|
|
// v16/v17 and v18+.
|
|
if (wvoec::global_features.api_version > 17) {
|
|
ODK_ProvisioningResponse odk_provisioning_response;
|
|
odk_provisioning_response.parsed_provisioning = &odk_parsed_provisioning;
|
|
Unpack_ODK_ProvisioningResponse(&odk_msg, &odk_provisioning_response);
|
|
EXPECT_EQ(ODK_Message_GetStatus(&odk_msg), MESSAGE_STATUS_OK);
|
|
|
|
// Print core message information for the provisioning response.
|
|
std::cout << std::endl
|
|
<< "Provisioning Response Information:" << std::endl;
|
|
std::cout << " Provisioning Response Core Version = "
|
|
<< odk_provisioning_response.core_message.nonce_values
|
|
.api_major_version
|
|
<< "."
|
|
<< odk_provisioning_response.core_message.nonce_values
|
|
.api_minor_version
|
|
<< std::endl;
|
|
std::cout << " Nonce = "
|
|
<< odk_provisioning_response.core_message.nonce_values.nonce
|
|
<< std::endl;
|
|
std::cout
|
|
<< " Session ID = "
|
|
<< odk_provisioning_response.core_message.nonce_values.session_id
|
|
<< std::endl;
|
|
std::cout << " Key Type = "
|
|
<< ((odk_parsed_provisioning.key_type ==
|
|
OEMCrypto_RSA_Private_Key)
|
|
? "OEMCrypto_RSA_Private_Key"
|
|
: "OEMCrypto_ECC_Private_Key")
|
|
<< std::endl;
|
|
} else {
|
|
// ODK_ParsedProvisioning odk_parsed_provisioning;
|
|
ODK_ProvisioningResponseV16 odk_provisioning_response;
|
|
odk_provisioning_response.parsed_provisioning = &odk_parsed_provisioning;
|
|
Unpack_ODK_ProvisioningResponseV16(&odk_msg, &odk_provisioning_response);
|
|
EXPECT_EQ(ODK_Message_GetStatus(&odk_msg), MESSAGE_STATUS_OK);
|
|
|
|
// Print core message information for the provisioning response.
|
|
std::cout << std::endl
|
|
<< "Provisioning Response Information:" << std::endl;
|
|
std::cout << " Provisioning Response Core Version = "
|
|
<< odk_provisioning_response.request.core_message.nonce_values
|
|
.api_major_version
|
|
<< "."
|
|
<< odk_provisioning_response.request.core_message.nonce_values
|
|
.api_minor_version
|
|
<< std::endl;
|
|
std::cout
|
|
<< " Nonce = "
|
|
<< odk_provisioning_response.request.core_message.nonce_values.nonce
|
|
<< std::endl;
|
|
std::cout << " Session ID = "
|
|
<< odk_provisioning_response.request.core_message.nonce_values
|
|
.session_id
|
|
<< std::endl;
|
|
std::cout << " Key Type = "
|
|
<< ((odk_parsed_provisioning.key_type ==
|
|
OEMCrypto_RSA_Private_Key)
|
|
? "OEMCrypto_RSA_Private_Key"
|
|
: "OEMCrypto_ECC_Private_Key")
|
|
<< std::endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
void MessageDumper::DumpProvisioningRequest(
|
|
const CdmProvisioningRequest& request) {
|
|
if (wvoec::global_features.derive_key_method ==
|
|
wvoec::DeviceFeatures::TEST_PROVISION_40) {
|
|
// The ODKGoldenProvision40V19 test will have its own class for now since
|
|
// we are only testing the request.
|
|
DumpHeader(&provision_file, "Provision40");
|
|
} else {
|
|
DumpHeader(&provision_file, "Provision");
|
|
}
|
|
SignedProvisioningMessage signed_message;
|
|
EXPECT_TRUE(signed_message.ParseFromString(request))
|
|
<< "Request = " << wvutil::b2a_hex(request);
|
|
if (wvoec::global_features.api_version >= wvoec::kCoreMessagesAPI) {
|
|
EXPECT_TRUE(signed_message.has_oemcrypto_core_message());
|
|
DumpHex(&provision_file, "core_request",
|
|
signed_message.oemcrypto_core_message());
|
|
}
|
|
}
|
|
|
|
void MessageDumper::DumpProvisioning(const CdmProvisioningResponse& response) {
|
|
if (wvoec::global_features.derive_key_method ==
|
|
wvoec::DeviceFeatures::TEST_PROVISION_40) {
|
|
LOGD(
|
|
"Provisioning 4.0 does not have a v17, v18 or v19 core message in "
|
|
"the "
|
|
"response.");
|
|
provision_file << " RunTest();\n";
|
|
provision_file << "}\n\n";
|
|
} else {
|
|
SignedProvisioningMessage signed_response;
|
|
if (!signed_response.ParseFromString(response)) {
|
|
// A binary provisioning response is buried within a json structure.
|
|
std::string extracted_message;
|
|
EXPECT_TRUE(CertificateProvisioning::ExtractAndDecodeSignedMessage(
|
|
response, &extracted_message));
|
|
EXPECT_TRUE(signed_response.ParseFromString(extracted_message));
|
|
}
|
|
if (wvoec::global_features.api_version >= wvoec::kCoreMessagesAPI) {
|
|
EXPECT_TRUE(signed_response.has_oemcrypto_core_message());
|
|
DumpHex(&provision_file, "core_response",
|
|
signed_response.oemcrypto_core_message());
|
|
}
|
|
DumpHex(&provision_file, "provisioning_response",
|
|
signed_response.message());
|
|
// The choice of ECC or RSA key is decided at the server, based on
|
|
// information in the DCSL. We can only reproduce this by looking
|
|
// at the current response.
|
|
std::string message =
|
|
signed_response.oemcrypto_core_message() + signed_response.message();
|
|
ODK_Message odk_msg = ODK_Message_Create(
|
|
reinterpret_cast<uint8_t*>(const_cast<char*>(message.c_str())),
|
|
message.length());
|
|
ODK_Message_SetSize(&odk_msg,
|
|
signed_response.oemcrypto_core_message().length());
|
|
ODK_ParsedProvisioning odk_parsed_provisioning;
|
|
ODK_ProvisioningResponse odk_provisioning_response;
|
|
odk_provisioning_response.parsed_provisioning = &odk_parsed_provisioning;
|
|
Unpack_ODK_ProvisioningResponse(&odk_msg, &odk_provisioning_response);
|
|
EXPECT_EQ(ODK_Message_GetStatus(&odk_msg), MESSAGE_STATUS_OK);
|
|
provision_file << " device_key_type_ = "
|
|
<< ((odk_parsed_provisioning.key_type ==
|
|
OEMCrypto_RSA_Private_Key)
|
|
? "OEMCrypto_RSA_Private_Key;\n"
|
|
: "OEMCrypto_ECC_Private_Key;\n");
|
|
provision_file << " RunTest();\n";
|
|
provision_file << "}\n\n";
|
|
}
|
|
}
|
|
} // namespace wvcdm
|