Source release 19.3.0
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
// License Agreement.
|
||||
|
||||
/**
|
||||
* @mainpage OEMCrypto API v19.2
|
||||
* @mainpage OEMCrypto API v19.3
|
||||
*
|
||||
* OEMCrypto is the low level library implemented by the OEM to provide key and
|
||||
* content protection, usually in a separate secure memory or process space. The
|
||||
@@ -746,6 +746,7 @@ typedef enum OEMCrypto_SignatureHashAlgorithm {
|
||||
#define OEMCrypto_UseSecondaryKey _oecc152
|
||||
#define OEMCrypto_MarkOfflineSession _oecc153
|
||||
#define OEMCrypto_WrapClearPrivateKey _oecc154
|
||||
#define OEMCrypto_SetSessionUsage _oecc155
|
||||
// clang-format on
|
||||
|
||||
/// @addtogroup initcontrol
|
||||
@@ -1939,6 +1940,33 @@ OEMCryptoResult OEMCrypto_GetOEMKeyToken(OEMCrypto_SESSION key_session,
|
||||
uint8_t* key_token,
|
||||
size_t* key_token_length);
|
||||
|
||||
/**
|
||||
* Sets the session's usage information and scrambling mode, allowing the
|
||||
* descrambler to be set up to decode one or more streams encrypted by the
|
||||
* Conditional Access System (CAS). This method is currently used exclusively by
|
||||
* CAS.
|
||||
*
|
||||
* @param[in] session: session id.
|
||||
* @param[in] intent: session usage information. A constant defined by MediaCaS.
|
||||
* @param[in] mode: scrambling mode. A constant defined by MediaCaS.
|
||||
*
|
||||
* @retval OEMCrypto_SUCCESS on success
|
||||
* @retval OEMCrypto_ERROR_INVALID_SESSION
|
||||
* @retval OEMCrypto_ERROR_INVALID_CONTEXT
|
||||
* @retval OEMCrypto_ERROR_NOT_IMPLEMENTED
|
||||
*
|
||||
* @threading
|
||||
* This is a "Session Function" and may be called simultaneously with session
|
||||
* functions for other sessions but not simultaneously with other functions
|
||||
* for this session. It is as if the CDM holds a write lock for this session,
|
||||
* and a read lock on the OEMCrypto system.
|
||||
*
|
||||
* @version
|
||||
* This method is new in API version 19.
|
||||
*/
|
||||
OEMCryptoResult OEMCrypto_SetSessionUsage(OEMCrypto_SESSION session,
|
||||
uint32_t intent, uint32_t mode);
|
||||
|
||||
/// @}
|
||||
|
||||
/// @addtogroup decryption
|
||||
@@ -2236,10 +2264,20 @@ OEMCryptoResult OEMCrypto_GetKeyHandle(OEMCrypto_SESSION session,
|
||||
* usually be non-zero. This mode allows devices to decrypt FMP4 HLS content,
|
||||
* SAMPLE-AES HLS content, as well as content using the DASH 'cbcs' scheme.
|
||||
*
|
||||
* The skip field of OEMCrypto_CENCEncryptPatternDesc may also be zero. If
|
||||
* the skip field is zero, then patterns are not in use and all crypto blocks
|
||||
* in the protected part of the subsample are encrypted. It is not valid for
|
||||
* the encrypt field to be zero.
|
||||
* The skip field of OEMCrypto_CENCEncryptPatternDesc may be zero. If the skip
|
||||
* field is zero, then patterns are not in use and all crypto blocks in the
|
||||
* protected part of the subsample are encrypted, except for any partial crypto
|
||||
* blocks at the end. The most common pattern with a skip field of zero is
|
||||
* (10,0), but all patterns with a skip field of zero are functionally the same.
|
||||
*
|
||||
* If the skip field of OEMCrypto_CENCEncryptPatternDesc is zero, the encrypt
|
||||
* field may also be zero. This pattern sometimes appears in content,
|
||||
* particularly in audio tracks. This (0,0) pattern should be treated as
|
||||
* equivalent to the pattern (10,0). e.g. All complete crypto blocks should be
|
||||
* decrypted.
|
||||
*
|
||||
* It is not valid for the encrypt field of OEMCrypto_CENCEncryptPatternDesc to
|
||||
* be zero if the skip field is non-zero.
|
||||
*
|
||||
* The length of a crypto block in AES-128 is 16 bytes. In the 'cbcs' scheme,
|
||||
* if the protected part of a subsample has a length that is not a multiple
|
||||
|
||||
@@ -26,9 +26,9 @@ struct CoreMessageFeatures {
|
||||
|
||||
// This is the published version of the ODK Core Message library. The default
|
||||
// behavior is for the server to restrict messages to at most this version
|
||||
// number. The default is 19.2.
|
||||
// number. The default is 19.3.
|
||||
uint32_t maximum_major_version = 19;
|
||||
uint32_t maximum_minor_version = 2;
|
||||
uint32_t maximum_minor_version = 3;
|
||||
|
||||
bool operator==(const CoreMessageFeatures &other) const;
|
||||
bool operator!=(const CoreMessageFeatures &other) const {
|
||||
|
||||
@@ -16,10 +16,10 @@ extern "C" {
|
||||
|
||||
/* The version of this library. */
|
||||
#define ODK_MAJOR_VERSION 19
|
||||
#define ODK_MINOR_VERSION 2
|
||||
#define ODK_MINOR_VERSION 3
|
||||
|
||||
/* ODK Version string. Date changed automatically on each release. */
|
||||
#define ODK_RELEASE_DATE "ODK v19.2 2024-06-11"
|
||||
#define ODK_RELEASE_DATE "ODK v19.3 2024-09-04"
|
||||
|
||||
/* The lowest version number for an ODK message. */
|
||||
#define ODK_FIRST_VERSION 16
|
||||
|
||||
@@ -33,7 +33,7 @@ CoreMessageFeatures CoreMessageFeatures::DefaultFeatures(
|
||||
features.maximum_minor_version = 4; // 18.4
|
||||
break;
|
||||
case 19:
|
||||
features.maximum_minor_version = 2; // 19.2
|
||||
features.maximum_minor_version = 3; // 19.3
|
||||
break;
|
||||
default:
|
||||
features.maximum_minor_version = 0;
|
||||
|
||||
@@ -277,7 +277,7 @@ OEMCryptoResult ODK_InitializeSessionValues(ODK_TimerLimits* timer_limits,
|
||||
nonce_values->api_minor_version = 4;
|
||||
break;
|
||||
case 19:
|
||||
nonce_values->api_minor_version = 2;
|
||||
nonce_values->api_minor_version = 3;
|
||||
break;
|
||||
default:
|
||||
nonce_values->api_minor_version = 0;
|
||||
|
||||
@@ -1275,7 +1275,7 @@ std::vector<VersionParameters> TestCases() {
|
||||
{16, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 16, 5},
|
||||
{17, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 17, 2},
|
||||
{18, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 18, 4},
|
||||
{19, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 19, 2},
|
||||
{19, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 19, 3},
|
||||
// Here are some known good versions. Make extra sure they work.
|
||||
{ODK_MAJOR_VERSION, 16, 3, 16, 3},
|
||||
{ODK_MAJOR_VERSION, 16, 4, 16, 4},
|
||||
@@ -1288,6 +1288,7 @@ std::vector<VersionParameters> TestCases() {
|
||||
{ODK_MAJOR_VERSION, 19, 0, 19, 0},
|
||||
{ODK_MAJOR_VERSION, 19, 1, 19, 1},
|
||||
{ODK_MAJOR_VERSION, 19, 2, 19, 2},
|
||||
{ODK_MAJOR_VERSION, 19, 3, 19, 3},
|
||||
{0, 16, 3, 16, 3},
|
||||
{0, 16, 4, 16, 4},
|
||||
{0, 16, 5, 16, 5},
|
||||
@@ -1298,6 +1299,7 @@ std::vector<VersionParameters> TestCases() {
|
||||
{0, 19, 0, 19, 0},
|
||||
{0, 19, 1, 19, 1},
|
||||
{0, 19, 2, 19, 2},
|
||||
{0, 19, 3, 19, 3},
|
||||
};
|
||||
return test_cases;
|
||||
}
|
||||
|
||||
@@ -434,3 +434,7 @@ OEMCryptoResult _oecc154(const uint8_t* clear_private_key_bytes,
|
||||
|
||||
// OEMCrypto_MarkOfflineSession defined in v19.2
|
||||
OEMCryptoResult _oecc153(OEMCrypto_SESSION session);
|
||||
|
||||
// OEMCrypto_SetSessionUsage defined in v18.7
|
||||
OEMCryptoResult _oecc155(OEMCrypto_SESSION session, uint32_t intent,
|
||||
uint32_t mode);
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "string_conversions.h"
|
||||
#include "wv_factory_extractor.h"
|
||||
|
||||
namespace {
|
||||
// Make and Model for system ID resolution.
|
||||
@@ -24,116 +25,8 @@ 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;
|
||||
@@ -154,17 +47,27 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
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;
|
||||
widevine::ClientInfo client_info;
|
||||
client_info.company_name = kDeviceMake;
|
||||
client_info.arch_name = kDeviceArchitecture;
|
||||
client_info.device_name = kDeviceName;
|
||||
client_info.model_name = kDeviceModel;
|
||||
client_info.product_name = kDeviceProduct;
|
||||
client_info.build_info = kDeviceBuildInfo;
|
||||
|
||||
auto extractor = widevine::WidevineFactoryExtractor::Create(client_info);
|
||||
if (extractor == nullptr) {
|
||||
std::cerr << "Failed to create WidevineFactoryExtractor" << 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;
|
||||
widevine::Status status = extractor->GenerateUploadRequest(bcc_record);
|
||||
if (status != widevine::Status::kSuccess) {
|
||||
std::cerr << "Fail to generate BCC record: " << status << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!OutputBccRecord(bcc_path, bcc_record)) {
|
||||
std::cerr << "Failed to output BCC record" << std::endl;
|
||||
return 1;
|
||||
|
||||
@@ -26,6 +26,8 @@ format below:
|
||||
+-----------------------+----------------------+--------------------------+
|
||||
| Private Key |
|
||||
+-----------------------+
|
||||
| (DER-encoded PKCS#8) |
|
||||
+-----------------------+
|
||||
|
||||
|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.
|
||||
|
||||
@@ -17,7 +17,6 @@ void advance_dest_buffer(OEMCrypto_DestBufferDesc* dest_buffer, size_t bytes) {
|
||||
switch (dest_buffer->type) {
|
||||
case OEMCrypto_BufferType_Clear:
|
||||
dest_buffer->buffer.clear.clear_buffer += bytes;
|
||||
dest_buffer->buffer.clear.clear_buffer_length -= bytes;
|
||||
break;
|
||||
|
||||
case OEMCrypto_BufferType_Secure:
|
||||
@@ -99,6 +98,11 @@ OEMCryptoResult DecryptFallbackChain::DecryptSample(
|
||||
const size_t length =
|
||||
subsample.num_bytes_clear + subsample.num_bytes_encrypted;
|
||||
fake_sample.buffers.input_data_length = length;
|
||||
if (fake_sample.buffers.output_descriptor.type ==
|
||||
OEMCrypto_BufferType_Clear) {
|
||||
fake_sample.buffers.output_descriptor.buffer.clear.clear_buffer_length =
|
||||
length;
|
||||
}
|
||||
fake_sample.subsamples = &subsample;
|
||||
fake_sample.subsamples_length = 1;
|
||||
|
||||
@@ -144,6 +148,11 @@ OEMCryptoResult DecryptFallbackChain::DecryptSubsample(
|
||||
|
||||
if (subsample.num_bytes_clear > 0) {
|
||||
fake_sample.buffers.input_data_length = subsample.num_bytes_clear;
|
||||
if (fake_sample.buffers.output_descriptor.type ==
|
||||
OEMCrypto_BufferType_Clear) {
|
||||
fake_sample.buffers.output_descriptor.buffer.clear.clear_buffer_length =
|
||||
subsample.num_bytes_clear;
|
||||
}
|
||||
fake_subsample.num_bytes_clear = subsample.num_bytes_clear;
|
||||
fake_subsample.num_bytes_encrypted = 0;
|
||||
fake_subsample.block_offset = 0;
|
||||
@@ -167,6 +176,11 @@ OEMCryptoResult DecryptFallbackChain::DecryptSubsample(
|
||||
|
||||
if (subsample.num_bytes_encrypted > 0) {
|
||||
fake_sample.buffers.input_data_length = subsample.num_bytes_encrypted;
|
||||
if (fake_sample.buffers.output_descriptor.type ==
|
||||
OEMCrypto_BufferType_Clear) {
|
||||
fake_sample.buffers.output_descriptor.buffer.clear.clear_buffer_length =
|
||||
subsample.num_bytes_encrypted;
|
||||
}
|
||||
fake_subsample.num_bytes_clear = 0;
|
||||
fake_subsample.num_bytes_encrypted = subsample.num_bytes_encrypted;
|
||||
fake_subsample.block_offset = subsample.block_offset;
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "log.h"
|
||||
#include "oec_test_data.h"
|
||||
#include "string_conversions.h"
|
||||
#include "test_sleep.h"
|
||||
|
||||
namespace wvoec {
|
||||
@@ -68,6 +70,12 @@ void DeviceFeatures::Initialize() {
|
||||
provisioning_method == OEMCrypto_BootCertificateChain ||
|
||||
provisioning_method == OEMCrypto_DrmReprovisioning;
|
||||
printf("loads_certificate = %s.\n", loads_certificate ? "true" : "false");
|
||||
if (rsa_test_key().empty()) {
|
||||
set_rsa_test_key(
|
||||
std::vector<uint8_t>(kTestRSAPKCS8PrivateKeyInfo2_2048,
|
||||
kTestRSAPKCS8PrivateKeyInfo2_2048 +
|
||||
sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048)));
|
||||
}
|
||||
generic_crypto =
|
||||
(OEMCrypto_ERROR_NOT_IMPLEMENTED !=
|
||||
OEMCrypto_Generic_Encrypt(buffer, 0, buffer, 0, iv,
|
||||
@@ -129,6 +137,9 @@ void DeviceFeatures::Initialize() {
|
||||
case LOAD_TEST_RSA_KEY:
|
||||
printf("LOAD_TEST_RSA_KEY: Call LoadTestRSAKey before deriving keys.\n");
|
||||
break;
|
||||
case PRELOADED_RSA_KEY:
|
||||
printf("PRELOADED_RSA_KEY: Device has test RSA key baked in.\n");
|
||||
break;
|
||||
case TEST_PROVISION_30:
|
||||
printf("TEST_PROVISION_30: Device provisioned with OEM Cert.\n");
|
||||
break;
|
||||
@@ -153,9 +164,10 @@ void DeviceFeatures::PickDerivedKey() {
|
||||
return;
|
||||
case OEMCrypto_DrmCertificate:
|
||||
case OEMCrypto_DrmReprovisioning:
|
||||
if (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestRSAKey()) {
|
||||
derive_key_method = LOAD_TEST_RSA_KEY;
|
||||
}
|
||||
derive_key_method =
|
||||
(OEMCrypto_ERROR_NOT_IMPLEMENTED == OEMCrypto_LoadTestRSAKey())
|
||||
? PRELOADED_RSA_KEY
|
||||
: LOAD_TEST_RSA_KEY;
|
||||
return;
|
||||
case OEMCrypto_Keybox:
|
||||
if (OEMCrypto_ERROR_NOT_IMPLEMENTED !=
|
||||
|
||||
@@ -38,6 +38,7 @@ class DeviceFeatures {
|
||||
LOAD_TEST_RSA_KEY, // Call LoadTestRSAKey before deriving keys.
|
||||
TEST_PROVISION_30, // Device has OEM Certificate installed.
|
||||
TEST_PROVISION_40, // Device has Boot Certificate Chain installed.
|
||||
PRELOADED_RSA_KEY, // Device has test RSA key baked in.
|
||||
};
|
||||
|
||||
enum DeriveMethod derive_key_method;
|
||||
@@ -65,6 +66,16 @@ class DeviceFeatures {
|
||||
// Get a list of output types that should be tested.
|
||||
const std::vector<OutputType>& GetOutputTypes();
|
||||
|
||||
// If the device has a baked in cert, then this is the public key that should
|
||||
// be used for testing.
|
||||
const std::vector<uint8_t>& rsa_test_key() const { return rsa_test_key_; };
|
||||
void set_rsa_test_key(const std::vector<uint8_t>& rsa_test_key) {
|
||||
rsa_test_key_ = rsa_test_key;
|
||||
}
|
||||
void set_rsa_test_key(std::vector<uint8_t>&& rsa_test_key) {
|
||||
rsa_test_key_ = std::move(rsa_test_key);
|
||||
}
|
||||
|
||||
private:
|
||||
// Decide which method should be used to derive session keys, based on
|
||||
// supported featuers.
|
||||
@@ -77,6 +88,7 @@ class DeviceFeatures {
|
||||
// A list of possible output types.
|
||||
std::vector<OutputType> output_types_;
|
||||
bool initialized_ = false;
|
||||
std::vector<uint8_t> rsa_test_key_;
|
||||
};
|
||||
|
||||
// There is one global set of features for the version of OEMCrypto being
|
||||
|
||||
@@ -582,7 +582,7 @@ void ProvisioningRoundTrip::VerifyLoadFailed() {
|
||||
}
|
||||
|
||||
void Provisioning40RoundTrip::PrepareSession(bool is_oem_key) {
|
||||
const size_t buffer_size = 5000; // Make sure it is large enough.
|
||||
const size_t buffer_size = 10240; // Make sure it is large enough.
|
||||
std::vector<uint8_t> public_key(buffer_size);
|
||||
size_t public_key_size = buffer_size;
|
||||
std::vector<uint8_t> public_key_signature(buffer_size);
|
||||
@@ -644,7 +644,7 @@ OEMCryptoResult Provisioning40RoundTrip::LoadDRMCertResponse() {
|
||||
}
|
||||
|
||||
void Provisioning40CastRoundTrip::PrepareSession() {
|
||||
const size_t buffer_size = 5000; // Make sure it is large enough.
|
||||
const size_t buffer_size = 10240; // Make sure it is large enough.
|
||||
std::vector<uint8_t> public_key(buffer_size);
|
||||
size_t public_key_size = buffer_size;
|
||||
std::vector<uint8_t> public_key_signature(buffer_size);
|
||||
@@ -2041,10 +2041,9 @@ void Session::LoadOEMCert(bool verify_cert) {
|
||||
|
||||
void Session::SetTestRsaPublicKey() {
|
||||
public_ec_.reset();
|
||||
public_rsa_ = util::RsaPublicKey::LoadPrivateKeyInfo(
|
||||
kTestRSAPKCS8PrivateKeyInfo2_2048,
|
||||
sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048));
|
||||
ASSERT_TRUE(public_rsa_) << "Could not parse test RSA public key #2";
|
||||
public_rsa_ =
|
||||
util::RsaPublicKey::LoadPrivateKeyInfo(global_features.rsa_test_key());
|
||||
ASSERT_TRUE(public_rsa_) << "Could not parse test RSA public key";
|
||||
}
|
||||
|
||||
void Session::SetPublicKeyFromPrivateKeyInfo(OEMCrypto_PrivateKeyType key_type,
|
||||
|
||||
@@ -2,17 +2,79 @@
|
||||
// source code may only be used and distributed under the Widevine
|
||||
// License Agreement.
|
||||
//
|
||||
|
||||
#include "oemcrypto_basic_test.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <ostream>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <jsmn.h>
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "clock.h"
|
||||
#include "jsmn.h"
|
||||
#include "log.h"
|
||||
#include "oemcrypto_corpus_generator_helper.h"
|
||||
#include "oemcrypto_resource_test.h"
|
||||
#include "test_sleep.h"
|
||||
|
||||
void PrintTo(const jsmntype_t& type, std::ostream* out) {
|
||||
switch (type) {
|
||||
case JSMN_UNDEFINED:
|
||||
*out << "Undefined";
|
||||
return;
|
||||
case JSMN_OBJECT:
|
||||
*out << "Object";
|
||||
return;
|
||||
case JSMN_ARRAY:
|
||||
*out << "Array";
|
||||
return;
|
||||
case JSMN_STRING:
|
||||
*out << "String";
|
||||
return;
|
||||
case JSMN_PRIMITIVE:
|
||||
*out << "Primitive";
|
||||
return;
|
||||
}
|
||||
*out << "Unknown(" << static_cast<int>(type) << ')';
|
||||
}
|
||||
|
||||
namespace wvoec {
|
||||
namespace {
|
||||
// Counts the number of ancestor tokens of the provided |root_index| token.
|
||||
// The result does not count the root itself.
|
||||
//
|
||||
// JSMN tokens specify the count of immediate ancessor tokens, but
|
||||
// not the total.
|
||||
// - Primitives never have children
|
||||
// - Strings have 0 if they are a value, and 1 if they are the
|
||||
// name of an object member
|
||||
// - Objects have the count of members (each key-value pair is 1,
|
||||
// regardless of the value's children elements)
|
||||
// - Arrays have the count of elements (regardless of the values members)
|
||||
//
|
||||
int32_t JsmnAncestorCount(const std::vector<jsmntok_t>& tokens,
|
||||
int32_t root_index) {
|
||||
if (root_index >= static_cast<int32_t>(tokens.size())) return 0;
|
||||
int32_t count = 0;
|
||||
int32_t iter = root_index;
|
||||
int32_t remainder = 1;
|
||||
while (remainder > 0 && iter < static_cast<int32_t>(tokens.size())) {
|
||||
const int32_t child_count = tokens[iter].size;
|
||||
remainder += child_count;
|
||||
count += child_count;
|
||||
iter++;
|
||||
remainder--;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void OEMCryptoClientTest::SetUp() {
|
||||
::testing::Test::SetUp();
|
||||
wvutil::TestSleep::SyncFakeClock();
|
||||
@@ -180,16 +242,14 @@ TEST_F(OEMCryptoClientTest, FreeUnallocatedSecureBufferNoFailure) {
|
||||
*/
|
||||
TEST_F(OEMCryptoClientTest, VersionNumber) {
|
||||
const std::string log_message =
|
||||
"OEMCrypto unit tests for API 19.2. Tests last updated 2024-06-24";
|
||||
"OEMCrypto unit tests for API 19.3. Tests last updated 2024-09-04";
|
||||
cout << " " << log_message << "\n";
|
||||
cout << " "
|
||||
<< "These tests are part of Android U."
|
||||
<< "\n";
|
||||
cout << " " << "These tests are part of Android V." << "\n";
|
||||
LOGI("%s", log_message.c_str());
|
||||
// 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, 2);
|
||||
EXPECT_EQ(ODK_MINOR_VERSION, 3);
|
||||
EXPECT_EQ(kCurrentAPI, static_cast<unsigned>(ODK_MAJOR_VERSION));
|
||||
OEMCrypto_Security_Level level = OEMCrypto_SecurityLevel();
|
||||
EXPECT_GT(level, OEMCrypto_Level_Unknown);
|
||||
@@ -316,29 +376,154 @@ TEST_F(OEMCryptoClientTest, CheckNullBuildInformationAPI17) {
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies that OEMCrypto_BuildInformation() is behaving as expected
|
||||
// by assigning appropriate values to the build info size.
|
||||
TEST_F(OEMCryptoClientTest, CheckBuildInformation_OutputLengthAPI17) {
|
||||
if (wvoec::global_features.api_version < 17) {
|
||||
GTEST_SKIP() << "Test for versions 17 and up only.";
|
||||
}
|
||||
|
||||
constexpr size_t kZero = 0;
|
||||
constexpr char kNullChar = '\0';
|
||||
|
||||
// Allocating single byte to avoid potential null dereference.
|
||||
std::string build_info(1, kNullChar);
|
||||
size_t build_info_length = 0;
|
||||
|
||||
OEMCryptoResult result =
|
||||
OEMCrypto_BuildInformation(&build_info[0], &build_info_length);
|
||||
|
||||
ASSERT_EQ(result, OEMCrypto_ERROR_SHORT_BUFFER);
|
||||
ASSERT_GT(build_info_length, kZero)
|
||||
<< "Signaling ERROR_SHORT_BUFFER should have assigned a length";
|
||||
|
||||
// Force a ERROR_SHORT_BUFFER using a non-zero value.
|
||||
// Note: It is assumed that vendors will provide more than a single
|
||||
// character of info.
|
||||
const size_t second_attempt_length =
|
||||
(build_info_length >= 2) ? build_info_length / 2 : 1;
|
||||
build_info.assign(second_attempt_length, kNullChar);
|
||||
build_info_length = build_info.size();
|
||||
|
||||
result = OEMCrypto_BuildInformation(&build_info[0], &build_info_length);
|
||||
ASSERT_EQ(result, OEMCrypto_ERROR_SHORT_BUFFER)
|
||||
<< "second_attempt_length = " << second_attempt_length
|
||||
<< ", build_info_length" << build_info_length;
|
||||
// OEM specified build info length should be larger than the
|
||||
// original length if returning ERROR_SHORT_BUFFER.
|
||||
ASSERT_GT(build_info_length, second_attempt_length);
|
||||
|
||||
// Final attempt with a buffer large enough buffer, padding to
|
||||
// ensure the caller truncates.
|
||||
constexpr size_t kBufferPadSize = 42;
|
||||
const size_t expected_length = build_info_length;
|
||||
const size_t final_attempt_length = expected_length + kBufferPadSize;
|
||||
build_info.assign(final_attempt_length, kNullChar);
|
||||
build_info_length = build_info.size();
|
||||
|
||||
result = OEMCrypto_BuildInformation(&build_info[0], &build_info_length);
|
||||
|
||||
ASSERT_EQ(result, OEMCrypto_SUCCESS)
|
||||
<< "final_attempt_length = " << final_attempt_length
|
||||
<< ", expected_length = " << expected_length
|
||||
<< ", build_info_length = " << build_info_length;
|
||||
// Ensure not empty.
|
||||
ASSERT_GT(build_info_length, kZero) << "Build info cannot be empty";
|
||||
// Ensure it was truncated down from the padded length.
|
||||
ASSERT_LT(build_info_length, final_attempt_length)
|
||||
<< "Should have truncated from oversized buffer: expected_length = "
|
||||
<< expected_length;
|
||||
// Ensure the real length is within the size originally specified.
|
||||
// OK if final length is smaller than estimated length.
|
||||
ASSERT_LE(build_info_length, expected_length);
|
||||
}
|
||||
|
||||
// Verifies that OEMCrypto_BuildInformation() is behaving as expected
|
||||
// by checking the resulting contents.
|
||||
// Does not validate whether output if valid JSON for v18.
|
||||
TEST_F(OEMCryptoClientTest, CheckBuildInformation_OutputContentAPI17) {
|
||||
if (wvoec::global_features.api_version < 17) {
|
||||
GTEST_SKIP() << "Test for versions 17 and up only.";
|
||||
}
|
||||
|
||||
constexpr size_t kZero = 0;
|
||||
constexpr char kNullChar = '\0';
|
||||
|
||||
// Allocating single byte to avoid potential null dereference.
|
||||
std::string build_info(1, kNullChar);
|
||||
size_t build_info_length = 0;
|
||||
OEMCryptoResult result =
|
||||
OEMCrypto_BuildInformation(&build_info[0], &build_info_length);
|
||||
ASSERT_EQ(result, OEMCrypto_ERROR_SHORT_BUFFER);
|
||||
ASSERT_GT(build_info_length, kZero)
|
||||
<< "Signaling ERROR_SHORT_BUFFER should have assigned a length";
|
||||
|
||||
// Expect successful acquisition of build information.
|
||||
const size_t expected_length = build_info_length;
|
||||
build_info.assign(expected_length, kNullChar);
|
||||
result = OEMCrypto_BuildInformation(&build_info[0], &build_info_length);
|
||||
ASSERT_EQ(result, OEMCrypto_SUCCESS)
|
||||
<< "expected_length = " << expected_length
|
||||
<< ", build_info_length = " << build_info_length;
|
||||
// Ensure not empty.
|
||||
ASSERT_GT(build_info_length, kZero) << "Build info cannot be empty";
|
||||
// Ensure the real length is within the size originally specified.
|
||||
ASSERT_LE(build_info_length, expected_length)
|
||||
<< "Cannot specify success if buffer was too small";
|
||||
build_info.resize(build_info_length);
|
||||
|
||||
// Ensure there isn't a trailing null byte.
|
||||
ASSERT_NE(build_info.back(), kNullChar)
|
||||
<< "Build info must not contain trailing null byte";
|
||||
|
||||
// Ensure all build info characters are printable, or a limited
|
||||
// set of white space characters (case of JSON build info).
|
||||
const auto is_valid_build_info_white_space = [](const char& ch) -> bool {
|
||||
constexpr char kSpace = ' ';
|
||||
constexpr char kLineFeed = '\n';
|
||||
constexpr char kTab = '\t';
|
||||
return ch == kLineFeed || ch == kTab || ch == kSpace;
|
||||
};
|
||||
const auto is_valid_build_info_char = [&](const char& ch) -> bool {
|
||||
return ::isprint(ch) || is_valid_build_info_white_space(ch);
|
||||
};
|
||||
ASSERT_TRUE(std::all_of(build_info.begin(), build_info.end(),
|
||||
is_valid_build_info_char))
|
||||
<< "Build info is not printable: " << wvutil::b2a_hex(build_info);
|
||||
|
||||
// Ensure build info isn't just white space.
|
||||
ASSERT_FALSE(std::all_of(build_info.begin(), build_info.end(),
|
||||
is_valid_build_info_white_space))
|
||||
<< "Build info is just white space: " << wvutil::b2a_hex(build_info);
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoClientTest, CheckJsonBuildInformationAPI18) {
|
||||
if (wvoec::global_features.api_version < 18) {
|
||||
GTEST_SKIP() << "Test for versions 18 and up only.";
|
||||
}
|
||||
std::string build_info;
|
||||
OEMCryptoResult sts = OEMCrypto_BuildInformation(&build_info[0], nullptr);
|
||||
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, sts);
|
||||
size_t buf_length = 0;
|
||||
constexpr char kNullChar = '\0';
|
||||
constexpr size_t kZero = 0;
|
||||
|
||||
// Step 1: Get Build Info
|
||||
size_t buffer_length = 0;
|
||||
// OEMCrypto must allow |buffer| to be null so long as |buffer_length|
|
||||
// is provided and initially set to zero.
|
||||
sts = OEMCrypto_BuildInformation(nullptr, &buf_length);
|
||||
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
|
||||
build_info.resize(buf_length);
|
||||
const size_t max_final_size = buf_length;
|
||||
sts = OEMCrypto_BuildInformation(&build_info[0], &buf_length);
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
ASSERT_LE(buf_length, max_final_size);
|
||||
build_info.resize(buf_length);
|
||||
OEMCryptoResult result = OEMCrypto_BuildInformation(nullptr, &buffer_length);
|
||||
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, result);
|
||||
ASSERT_GT(buffer_length, kZero);
|
||||
|
||||
std::string build_info(buffer_length, kNullChar);
|
||||
const size_t max_final_size = buffer_length;
|
||||
result = OEMCrypto_BuildInformation(&build_info[0], &buffer_length);
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, result);
|
||||
ASSERT_LE(buffer_length, max_final_size);
|
||||
build_info.resize(buffer_length);
|
||||
|
||||
// Step 2: Parse as JSON
|
||||
jsmn_parser p;
|
||||
jsmn_init(&p);
|
||||
std::vector<jsmntok_t> tokens;
|
||||
int32_t num_tokens =
|
||||
const int32_t num_tokens =
|
||||
jsmn_parse(&p, build_info.c_str(), build_info.size(), nullptr, 0);
|
||||
EXPECT_GT(num_tokens, 0)
|
||||
<< "Failed to parse BuildInformation as JSON, parse returned "
|
||||
@@ -346,45 +531,186 @@ TEST_F(OEMCryptoClientTest, CheckJsonBuildInformationAPI18) {
|
||||
|
||||
tokens.resize(num_tokens);
|
||||
jsmn_init(&p);
|
||||
int32_t jsmn_result = jsmn_parse(&p, build_info.c_str(), build_info.size(),
|
||||
tokens.data(), num_tokens);
|
||||
const int32_t jsmn_result = jsmn_parse(
|
||||
&p, build_info.c_str(), build_info.size(), tokens.data(), num_tokens);
|
||||
EXPECT_GE(jsmn_result, 0)
|
||||
<< "Failed to parse BuildInformation as JSON, parse returned "
|
||||
<< jsmn_result << "for following build info: " << build_info;
|
||||
|
||||
std::map<std::string, jsmntype_t> expected;
|
||||
expected["soc_vendor"] = JSMN_STRING;
|
||||
expected["soc_model"] = JSMN_STRING;
|
||||
expected["ta_ver"] = JSMN_STRING;
|
||||
expected["uses_opk"] = JSMN_PRIMITIVE;
|
||||
expected["tee_os"] = JSMN_STRING;
|
||||
expected["tee_os_ver"] = JSMN_STRING;
|
||||
// Step 3a: Ensure info is a single JSON object.
|
||||
const jsmntok_t& object_token = tokens[0];
|
||||
ASSERT_EQ(object_token.type, JSMN_OBJECT)
|
||||
<< "Build info is not a JSON object: " << build_info;
|
||||
|
||||
// for values in token
|
||||
// build string from start,end
|
||||
// check for existence in map
|
||||
// check if value matches expectation
|
||||
// remove from map
|
||||
for (int32_t i = 0; i < jsmn_result; i++) {
|
||||
jsmntok_t token = tokens[i];
|
||||
std::string key = build_info.substr(token.start, token.end - token.start);
|
||||
if (expected.find(key) != expected.end()) {
|
||||
EXPECT_EQ(expected.find(key)->second, tokens[i + 1].type)
|
||||
<< "Type is incorrect for key " << key;
|
||||
expected.erase(key);
|
||||
// Step 3b: Verify schema of defined fields.
|
||||
|
||||
// Required fields must be present in the build information,
|
||||
// and be of the correct type.
|
||||
const std::map<std::string, jsmntype_t> kRequiredFields = {
|
||||
// SOC manufacturer name
|
||||
{"soc_vendor", JSMN_STRING},
|
||||
// SOC model name
|
||||
{"soc_model", JSMN_STRING},
|
||||
// TA version in string format eg "1.12.3+tag", "2.0"
|
||||
{"ta_ver", JSMN_STRING},
|
||||
// [bool] Whether TA was built with Widevine's OPK
|
||||
{"uses_opk", JSMN_PRIMITIVE},
|
||||
// Trusted OS intended to run the TA, eg "Trusty", "QSEE", "OP-TEE"
|
||||
{"tee_os", JSMN_STRING},
|
||||
// Version of Trusted OS intended to run the TA
|
||||
{"tee_os_ver", JSMN_STRING},
|
||||
// [bool] Whether this is a debug build of the TA
|
||||
// Not forcing behavior until implementations fix
|
||||
// them self
|
||||
// {"is_debug", JSMN_PRIMITIVE},
|
||||
};
|
||||
|
||||
const std::string kSpecialCaseReeKey = "ree";
|
||||
|
||||
// Optional fields may be present in the build information;
|
||||
// if they are, then the must be the correct type.
|
||||
const std::map<std::string, jsmntype_t> kOptionalFields = {
|
||||
// Name of company or entity that provides OEMCrypto.
|
||||
{"implementor", JSMN_STRING},
|
||||
// Git commit hash of the code repository.
|
||||
{"git_commit", JSMN_STRING},
|
||||
// ISO 8601 formatted timestamp of the time the TA was compiled
|
||||
{"build_timestamp", JSMN_STRING},
|
||||
// Whether this was built with FACTORY_MODE_ONLY defined
|
||||
{"is_factory_mode", JSMN_PRIMITIVE},
|
||||
// ... provide information about liboemcrypto.so
|
||||
// Special case, see kOptionalReeFields for details.
|
||||
{kSpecialCaseReeKey, JSMN_OBJECT},
|
||||
// Technically required, but several implementations
|
||||
// do not implement this fields.
|
||||
{"is_debug", JSMN_PRIMITIVE},
|
||||
};
|
||||
|
||||
// A set of the required fields found when examining the
|
||||
// build information, use to verify all fields are present.
|
||||
std::set<std::string> found_required_fields;
|
||||
// Stores the tokens of the "ree" field, if set, used to
|
||||
// validate its content.
|
||||
std::vector<jsmntok_t> ree_tokens;
|
||||
bool has_ree_info = false;
|
||||
|
||||
// Start: first object key token
|
||||
// Condition: key-value pair (2 tokens)
|
||||
// Iter: next key-value pair (2 tokens)
|
||||
for (int32_t i = 1; (i + 1) < jsmn_result; i += 2) {
|
||||
// JSMN objects consist of pairs of key-value pairs (keys are always
|
||||
// JSMN_STRING).
|
||||
const jsmntok_t& key_token = tokens[i];
|
||||
ASSERT_EQ(key_token.type, JSMN_STRING)
|
||||
<< "Bad object key: i = " << i << ", build_info = " << build_info;
|
||||
const jsmntok_t& value_token = tokens[i + 1];
|
||||
|
||||
const std::string key =
|
||||
build_info.substr(key_token.start, key_token.end - key_token.start);
|
||||
if (kRequiredFields.find(key) != kRequiredFields.end()) {
|
||||
ASSERT_EQ(value_token.type, kRequiredFields.at(key))
|
||||
<< "Unexpected required field type: field = " << key
|
||||
<< ", build_info = " << build_info;
|
||||
found_required_fields.insert(key);
|
||||
} else if (kOptionalFields.find(key) != kOptionalFields.end()) {
|
||||
ASSERT_EQ(value_token.type, kOptionalFields.at(key))
|
||||
<< "Unexpected optional field type: field = " << key
|
||||
<< ", build_info = " << build_info;
|
||||
} // Do not validate vendor fields.
|
||||
|
||||
if (key == kSpecialCaseReeKey) {
|
||||
// Store the tokens of the "ree" field for additional validation.
|
||||
const int32_t first_ree_field_index = i + 2;
|
||||
const int32_t ree_token_count = JsmnAncestorCount(tokens, i + 1);
|
||||
const auto first_ree_field_iter = tokens.begin() + first_ree_field_index;
|
||||
ree_tokens.assign(first_ree_field_iter,
|
||||
first_ree_field_iter + ree_token_count);
|
||||
has_ree_info = true;
|
||||
}
|
||||
|
||||
// Skip potential nested tokens.
|
||||
i += JsmnAncestorCount(tokens, i + 1);
|
||||
}
|
||||
|
||||
// if map is not empty, return false
|
||||
if (expected.size() > 0) {
|
||||
std::string missing;
|
||||
for (const auto& e : expected) {
|
||||
missing.append(e.first);
|
||||
missing.append(" ");
|
||||
// Step 3c: Ensure all required fields were found.
|
||||
if (found_required_fields.size() != kRequiredFields.size()) {
|
||||
// Generate a list of all the missing fields.
|
||||
std::string missing_fields;
|
||||
for (const auto& required_field : kRequiredFields) {
|
||||
if (found_required_fields.find(required_field.first) !=
|
||||
found_required_fields.end())
|
||||
continue;
|
||||
if (!missing_fields.empty()) {
|
||||
missing_fields.append(", ");
|
||||
}
|
||||
missing_fields.push_back('"');
|
||||
missing_fields.append(required_field.first);
|
||||
missing_fields.push_back('"');
|
||||
}
|
||||
FAIL() << "JSON does not contain all required keys. Missing keys: ["
|
||||
<< missing << "] in string " << build_info;
|
||||
|
||||
FAIL() << "Build info JSON object does not contain all required keys; "
|
||||
<< "missing_fields = [" << missing_fields
|
||||
<< "], build_info = " << build_info;
|
||||
return;
|
||||
}
|
||||
|
||||
// If no "ree" field tokens, then end here.
|
||||
if (!has_ree_info) return;
|
||||
// Step 4a: Verify "ree" object scheme.
|
||||
ASSERT_FALSE(ree_tokens.empty())
|
||||
<< "REE field was specified, but contents were empty: build_info = "
|
||||
<< build_info;
|
||||
|
||||
// The optional field "ree", if present, must follow the required
|
||||
// format.
|
||||
const std::map<std::string, jsmntype_t> kReeRequiredFields = {
|
||||
// liboemcrypto.so version in string format eg "2.15.0+tag"
|
||||
{"liboemcrypto_ver", JSMN_STRING},
|
||||
// git hash of code that compiled liboemcrypto.so
|
||||
{"git_commit", JSMN_STRING},
|
||||
// ISO 8601 timestamp for when liboemcrypto.so was built
|
||||
{"build_timestamp", JSMN_STRING}};
|
||||
|
||||
found_required_fields.clear();
|
||||
for (int32_t i = 0; (i + 1) < static_cast<int32_t>(ree_tokens.size());
|
||||
i += 2) {
|
||||
const jsmntok_t& key_token = ree_tokens[i];
|
||||
ASSERT_EQ(key_token.type, JSMN_STRING)
|
||||
<< "Bad REE object key: i = " << i << ", build_info = " << build_info;
|
||||
const jsmntok_t& value_token = ree_tokens[i + 1];
|
||||
|
||||
const std::string key =
|
||||
build_info.substr(key_token.start, key_token.end - key_token.start);
|
||||
if (kReeRequiredFields.find(key) != kReeRequiredFields.end()) {
|
||||
ASSERT_EQ(value_token.type, kReeRequiredFields.at(key))
|
||||
<< "Unexpected optional REE field type: ree_field = " << key
|
||||
<< ", build_info = " << build_info;
|
||||
found_required_fields.insert(key);
|
||||
} // Do not validate vendor fields.
|
||||
|
||||
// Skip potential nested tokens.
|
||||
i += JsmnAncestorCount(ree_tokens, i + 1);
|
||||
}
|
||||
|
||||
// Step 4b: Ensure all required fields of the "ree" object were found.
|
||||
if (found_required_fields.size() == kReeRequiredFields.size()) return;
|
||||
// Generate a list of all the missing REE fields.
|
||||
std::string missing_ree_fields;
|
||||
for (const auto& required_field : kReeRequiredFields) {
|
||||
if (found_required_fields.find(required_field.first) !=
|
||||
found_required_fields.end())
|
||||
continue;
|
||||
if (!missing_ree_fields.empty()) {
|
||||
missing_ree_fields.append(", ");
|
||||
}
|
||||
missing_ree_fields.push_back('"');
|
||||
missing_ree_fields.append(required_field.first);
|
||||
missing_ree_fields.push_back('"');
|
||||
}
|
||||
|
||||
FAIL() << "REE info JSON object does not contain all required keys; "
|
||||
<< "missing_ree_fields = [" << missing_ree_fields
|
||||
<< "], build_info = " << build_info;
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoClientTest, CheckMaxNumberOfSessionsAPI10) {
|
||||
|
||||
@@ -121,38 +121,6 @@ TEST_P(OEMCryptoLicenseTest, RejectCensAPI16) {
|
||||
EXPECT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, sts);
|
||||
}
|
||||
|
||||
// 'cbc1' mode is no longer supported in v16
|
||||
TEST_P(OEMCryptoLicenseTest, RejectCbc1API16) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||
|
||||
vector<uint8_t> key_handle;
|
||||
OEMCryptoResult sts;
|
||||
sts = GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[0].key_id,
|
||||
session_.license().keys[0].key_id_length,
|
||||
OEMCrypto_CipherMode_CBCS, key_handle);
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
|
||||
vector<uint8_t> in_buffer(256);
|
||||
vector<uint8_t> out_buffer(in_buffer.size());
|
||||
OEMCrypto_SampleDescription sample_description;
|
||||
OEMCrypto_SubSampleDescription subsample_description;
|
||||
|
||||
GenerateSimpleSampleDescription(in_buffer, out_buffer, &sample_description,
|
||||
&subsample_description);
|
||||
|
||||
// Create a zero pattern to indicate this is 'cbc1'
|
||||
OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0};
|
||||
|
||||
// Try to decrypt the data
|
||||
sts = OEMCrypto_DecryptCENC(key_handle.data(), key_handle.size(),
|
||||
&sample_description, 1, &pattern);
|
||||
EXPECT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, sts);
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoLicenseTest, RejectCbcsWithBlockOffset) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
|
||||
@@ -70,6 +70,9 @@ void SessionUtil::EnsureTestROT() {
|
||||
case DeviceFeatures::TEST_PROVISION_30:
|
||||
// Can use oem certificate to install test rsa key.
|
||||
break;
|
||||
case DeviceFeatures::PRELOADED_RSA_KEY:
|
||||
// There is already a key.
|
||||
break;
|
||||
case wvoec::DeviceFeatures::TEST_PROVISION_40:
|
||||
// OEM certificate is retrieved from the server.
|
||||
break;
|
||||
|
||||
@@ -96,6 +96,9 @@ TEST_F(OEMCryptoSessionTests, License_IncrementCounterAPI18) {
|
||||
if (wvoec::global_features.api_version < 18) {
|
||||
GTEST_SKIP() << "Test for versions 18 and up only.";
|
||||
}
|
||||
if (OEMCrypto_SecurityLevel() == OEMCrypto_Level3) {
|
||||
GTEST_SKIP() << "L3 does not support license counter.";
|
||||
}
|
||||
Session s;
|
||||
s.open();
|
||||
LicenseRoundTrip license_messages(&s);
|
||||
@@ -141,6 +144,9 @@ TEST_F(OEMCryptoSessionTests, MasterGeneration_IncrementCounterAPI18) {
|
||||
GTEST_SKIP() << "Usage table not supported, so master generation number "
|
||||
"does not need to be checked.";
|
||||
}
|
||||
if (OEMCrypto_SecurityLevel() == OEMCrypto_Level3) {
|
||||
GTEST_SKIP() << "L3 does not support license counter.";
|
||||
}
|
||||
Session s1;
|
||||
s1.open();
|
||||
LicenseRoundTrip license_messages(&s1);
|
||||
|
||||
@@ -7,12 +7,15 @@
|
||||
#ifndef WVOEC_UTIL_BCC_VALIDATOR_H_
|
||||
#define WVOEC_UTIL_BCC_VALIDATOR_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cbor_validator.h"
|
||||
#include "cppbor.h"
|
||||
#include "wv_class_utils.h"
|
||||
|
||||
namespace wvoec {
|
||||
namespace util {
|
||||
@@ -45,10 +48,10 @@ struct BccPublicKeyInfo {
|
||||
// Google Dice Profile: go/dice-profile
|
||||
class BccValidator : public CborValidator {
|
||||
public:
|
||||
explicit BccValidator() {}
|
||||
BccValidator() = default;
|
||||
virtual ~BccValidator() override = default;
|
||||
BccValidator(const BccValidator&) = delete;
|
||||
BccValidator& operator=(const BccValidator&) = delete;
|
||||
WVCDM_DISALLOW_COPY_AND_MOVE(BccValidator);
|
||||
|
||||
// Verifies the Cbor struct of a client generated root of trust. This message
|
||||
// is part of an attestation model conforming to the Google Open Dice Profile.
|
||||
// This message is received from a client device to attest it is a valid
|
||||
@@ -75,7 +78,7 @@ class BccValidator : public CborValidator {
|
||||
const std::vector<uint8_t>& signature);
|
||||
// Used to generate formatted message.
|
||||
std::stringstream msg_ss_;
|
||||
};
|
||||
}; // class BccValidator
|
||||
} // namespace util
|
||||
} // namespace wvoec
|
||||
#endif // WVOEC_UTIL_BCC_VALIDATOR_H_
|
||||
|
||||
@@ -7,11 +7,15 @@
|
||||
#ifndef WVOEC_UTIL_CBOR_VALIDATOR_H_
|
||||
#define WVOEC_UTIL_CBOR_VALIDATOR_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "cppbor.h"
|
||||
#include "cppbor_parse.h"
|
||||
#include "wv_class_utils.h"
|
||||
|
||||
namespace wvoec {
|
||||
namespace util {
|
||||
@@ -33,10 +37,9 @@ std::string CborMessageStatusToString(CborMessageStatus status);
|
||||
|
||||
class CborValidator {
|
||||
public:
|
||||
explicit CborValidator() {}
|
||||
CborValidator() = default;
|
||||
WVCDM_DISALLOW_COPY_AND_MOVE(CborValidator);
|
||||
virtual ~CborValidator() = default;
|
||||
CborValidator(const CborValidator&) = delete;
|
||||
CborValidator& operator=(const CborValidator&) = delete;
|
||||
|
||||
// Decodes |cbor| and sets |message_status_|.
|
||||
virtual CborMessageStatus Parse(const std::vector<uint8_t>& cbor);
|
||||
@@ -80,7 +83,7 @@ class CborValidator {
|
||||
// Internal status of parsing and validating.
|
||||
cppbor::ParseResult parse_result_ = {};
|
||||
std::vector<std::pair<CborMessageStatus, std::string>> validate_messages_;
|
||||
};
|
||||
}; // class CborValidator
|
||||
} // namespace util
|
||||
} // namespace wvoec
|
||||
#endif // WVOEC_UTIL_CBOR_VALIDATOR_H_
|
||||
|
||||
@@ -7,18 +7,22 @@
|
||||
#ifndef WVOEC_UTIL_CMAC_H_
|
||||
#define WVOEC_UTIL_CMAC_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/cmac.h>
|
||||
|
||||
#include "wv_class_utils.h"
|
||||
|
||||
namespace wvoec {
|
||||
namespace util {
|
||||
class Cmac {
|
||||
public:
|
||||
WVCDM_DISALLOW_COPY_AND_MOVE(Cmac);
|
||||
|
||||
// Creates an AES-128-CMAC or an AES-256-CMAC depending on |key_size|.
|
||||
// Returns an empty pointer if the key size is not valid.
|
||||
static std::unique_ptr<Cmac> Create(const uint8_t* key, size_t key_size);
|
||||
@@ -48,14 +52,14 @@ class Cmac {
|
||||
~Cmac();
|
||||
|
||||
private:
|
||||
Cmac() {}
|
||||
Cmac() = default;
|
||||
|
||||
// Assumes |key_size| is a valid AES-128 or AES-256 key.
|
||||
bool Init(const uint8_t* key, size_t key_size);
|
||||
|
||||
CMAC_CTX* ctx_ = nullptr;
|
||||
bool ready_ = false;
|
||||
};
|
||||
}; // class Cmac
|
||||
} // namespace util
|
||||
} // namespace wvoec
|
||||
#endif // WVOEC_UTIL_CMAC_H_
|
||||
|
||||
@@ -7,12 +7,15 @@
|
||||
#ifndef WVOEC_UTIL_DEVICE_INFO_VALIDATOR_H_
|
||||
#define WVOEC_UTIL_DEVICE_INFO_VALIDATOR_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cbor_validator.h"
|
||||
#include "cppbor.h"
|
||||
#include "wv_class_utils.h"
|
||||
|
||||
namespace wvoec {
|
||||
namespace util {
|
||||
@@ -21,12 +24,13 @@ namespace util {
|
||||
// https://source.corp.google.com/h/googleplex-android/platform/superproject/main/+/main:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/DeviceInfoV3.cddl
|
||||
class DeviceInfoValidator : public CborValidator {
|
||||
public:
|
||||
DeviceInfoValidator() = delete;
|
||||
WVCDM_DISALLOW_COPY_AND_MOVE(DeviceInfoValidator);
|
||||
|
||||
explicit DeviceInfoValidator(int version_number)
|
||||
: version_number_(version_number) {}
|
||||
DeviceInfoValidator() = delete;
|
||||
|
||||
virtual ~DeviceInfoValidator() override = default;
|
||||
DeviceInfoValidator(const DeviceInfoValidator&) = delete;
|
||||
DeviceInfoValidator& operator=(const DeviceInfoValidator&) = delete;
|
||||
|
||||
// Decodes |device_info| and sets |message_status_|.
|
||||
virtual CborMessageStatus Parse(
|
||||
@@ -48,7 +52,7 @@ class DeviceInfoValidator : public CborValidator {
|
||||
int version_number_;
|
||||
// Saved Cbor-encoded device info.
|
||||
std::vector<uint8_t> device_info_bytes_;
|
||||
};
|
||||
}; // class DeviceInfoValidator
|
||||
} // namespace util
|
||||
} // namespace wvoec
|
||||
#endif // WVOEC_UTIL_DEVICE_INFO_VALIDATOR_H_
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
#ifndef WVOEC_UTIL_HMAC_H_
|
||||
#define WVOEC_UTIL_HMAC_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "OEMCryptoCENCCommon.h"
|
||||
#include "oemcrypto_ecc_key.h"
|
||||
#include "oemcrypto_rsa_key.h"
|
||||
#include "wv_class_utils.h"
|
||||
|
||||
namespace wvoec {
|
||||
namespace util {
|
||||
@@ -21,6 +22,9 @@ namespace util {
|
||||
// OEMCrypto session's RSA/ECC private key.
|
||||
class DrmPrivateKey {
|
||||
public:
|
||||
WVCDM_DISALLOW_COPY_AND_MOVE(DrmPrivateKey);
|
||||
~DrmPrivateKey() = default;
|
||||
|
||||
// Create an RSA-based DRM key.
|
||||
static std::unique_ptr<DrmPrivateKey> Create(
|
||||
std::shared_ptr<RsaPrivateKey>&& rsa_key);
|
||||
@@ -71,8 +75,6 @@ class DrmPrivateKey {
|
||||
std::vector<uint8_t> GenerateRsaSignature(
|
||||
const std::vector<uint8_t>& message) const;
|
||||
|
||||
~DrmPrivateKey() {}
|
||||
|
||||
private:
|
||||
DrmPrivateKey() {}
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
#ifndef WVOEC_UTIL_ECC_KEY_H_
|
||||
#define WVOEC_UTIL_ECC_KEY_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <openssl/ec.h>
|
||||
|
||||
#include "OEMCryptoCENCCommon.h"
|
||||
#include "wv_class_utils.h"
|
||||
|
||||
namespace wvoec {
|
||||
namespace util {
|
||||
@@ -35,6 +36,9 @@ class EccPrivateKey;
|
||||
|
||||
class EccPublicKey {
|
||||
public:
|
||||
~EccPublicKey();
|
||||
WVCDM_DISALLOW_COPY_AND_MOVE(EccPublicKey);
|
||||
|
||||
// Creates a new public key equivalent of the provided private key.
|
||||
static std::unique_ptr<EccPublicKey> New(const EccPrivateKey& private_key);
|
||||
|
||||
@@ -173,15 +177,8 @@ class EccPublicKey {
|
||||
const std::vector<uint8_t>& message,
|
||||
const std::vector<uint8_t>& signature) const;
|
||||
|
||||
~EccPublicKey();
|
||||
|
||||
EccPublicKey(const EccPublicKey&) = delete;
|
||||
EccPublicKey(EccPublicKey&&) = delete;
|
||||
const EccPublicKey& operator=(const EccPublicKey&) = delete;
|
||||
EccPublicKey& operator=(EccPublicKey&&) = delete;
|
||||
|
||||
private:
|
||||
EccPublicKey() {}
|
||||
EccPublicKey() = default;
|
||||
|
||||
// Initializes the public key object using the provided |buffer|.
|
||||
// In case of any failure, false is return and the key should be
|
||||
@@ -207,6 +204,9 @@ class EccPublicKey {
|
||||
|
||||
class EccPrivateKey {
|
||||
public:
|
||||
~EccPrivateKey();
|
||||
WVCDM_DISALLOW_COPY_AND_MOVE(EccPrivateKey);
|
||||
|
||||
// Creates a new, pseudorandom ECC private key belonging to the
|
||||
// curve specified.
|
||||
static std::unique_ptr<EccPrivateKey> New(EccCurve curve);
|
||||
@@ -318,7 +318,7 @@ class EccPrivateKey {
|
||||
size_t SignatureSize() const;
|
||||
|
||||
// Special test method used to generate a raw ECDSA signature.
|
||||
// A raw ECDSA signature is a concatination of a same-width-big-endian
|
||||
// A raw ECDSA signature is a concatenation of a same-width-big-endian
|
||||
// encoding of the ECDSA signature point components r and s.
|
||||
std::vector<uint8_t> GenerateRawSignature(
|
||||
const std::vector<uint8_t>& message) const;
|
||||
@@ -339,15 +339,8 @@ class EccPrivateKey {
|
||||
// by DeriveSymmetricKey().
|
||||
size_t SessionKeyLength() const;
|
||||
|
||||
~EccPrivateKey();
|
||||
|
||||
EccPrivateKey(const EccPrivateKey&) = delete;
|
||||
EccPrivateKey(EccPrivateKey&&) = delete;
|
||||
const EccPrivateKey& operator=(const EccPrivateKey&) = delete;
|
||||
EccPrivateKey& operator=(EccPrivateKey&&) = delete;
|
||||
|
||||
private:
|
||||
EccPrivateKey() {}
|
||||
EccPrivateKey() = default;
|
||||
|
||||
// Initializes the public key object using the provided |buffer|.
|
||||
// In case of any failure, false is return and the key should be
|
||||
|
||||
@@ -7,18 +7,22 @@
|
||||
#ifndef WVOEC_UTIL_KEY_DERIVER_H_
|
||||
#define WVOEC_UTIL_KEY_DERIVER_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "cmac.h"
|
||||
#include "wv_class_utils.h"
|
||||
|
||||
namespace wvoec {
|
||||
namespace util {
|
||||
class KeyDeriver {
|
||||
public:
|
||||
~KeyDeriver() = default;
|
||||
WVCDM_DISALLOW_COPY_AND_MOVE(KeyDeriver);
|
||||
|
||||
// Create a new key deriver using either the session key or the device
|
||||
// key.
|
||||
// Returns an empty pointer if the key size is not valid.
|
||||
@@ -52,15 +56,13 @@ class KeyDeriver {
|
||||
bool DeriveRenewedDeviceKey(const std::vector<uint8_t>& context,
|
||||
std::vector<uint8_t>* renewed_device_key);
|
||||
|
||||
~KeyDeriver() {}
|
||||
|
||||
private:
|
||||
KeyDeriver() {}
|
||||
|
||||
bool Init(const uint8_t* key, size_t key_size);
|
||||
|
||||
std::unique_ptr<Cmac> cmac_;
|
||||
};
|
||||
}; // class KeyDeriver
|
||||
} // namespace util
|
||||
} // namespace wvoec
|
||||
#endif // WVOEC_UTIL_KEY_DERIVER_H_
|
||||
|
||||
@@ -7,10 +7,13 @@
|
||||
#ifndef WVOEC_UTIL_OEM_CERT_H_
|
||||
#define WVOEC_UTIL_OEM_CERT_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "OEMCryptoCENCCommon.h"
|
||||
#include "wv_class_utils.h"
|
||||
|
||||
namespace wvoec {
|
||||
namespace util {
|
||||
@@ -39,6 +42,9 @@ class OemCertificate {
|
||||
kRsa = 1
|
||||
};
|
||||
|
||||
~OemCertificate();
|
||||
WVCDM_DISALLOW_COPY_AND_MOVE(OemCertificate);
|
||||
|
||||
// Creates a new OEM Certificate and performs basic validation
|
||||
// to ensure that the private key and public cert are well-formed.
|
||||
// The |public_cert| provided is parsed as an X.509 Certificate
|
||||
@@ -84,13 +90,6 @@ class OemCertificate {
|
||||
// (ie, same modulos and public exponent).
|
||||
OEMCryptoResult IsCertificateValid() const;
|
||||
|
||||
~OemCertificate();
|
||||
|
||||
OemCertificate(const OemCertificate&) = delete;
|
||||
OemCertificate(OemCertificate&&) = delete;
|
||||
const OemCertificate& operator=(const OemCertificate&) = delete;
|
||||
OemCertificate& operator=(OemCertificate&&) = delete;
|
||||
|
||||
private:
|
||||
OemCertificate();
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
#ifndef WVOEC_UTIL_RSA_KEY_H_
|
||||
#define WVOEC_UTIL_RSA_KEY_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "wv_class_utils.h"
|
||||
|
||||
namespace wvoec {
|
||||
namespace util {
|
||||
@@ -61,6 +62,9 @@ class RsaPrivateKey;
|
||||
|
||||
class RsaPublicKey {
|
||||
public:
|
||||
~RsaPublicKey();
|
||||
WVCDM_DISALLOW_COPY_AND_MOVE(RsaPublicKey);
|
||||
|
||||
// Creates a new public key equivalent of the provided private key.
|
||||
static std::unique_ptr<RsaPublicKey> New(const RsaPrivateKey& private_key);
|
||||
|
||||
@@ -176,15 +180,8 @@ class RsaPublicKey {
|
||||
std::vector<uint8_t> EncryptEncryptionKey(
|
||||
const std::string& encryption_key) const;
|
||||
|
||||
~RsaPublicKey();
|
||||
|
||||
RsaPublicKey(const RsaPublicKey&) = delete;
|
||||
RsaPublicKey(RsaPublicKey&&) = delete;
|
||||
const RsaPublicKey& operator=(const RsaPublicKey&) = delete;
|
||||
RsaPublicKey& operator=(RsaPublicKey&&) = delete;
|
||||
|
||||
private:
|
||||
RsaPublicKey() {}
|
||||
RsaPublicKey() = default;
|
||||
|
||||
// Initializes the public key object using the provided |buffer|.
|
||||
// In case of any failure, false is return and the key should be
|
||||
@@ -222,6 +219,9 @@ class RsaPublicKey {
|
||||
|
||||
class RsaPrivateKey {
|
||||
public:
|
||||
~RsaPrivateKey();
|
||||
WVCDM_DISALLOW_COPY_AND_MOVE(RsaPrivateKey);
|
||||
|
||||
// Creates a new, pseudorandom RSA private key.
|
||||
static std::unique_ptr<RsaPrivateKey> New(RsaFieldSize field_size);
|
||||
|
||||
@@ -342,15 +342,8 @@ class RsaPrivateKey {
|
||||
std::vector<uint8_t> DecryptEncryptionKey(
|
||||
const std::string& enc_encryption_key) const;
|
||||
|
||||
~RsaPrivateKey();
|
||||
|
||||
RsaPrivateKey(const RsaPrivateKey&) = delete;
|
||||
RsaPrivateKey(RsaPrivateKey&&) = delete;
|
||||
const RsaPrivateKey& operator=(const RsaPrivateKey&) = delete;
|
||||
RsaPrivateKey& operator=(RsaPrivateKey&&) = delete;
|
||||
|
||||
private:
|
||||
RsaPrivateKey() {}
|
||||
RsaPrivateKey() = default;
|
||||
|
||||
// Initializes the public key object using the provided |buffer|.
|
||||
// In case of any failure, false is return and the key should be
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#ifndef WVOEC_UTIL_SCOPED_OBJECT_H_
|
||||
#define WVOEC_UTIL_SCOPED_OBJECT_H_
|
||||
|
||||
#include "wv_class_utils.h"
|
||||
|
||||
namespace wvoec {
|
||||
namespace util {
|
||||
// A generic wrapper around pointer. This allows for automatic
|
||||
@@ -25,8 +27,7 @@ class ScopedObject {
|
||||
}
|
||||
|
||||
// Copy construction and assignment are not allowed.
|
||||
ScopedObject(const ScopedObject& other) = delete;
|
||||
ScopedObject& operator=(const ScopedObject& other) = delete;
|
||||
WVCDM_DISALLOW_COPY(ScopedObject);
|
||||
|
||||
// Move construction and assignment are allowed.
|
||||
ScopedObject(ScopedObject&& other) : ptr_(other.ptr_) {
|
||||
@@ -65,7 +66,7 @@ class ScopedObject {
|
||||
|
||||
private:
|
||||
Type* ptr_ = nullptr;
|
||||
};
|
||||
}; // class ScopedObject
|
||||
} // namespace util
|
||||
} // namespace wvoec
|
||||
#endif // WVOEC_UTIL_SCOPED_OBJECT_H_
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "cbor_validator.h"
|
||||
#include "cppbor.h"
|
||||
#include "wv_class_utils.h"
|
||||
|
||||
namespace wvoec {
|
||||
namespace util {
|
||||
@@ -23,9 +24,7 @@ class SignedCsrPayloadValidator : public CborValidator {
|
||||
public:
|
||||
explicit SignedCsrPayloadValidator() {}
|
||||
virtual ~SignedCsrPayloadValidator() override = default;
|
||||
SignedCsrPayloadValidator(const SignedCsrPayloadValidator&) = delete;
|
||||
SignedCsrPayloadValidator& operator=(const SignedCsrPayloadValidator&) =
|
||||
delete;
|
||||
WVCDM_DISALLOW_COPY_AND_MOVE(SignedCsrPayloadValidator);
|
||||
|
||||
// Verifies the Cbor struct of a client generated SignedData<CsrPayload>.
|
||||
virtual CborMessageStatus Validate() override;
|
||||
@@ -38,7 +37,7 @@ class SignedCsrPayloadValidator : public CborValidator {
|
||||
CborMessageStatus ValidateDataToBeSigned(const cppbor::Bstr* data);
|
||||
// Used to generate formatted message.
|
||||
std::stringstream msg_ss_;
|
||||
};
|
||||
}; // class SignedCsrPayloadValidator
|
||||
} // namespace util
|
||||
} // namespace wvoec
|
||||
#endif // WVOEC_UTIL_SIGNED_CSR_PAYLOAD_VALIDATOR_H_
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#ifndef WVOEC_UTIL_WVCRC32_H_
|
||||
#define WVOEC_UTIL_WVCRC32_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
namespace wvoec {
|
||||
namespace util {
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
@@ -358,7 +357,7 @@ CborMessageStatus BccValidator::ProcessSubjectPublicKeyInfo(
|
||||
"MAP_KEY_DEVICE_KEY_TYPE: " +
|
||||
std::to_string(value));
|
||||
}
|
||||
fmt_msgs.push_back(kv);
|
||||
fmt_msgs.push_back(std::move(kv));
|
||||
} break;
|
||||
case MAP_KEY_DEVICE_KEY_ALGORITHM: {
|
||||
if (entry.second->type() != cppbor::NINT) {
|
||||
@@ -386,7 +385,7 @@ CborMessageStatus BccValidator::ProcessSubjectPublicKeyInfo(
|
||||
"MAP_KEY_DEVICE_KEY_ALGORITHM: " +
|
||||
std::to_string(value));
|
||||
}
|
||||
fmt_msgs.push_back(kv);
|
||||
fmt_msgs.push_back(std::move(kv));
|
||||
} break;
|
||||
case MAP_KEY_DEVICE_KEY_OPS:
|
||||
// The OPS is an array. Ignored for now.
|
||||
@@ -417,7 +416,7 @@ CborMessageStatus BccValidator::ProcessSubjectPublicKeyInfo(
|
||||
"MAP_KEY_DEVICE_KEY_CURVE: " +
|
||||
std::to_string(value));
|
||||
}
|
||||
fmt_msgs.push_back(kv);
|
||||
fmt_msgs.push_back(std::move(kv));
|
||||
} break;
|
||||
case MAP_KEY_DEVICE_KEY_BYTES_0:
|
||||
case MAP_KEY_DEVICE_KEY_BYTES_1:
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
@@ -785,7 +785,7 @@ OEMCryptoResult EccPublicKey::VerifyRawSignature(
|
||||
if (!s || !r) {
|
||||
LOGE("Failed to parse R/S values: r = %s, s = %s, r_s_size = %d",
|
||||
BoolToStatus(r.ok()), BoolToStatus(s.ok()), r_s_size);
|
||||
// Technically, any byte string should be convertable to an
|
||||
// Technically, any byte string should be convertible to an
|
||||
// integer. This must be an OpenSSL/BoringSSL error.
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "log.h"
|
||||
#include "oemcrypto_rsa_key.h"
|
||||
#include "scoped_object.h"
|
||||
#include "wv_class_utils.h"
|
||||
|
||||
namespace wvoec {
|
||||
namespace util {
|
||||
@@ -53,6 +54,9 @@ OEMCryptoResult VerifyRsaKey(const RSA* public_key,
|
||||
// Certificate.
|
||||
class OemPublicCertificate {
|
||||
public:
|
||||
~OemPublicCertificate() = default;
|
||||
WVCDM_DISALLOW_COPY_AND_MOVE(OemPublicCertificate);
|
||||
|
||||
// Loads a PKCS #7 signedData message with certificate chain.
|
||||
// Minimum validation is performed. Only checks that the
|
||||
// device's public key is of a known type (RSA).
|
||||
@@ -81,15 +85,8 @@ class OemPublicCertificate {
|
||||
return EVP_PKEY_get0_RSA(device_public_key_.get());
|
||||
}
|
||||
|
||||
~OemPublicCertificate() = default;
|
||||
|
||||
OemPublicCertificate(const OemPublicCertificate&) = delete;
|
||||
OemPublicCertificate(OemPublicCertificate&&) = delete;
|
||||
const OemPublicCertificate& operator=(const OemPublicCertificate&) = delete;
|
||||
OemPublicCertificate& operator=(OemPublicCertificate&&) = delete;
|
||||
|
||||
private:
|
||||
OemPublicCertificate() {}
|
||||
OemPublicCertificate() = default;
|
||||
|
||||
bool InitFromBuffer(const uint8_t* public_cert, size_t public_cert_size) {
|
||||
// Step 1: Parse the PKCS7 certificate chain as signedData.
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
#ifndef OEM_CERT_TEST_H_
|
||||
#define OEM_CERT_TEST_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace wvoec {
|
||||
namespace util {
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
#ifndef WVOEC_UTIL_REF_TEST_UTILS_H_
|
||||
#define WVOEC_UTIL_REF_TEST_UTILS_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user