OEMCrypto and OPK 18.8
This commit is contained in:
11
CHANGELOG.md
11
CHANGELOG.md
@@ -2,6 +2,16 @@
|
|||||||
|
|
||||||
[TOC]
|
[TOC]
|
||||||
|
|
||||||
|
## [Version 18.8][v18.8]
|
||||||
|
|
||||||
|
This is a minor release with minor test improvements.
|
||||||
|
|
||||||
|
### Tests
|
||||||
|
|
||||||
|
- Update some CAST tests to enforce format of the message signed by
|
||||||
|
OEMCrypto_GenerateRSASignature()
|
||||||
|
- Skip usage table tests on devices that don't support usage tables
|
||||||
|
|
||||||
## [Version 18.7][v18.7]
|
## [Version 18.7][v18.7]
|
||||||
|
|
||||||
This release adds new tests that provide stricter enforcement of the existing
|
This release adds new tests that provide stricter enforcement of the existing
|
||||||
@@ -588,3 +598,4 @@ Public release for OEMCrypto API and ODK library version 16.4.
|
|||||||
[v18.5]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v18.5
|
[v18.5]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v18.5
|
||||||
[v18.6]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v18.6
|
[v18.6]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v18.6
|
||||||
[v18.7]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v18.7
|
[v18.7]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v18.7
|
||||||
|
[v18.8]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v18.8
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
// License Agreement.
|
// License Agreement.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @mainpage OEMCrypto API v18.7
|
* @mainpage OEMCrypto API v18.8
|
||||||
*
|
*
|
||||||
* OEMCrypto is the low level library implemented by the OEM to provide key and
|
* 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
|
* content protection, usually in a separate secure memory or process space. The
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ struct CoreMessageFeatures {
|
|||||||
|
|
||||||
// This is the published version of the ODK Core Message library. The default
|
// 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
|
// behavior is for the server to restrict messages to at most this version
|
||||||
// number. The default is 18.7.
|
// number. The default is 18.8.
|
||||||
uint32_t maximum_major_version = 18;
|
uint32_t maximum_major_version = 18;
|
||||||
uint32_t maximum_minor_version = 7;
|
uint32_t maximum_minor_version = 8;
|
||||||
|
|
||||||
bool operator==(const CoreMessageFeatures &other) const;
|
bool operator==(const CoreMessageFeatures &other) const;
|
||||||
bool operator!=(const CoreMessageFeatures &other) const {
|
bool operator!=(const CoreMessageFeatures &other) const {
|
||||||
|
|||||||
@@ -16,10 +16,10 @@ extern "C" {
|
|||||||
|
|
||||||
/* The version of this library. */
|
/* The version of this library. */
|
||||||
#define ODK_MAJOR_VERSION 18
|
#define ODK_MAJOR_VERSION 18
|
||||||
#define ODK_MINOR_VERSION 7
|
#define ODK_MINOR_VERSION 8
|
||||||
|
|
||||||
/* ODK Version string. Date changed automatically on each release. */
|
/* ODK Version string. Date changed automatically on each release. */
|
||||||
#define ODK_RELEASE_DATE "ODK v18.7 2024-09-04"
|
#define ODK_RELEASE_DATE "ODK v18.8 2024-11-04"
|
||||||
|
|
||||||
/* The lowest version number for an ODK message. */
|
/* The lowest version number for an ODK message. */
|
||||||
#define ODK_FIRST_VERSION 16
|
#define ODK_FIRST_VERSION 16
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ CoreMessageFeatures CoreMessageFeatures::DefaultFeatures(
|
|||||||
features.maximum_minor_version = 2; // 17.2
|
features.maximum_minor_version = 2; // 17.2
|
||||||
break;
|
break;
|
||||||
case 18:
|
case 18:
|
||||||
features.maximum_minor_version = 7; // 18.7
|
features.maximum_minor_version = 8; // 18.8
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
features.maximum_minor_version = 0;
|
features.maximum_minor_version = 0;
|
||||||
|
|||||||
@@ -274,7 +274,7 @@ OEMCryptoResult ODK_InitializeSessionValues(ODK_TimerLimits* timer_limits,
|
|||||||
nonce_values->api_minor_version = 2;
|
nonce_values->api_minor_version = 2;
|
||||||
break;
|
break;
|
||||||
case 18:
|
case 18:
|
||||||
nonce_values->api_minor_version = 7;
|
nonce_values->api_minor_version = 8;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
nonce_values->api_minor_version = 0;
|
nonce_values->api_minor_version = 0;
|
||||||
|
|||||||
@@ -1216,7 +1216,7 @@ std::vector<VersionParameters> TestCases() {
|
|||||||
// number.
|
// number.
|
||||||
{16, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 16, 5},
|
{16, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 16, 5},
|
||||||
{17, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 17, 2},
|
{17, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 17, 2},
|
||||||
{18, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 18, 7},
|
{18, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 18, 8},
|
||||||
// Here are some known good versions. Make extra sure they work.
|
// Here are some known good versions. Make extra sure they work.
|
||||||
{ODK_MAJOR_VERSION, 16, 3, 16, 3},
|
{ODK_MAJOR_VERSION, 16, 3, 16, 3},
|
||||||
{ODK_MAJOR_VERSION, 16, 4, 16, 4},
|
{ODK_MAJOR_VERSION, 16, 4, 16, 4},
|
||||||
@@ -1230,6 +1230,7 @@ std::vector<VersionParameters> TestCases() {
|
|||||||
{ODK_MAJOR_VERSION, 18, 5, 18, 5},
|
{ODK_MAJOR_VERSION, 18, 5, 18, 5},
|
||||||
{ODK_MAJOR_VERSION, 18, 6, 18, 6},
|
{ODK_MAJOR_VERSION, 18, 6, 18, 6},
|
||||||
{ODK_MAJOR_VERSION, 18, 7, 18, 7},
|
{ODK_MAJOR_VERSION, 18, 7, 18, 7},
|
||||||
|
{ODK_MAJOR_VERSION, 18, 8, 18, 8},
|
||||||
{0, 16, 3, 16, 3},
|
{0, 16, 3, 16, 3},
|
||||||
{0, 16, 4, 16, 4},
|
{0, 16, 4, 16, 4},
|
||||||
{0, 16, 5, 16, 5},
|
{0, 16, 5, 16, 5},
|
||||||
@@ -1239,6 +1240,7 @@ std::vector<VersionParameters> TestCases() {
|
|||||||
{0, 18, 5, 18, 5},
|
{0, 18, 5, 18, 5},
|
||||||
{0, 18, 6, 18, 6},
|
{0, 18, 6, 18, 6},
|
||||||
{0, 18, 7, 18, 7},
|
{0, 18, 7, 18, 7},
|
||||||
|
{0, 18, 8, 18, 8},
|
||||||
};
|
};
|
||||||
return test_cases;
|
return test_cases;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,6 +216,7 @@ oemcrypto_unittests_sources += \
|
|||||||
$(oemcrypto_unittests_dir)/oemcrypto_generic_crypto_test.cpp \
|
$(oemcrypto_unittests_dir)/oemcrypto_generic_crypto_test.cpp \
|
||||||
$(oemcrypto_unittests_dir)/oemcrypto_license_test.cpp \
|
$(oemcrypto_unittests_dir)/oemcrypto_license_test.cpp \
|
||||||
$(oemcrypto_unittests_dir)/oemcrypto_provisioning_test.cpp \
|
$(oemcrypto_unittests_dir)/oemcrypto_provisioning_test.cpp \
|
||||||
|
$(oemcrypto_unittests_dir)/oemcrypto_security_test.cpp \
|
||||||
$(oemcrypto_unittests_dir)/oemcrypto_usage_table_test.cpp \
|
$(oemcrypto_unittests_dir)/oemcrypto_usage_table_test.cpp \
|
||||||
$(oemcrypto_unittests_dir)/oemcrypto_test.cpp \
|
$(oemcrypto_unittests_dir)/oemcrypto_test.cpp \
|
||||||
$(oemcrypto_dir)/util/src/cmac.cpp \
|
$(oemcrypto_dir)/util/src/cmac.cpp \
|
||||||
|
|||||||
@@ -350,10 +350,24 @@ static OEMCryptoResult RewrapDeviceDRMKeyOEMCert(
|
|||||||
LOGE("Failed to AES CBC decrypt DRM private key with result: %u", result);
|
LOGE("Failed to AES CBC decrypt DRM private key with result: %u", result);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
/* Adjust for RSA keys with specified schemes */
|
||||||
|
uint32_t allowed_schemes = 0;
|
||||||
|
size_t key_offset = 0;
|
||||||
|
if (drm_key_type == DRM_RSA_PRIVATE_KEY) {
|
||||||
|
if (enc_drm_key_length >= 8 &&
|
||||||
|
crypto_memcmp(clear_drm_key, "SIGN", 4) == 0) {
|
||||||
|
memcpy(&allowed_schemes, clear_drm_key + 4, 4);
|
||||||
|
allowed_schemes = oemcrypto_be32toh(allowed_schemes);
|
||||||
|
key_offset = 8;
|
||||||
|
} else {
|
||||||
|
allowed_schemes = kSign_RSASSA_PSS;
|
||||||
|
}
|
||||||
|
}
|
||||||
/* Create asymmetric key handle for DRM private key in order to get the
|
/* Create asymmetric key handle for DRM private key in order to get the
|
||||||
* signature size. */
|
* signature size. */
|
||||||
WTPI_AsymmetricKey_Handle private_key_handle;
|
WTPI_AsymmetricKey_Handle private_key_handle;
|
||||||
result = WTPI_CreateAsymmetricKeyHandle(clear_drm_key, enc_drm_key_length,
|
result = WTPI_CreateAsymmetricKeyHandle(clear_drm_key + key_offset,
|
||||||
|
enc_drm_key_length - key_offset,
|
||||||
drm_key_type, &private_key_handle);
|
drm_key_type, &private_key_handle);
|
||||||
if (result != OEMCrypto_SUCCESS) {
|
if (result != OEMCrypto_SUCCESS) {
|
||||||
LOGE(
|
LOGE(
|
||||||
@@ -380,7 +394,7 @@ static OEMCryptoResult RewrapDeviceDRMKeyOEMCert(
|
|||||||
/* Check that it's a valid DRM key. */
|
/* Check that it's a valid DRM key. */
|
||||||
result =
|
result =
|
||||||
OPKI_LoadDRMKey(session_context, drm_key_type, wrapped_drm_key,
|
OPKI_LoadDRMKey(session_context, drm_key_type, wrapped_drm_key,
|
||||||
wrapped_drm_key_length, signature_size, kSign_RSASSA_PSS);
|
wrapped_drm_key_length, signature_size, allowed_schemes);
|
||||||
if (result != OEMCrypto_SUCCESS) {
|
if (result != OEMCrypto_SUCCESS) {
|
||||||
LOGE("Failed to load DRM key with result: %u", result);
|
LOGE("Failed to load DRM key with result: %u", result);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
// version bumps to v17.1, the first released OPK implementation would be
|
// version bumps to v17.1, the first released OPK implementation would be
|
||||||
// v17.1.0
|
// v17.1.0
|
||||||
#define API_MAJOR_VERSION 18
|
#define API_MAJOR_VERSION 18
|
||||||
#define API_MINOR_VERSION 7
|
#define API_MINOR_VERSION 8
|
||||||
#define OPK_PATCH_VERSION 0
|
#define OPK_PATCH_VERSION 0
|
||||||
|
|
||||||
#endif /* OEMCRYPTO_TA_OEMCRYPTO_API_MACROS_H_ */
|
#endif /* OEMCRYPTO_TA_OEMCRYPTO_API_MACROS_H_ */
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
# production use.
|
# production use.
|
||||||
'wtpi_stub_dir': '<(oemcrypto_ta_dir)/wtpi_useless',
|
'wtpi_stub_dir': '<(oemcrypto_ta_dir)/wtpi_useless',
|
||||||
'use_provisioning_40%': 0,
|
'use_provisioning_40%': 0,
|
||||||
|
'use_random_device_key%': 0,
|
||||||
},
|
},
|
||||||
'target_defaults': {
|
'target_defaults': {
|
||||||
'toolsets' : [ 'target' ],
|
'toolsets' : [ 'target' ],
|
||||||
@@ -31,7 +32,6 @@
|
|||||||
'test-only/wtpi_persistent_storage.c',
|
'test-only/wtpi_persistent_storage.c',
|
||||||
'test-only/file_store_interface.c',
|
'test-only/file_store_interface.c',
|
||||||
'test-only/wtpi_cas.c',
|
'test-only/wtpi_cas.c',
|
||||||
'test-only/wtpi_device_key_access.c',
|
|
||||||
'<(wtpi_stub_dir)/wtpi_root_of_trust_layer2.c',
|
'<(wtpi_stub_dir)/wtpi_root_of_trust_layer2.c',
|
||||||
'<(wtpi_stub_dir)/wtpi_secure_buffer_access.c',
|
'<(wtpi_stub_dir)/wtpi_secure_buffer_access.c',
|
||||||
'<(wtpi_stub_dir)/wtpi_fused.c',
|
'<(wtpi_stub_dir)/wtpi_fused.c',
|
||||||
@@ -49,6 +49,11 @@
|
|||||||
'wtpi_device_renewal_layer2_test.c',
|
'wtpi_device_renewal_layer2_test.c',
|
||||||
],
|
],
|
||||||
}],
|
}],
|
||||||
|
['use_random_device_key', {
|
||||||
|
'sources': ['<(wtpi_stub_dir)/wtpi_device_key_access.c',],
|
||||||
|
}, {
|
||||||
|
'sources': ['test-only/wtpi_device_key_access.c',],
|
||||||
|
}],
|
||||||
],
|
],
|
||||||
'dependencies': [
|
'dependencies': [
|
||||||
'<(oemcrypto_ta_dir)/oemcrypto_ta.gyp:oemcrypto_ta_linux_tee',
|
'<(oemcrypto_ta_dir)/oemcrypto_ta.gyp:oemcrypto_ta_linux_tee',
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ repo sync -c -j32
|
|||||||
# Download an Android NDK prebuilt to compile liboemcrypto.so
|
# Download an Android NDK prebuilt to compile liboemcrypto.so
|
||||||
cd $TRUSTY_DIR/prebuilts
|
cd $TRUSTY_DIR/prebuilts
|
||||||
mkdir ndk && cd ndk
|
mkdir ndk && cd ndk
|
||||||
git clone https://android.googlesource.com/toolchain/prebuilts/ndk/r25
|
git clone https://android.googlesource.com/toolchain/prebuilts/ndk/r26
|
||||||
|
|
||||||
# Add the OEMCrypto TA path as a user module. The OEMCRYPTO_TA_DIR must expand
|
# Add the OEMCrypto TA path as a user module. The OEMCRYPTO_TA_DIR must expand
|
||||||
# to a path that is relative to the Trusty directory
|
# to a path that is relative to the Trusty directory
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ SCRIPT_DIR=$(dirname "${BASH_SOURCE[0]}")
|
|||||||
# Build liboemcrypto.so
|
# Build liboemcrypto.so
|
||||||
|
|
||||||
if [ ! -v ANDROID_NDK_ROOT ]; then
|
if [ ! -v ANDROID_NDK_ROOT ]; then
|
||||||
ANDROID_NDK_ROOT=$(realpath "$SCRIPT_DIR/../../../../../prebuilts/ndk/r25")
|
ANDROID_NDK_ROOT=$(realpath "$SCRIPT_DIR/../../../../../prebuilts/ndk/r26")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
"$ANDROID_NDK_ROOT/ndk-build" \
|
"$ANDROID_NDK_ROOT/ndk-build" \
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ LIBOEMCRYPTO_SO := $(LIBOEMCRYPTO_OUT_DIR)/lib/arm64-v8a/liboemcrypto.so
|
|||||||
$(LIBOEMCRYPTO_SO): LOCAL_DIR := $(GET_LOCAL_DIR)
|
$(LIBOEMCRYPTO_SO): LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||||
$(LIBOEMCRYPTO_SO): LIBOEMCRYPTO_BUILD_DIR := $(LIBOEMCRYPTO_BUILD_DIR)
|
$(LIBOEMCRYPTO_SO): LIBOEMCRYPTO_BUILD_DIR := $(LIBOEMCRYPTO_BUILD_DIR)
|
||||||
$(LIBOEMCRYPTO_SO): LIBOEMCRYPTO_OUT_DIR := $(LIBOEMCRYPTO_OUT_DIR)
|
$(LIBOEMCRYPTO_SO): LIBOEMCRYPTO_OUT_DIR := $(LIBOEMCRYPTO_OUT_DIR)
|
||||||
$(LIBOEMCRYPTO_SO): NDK_ROOT := $(TRUSTY_TOP)/prebuilts/ndk/r25
|
$(LIBOEMCRYPTO_SO): NDK_ROOT := $(TRUSTY_TOP)/prebuilts/ndk/r26
|
||||||
$(LIBOEMCRYPTO_SO):
|
$(LIBOEMCRYPTO_SO):
|
||||||
$(NOECHO)$(NDK_ROOT)/ndk-build \
|
$(NOECHO)$(NDK_ROOT)/ndk-build \
|
||||||
-C $(LOCAL_DIR) \
|
-C $(LOCAL_DIR) \
|
||||||
|
|||||||
@@ -185,12 +185,18 @@ static bool is_bound(struct widevine_ctx* ctx) {
|
|||||||
static void close_shared_memory(struct widevine_ctx* ctx) {
|
static void close_shared_memory(struct widevine_ctx* ctx) {
|
||||||
TEE_SharedMemory_Bind(NULL, 0);
|
TEE_SharedMemory_Bind(NULL, 0);
|
||||||
if (ctx->shared_buffer_addr != NULL) {
|
if (ctx->shared_buffer_addr != NULL) {
|
||||||
munmap(ctx->shared_buffer_addr, ctx->shared_buffer_size);
|
int rc = munmap(ctx->shared_buffer_addr, ctx->shared_buffer_size);
|
||||||
|
if (rc != NO_ERROR) {
|
||||||
|
TLOGW("munmap() failed: %d\n", rc);
|
||||||
|
}
|
||||||
ctx->shared_buffer_addr = NULL;
|
ctx->shared_buffer_addr = NULL;
|
||||||
ctx->shared_buffer_size = 0;
|
ctx->shared_buffer_size = 0;
|
||||||
}
|
}
|
||||||
if (ctx->shared_message_addr != NULL) {
|
if (ctx->shared_message_addr != NULL) {
|
||||||
munmap(ctx->shared_message_addr, ctx->shared_message_size);
|
int rc = munmap(ctx->shared_message_addr, ctx->shared_message_size);
|
||||||
|
if (rc != NO_ERROR) {
|
||||||
|
TLOGW("munmap() failed: %d\n", rc);
|
||||||
|
}
|
||||||
ctx->shared_message_addr = NULL;
|
ctx->shared_message_addr = NULL;
|
||||||
ctx->shared_message_size = 0;
|
ctx->shared_message_size = 0;
|
||||||
}
|
}
|
||||||
@@ -310,7 +316,10 @@ static int dispatch_bind_message(handle_t chan,
|
|||||||
PROT_READ | PROT_WRITE, 0, handles[1], 0);
|
PROT_READ | PROT_WRITE, 0, handles[1], 0);
|
||||||
if (shared_buffer_addr == MAP_FAILED) {
|
if (shared_buffer_addr == MAP_FAILED) {
|
||||||
TLOGE("Could not map shared buffer.\n");
|
TLOGE("Could not map shared buffer.\n");
|
||||||
munmap(shared_message_addr, shared_message_size);
|
int rc = munmap(shared_message_addr, shared_message_size);
|
||||||
|
if (rc != NO_ERROR) {
|
||||||
|
TLOGW("munmap() failed: %d\n", rc);
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ LOCAL_SRC_FILES:= \
|
|||||||
oemcrypto_generic_crypto_test.cpp \
|
oemcrypto_generic_crypto_test.cpp \
|
||||||
oemcrypto_license_test.cpp \
|
oemcrypto_license_test.cpp \
|
||||||
oemcrypto_provisioning_test.cpp \
|
oemcrypto_provisioning_test.cpp \
|
||||||
|
oemcrypto_security_test.cpp \
|
||||||
oemcrypto_usage_table_test.cpp \
|
oemcrypto_usage_table_test.cpp \
|
||||||
oemcrypto_test.cpp \
|
oemcrypto_test.cpp \
|
||||||
oemcrypto_test_android.cpp \
|
oemcrypto_test_android.cpp \
|
||||||
|
|||||||
177
oemcrypto/test/extract_bcc_tool.cpp
Normal file
177
oemcrypto/test/extract_bcc_tool.cpp
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
// 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);
|
||||||
|
std::vector<char> build_info_buffer;
|
||||||
|
size_t oemcrypto_build_info_size = 0;
|
||||||
|
result = OEMCrypto_BuildInformation(build_info_buffer.data(),
|
||||||
|
&oemcrypto_build_info_size);
|
||||||
|
if (result == OEMCrypto_ERROR_SHORT_BUFFER) {
|
||||||
|
build_info_buffer.resize(oemcrypto_build_info_size);
|
||||||
|
result = OEMCrypto_BuildInformation(build_info_buffer.data(),
|
||||||
|
&oemcrypto_build_info_size);
|
||||||
|
}
|
||||||
|
if (result != OEMCrypto_SUCCESS) {
|
||||||
|
std::cerr << "Failed to get build information: result = " << result
|
||||||
|
<< std::endl;
|
||||||
|
OEMCrypto_Terminate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
build_info_buffer.resize(oemcrypto_build_info_size);
|
||||||
|
oemcrypto_build_info->assign(build_info_buffer.begin(),
|
||||||
|
build_info_buffer.end());
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@ void advance_dest_buffer(OEMCrypto_DestBufferDesc* dest_buffer, size_t bytes) {
|
|||||||
switch (dest_buffer->type) {
|
switch (dest_buffer->type) {
|
||||||
case OEMCrypto_BufferType_Clear:
|
case OEMCrypto_BufferType_Clear:
|
||||||
dest_buffer->buffer.clear.clear_buffer += bytes;
|
dest_buffer->buffer.clear.clear_buffer += bytes;
|
||||||
|
dest_buffer->buffer.clear.clear_buffer_length -= bytes;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OEMCrypto_BufferType_Secure:
|
case OEMCrypto_BufferType_Secure:
|
||||||
@@ -98,11 +99,6 @@ OEMCryptoResult DecryptFallbackChain::DecryptSample(
|
|||||||
const size_t length =
|
const size_t length =
|
||||||
subsample.num_bytes_clear + subsample.num_bytes_encrypted;
|
subsample.num_bytes_clear + subsample.num_bytes_encrypted;
|
||||||
fake_sample.buffers.input_data_length = length;
|
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 = &subsample;
|
||||||
fake_sample.subsamples_length = 1;
|
fake_sample.subsamples_length = 1;
|
||||||
|
|
||||||
@@ -148,11 +144,6 @@ OEMCryptoResult DecryptFallbackChain::DecryptSubsample(
|
|||||||
|
|
||||||
if (subsample.num_bytes_clear > 0) {
|
if (subsample.num_bytes_clear > 0) {
|
||||||
fake_sample.buffers.input_data_length = subsample.num_bytes_clear;
|
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_clear = subsample.num_bytes_clear;
|
||||||
fake_subsample.num_bytes_encrypted = 0;
|
fake_subsample.num_bytes_encrypted = 0;
|
||||||
fake_subsample.block_offset = 0;
|
fake_subsample.block_offset = 0;
|
||||||
@@ -176,11 +167,6 @@ OEMCryptoResult DecryptFallbackChain::DecryptSubsample(
|
|||||||
|
|
||||||
if (subsample.num_bytes_encrypted > 0) {
|
if (subsample.num_bytes_encrypted > 0) {
|
||||||
fake_sample.buffers.input_data_length = subsample.num_bytes_encrypted;
|
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_clear = 0;
|
||||||
fake_subsample.num_bytes_encrypted = subsample.num_bytes_encrypted;
|
fake_subsample.num_bytes_encrypted = subsample.num_bytes_encrypted;
|
||||||
fake_subsample.block_offset = subsample.block_offset;
|
fake_subsample.block_offset = subsample.block_offset;
|
||||||
|
|||||||
@@ -73,6 +73,76 @@ int32_t JsmnAncestorCount(const std::vector<jsmntok_t>& tokens,
|
|||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* BoolName(bool value) { return value ? "true" : "false"; }
|
||||||
|
const char* SecurityLevelName(OEMCrypto_Security_Level value) {
|
||||||
|
switch (value) {
|
||||||
|
case OEMCrypto_Level_Unknown:
|
||||||
|
return "OEMCrypto_Level_Unknown";
|
||||||
|
case OEMCrypto_Level1:
|
||||||
|
return "OEMCrypto_Level1";
|
||||||
|
case OEMCrypto_Level2:
|
||||||
|
return "OEMCrypto_Level2";
|
||||||
|
case OEMCrypto_Level3:
|
||||||
|
return "OEMCrypto_Level3";
|
||||||
|
}
|
||||||
|
// Not reachable unless the enum value is invalid
|
||||||
|
return "<INVALID VALUE>";
|
||||||
|
}
|
||||||
|
const char* HDCPCapabilityName(OEMCrypto_HDCP_Capability value) {
|
||||||
|
switch (value) {
|
||||||
|
case HDCP_NONE:
|
||||||
|
return "HDCP_NONE";
|
||||||
|
case HDCP_V1:
|
||||||
|
return "HDCP_V1";
|
||||||
|
case HDCP_V1_0:
|
||||||
|
return "HDCP_V1_0";
|
||||||
|
case HDCP_V1_1:
|
||||||
|
return "HDCP_V1_1";
|
||||||
|
case HDCP_V1_2:
|
||||||
|
return "HDCP_V1_2";
|
||||||
|
case HDCP_V1_3:
|
||||||
|
return "HDCP_V1_3";
|
||||||
|
case HDCP_V1_4:
|
||||||
|
return "HDCP_V1_4";
|
||||||
|
case HDCP_V2:
|
||||||
|
return "HDCP_V2";
|
||||||
|
case HDCP_V2_1:
|
||||||
|
return "HDCP_V2_1";
|
||||||
|
case HDCP_V2_2:
|
||||||
|
return "HDCP_V2_2";
|
||||||
|
case HDCP_V2_3:
|
||||||
|
return "HDCP_V2_3";
|
||||||
|
case HDCP_NO_DIGITAL_OUTPUT:
|
||||||
|
return "HDCP_NO_DIGITAL_OUTPUT";
|
||||||
|
}
|
||||||
|
// Not reachable unless the enum value is invalid
|
||||||
|
return "<INVALID VALUE>";
|
||||||
|
}
|
||||||
|
const char* WatermarkingSupportName(OEMCrypto_WatermarkingSupport value) {
|
||||||
|
switch (value) {
|
||||||
|
case OEMCrypto_WatermarkingError:
|
||||||
|
return "OEMCrypto_WatermarkingError";
|
||||||
|
case OEMCrypto_WatermarkingNotSupported:
|
||||||
|
return "OEMCrypto_WatermarkingNotSupported";
|
||||||
|
case OEMCrypto_WatermarkingConfigurable:
|
||||||
|
return "OEMCrypto_WatermarkingConfigurable";
|
||||||
|
case OEMCrypto_WatermarkingAlwaysOn:
|
||||||
|
return "OEMCrypto_WatermarkingAlwaysOn";
|
||||||
|
}
|
||||||
|
// Not reachable unless the enum value is invalid
|
||||||
|
return "<INVALID VALUE>";
|
||||||
|
}
|
||||||
|
const char* DTCP2CapabiityName(OEMCrypto_DTCP2_Capability value) {
|
||||||
|
switch (value) {
|
||||||
|
case OEMCrypto_NO_DTCP2:
|
||||||
|
return "OEMCrypto_NO_DTCP2";
|
||||||
|
case OEMCrypto_DTCP2_V1:
|
||||||
|
return "OEMCrypto_DTCP2_V1";
|
||||||
|
}
|
||||||
|
// Not reachable unless the enum value is invalid
|
||||||
|
return "<INVALID VALUE>";
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void OEMCryptoClientTest::SetUp() {
|
void OEMCryptoClientTest::SetUp() {
|
||||||
@@ -148,6 +218,11 @@ OEMCryptoResult OEMCryptoClientTest::CopyBuffer(
|
|||||||
dest_buffer_descriptor, subsample_flags);
|
dest_buffer_descriptor, subsample_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OEMCryptoClientTest::RecordWvProperty(const std::string& key,
|
||||||
|
const std::string& value) {
|
||||||
|
RecordProperty("widevine_metadata_oec_" + key, value);
|
||||||
|
}
|
||||||
|
|
||||||
const char* HDCPCapabilityAsString(OEMCrypto_HDCP_Capability value) {
|
const char* HDCPCapabilityAsString(OEMCrypto_HDCP_Capability value) {
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case HDCP_NONE:
|
case HDCP_NONE:
|
||||||
@@ -174,9 +249,9 @@ const char* HDCPCapabilityAsString(OEMCrypto_HDCP_Capability value) {
|
|||||||
return "HDCP version 2.3";
|
return "HDCP version 2.3";
|
||||||
case HDCP_NO_DIGITAL_OUTPUT:
|
case HDCP_NO_DIGITAL_OUTPUT:
|
||||||
return "No HDCP device attached/using local display with secure path";
|
return "No HDCP device attached/using local display with secure path";
|
||||||
default:
|
|
||||||
return "<INVALID VALUE>";
|
|
||||||
}
|
}
|
||||||
|
// Not reachable unless the enum value is invalid
|
||||||
|
return "<INVALID VALUE>";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a printable string from data. If all the characters are printable,
|
// Return a printable string from data. If all the characters are printable,
|
||||||
@@ -218,7 +293,7 @@ TEST_F(OEMCryptoClientTest, FreeUnallocatedSecureBufferNoFailure) {
|
|||||||
*/
|
*/
|
||||||
TEST_F(OEMCryptoClientTest, VersionNumber) {
|
TEST_F(OEMCryptoClientTest, VersionNumber) {
|
||||||
const std::string log_message =
|
const std::string log_message =
|
||||||
"OEMCrypto unit tests for API 18.7. Tests last updated 2024-09-04";
|
"OEMCrypto unit tests for API 18.8. Tests last updated 2024-11-04";
|
||||||
cout << " " << log_message << "\n";
|
cout << " " << log_message << "\n";
|
||||||
cout << " "
|
cout << " "
|
||||||
<< "These tests are part of Android U."
|
<< "These tests are part of Android U."
|
||||||
@@ -227,30 +302,45 @@ TEST_F(OEMCryptoClientTest, VersionNumber) {
|
|||||||
// If any of the following fail, then it is time to update the log message
|
// If any of the following fail, then it is time to update the log message
|
||||||
// above.
|
// above.
|
||||||
EXPECT_EQ(ODK_MAJOR_VERSION, 18);
|
EXPECT_EQ(ODK_MAJOR_VERSION, 18);
|
||||||
EXPECT_EQ(ODK_MINOR_VERSION, 7);
|
EXPECT_EQ(ODK_MINOR_VERSION, 8);
|
||||||
EXPECT_EQ(kCurrentAPI, static_cast<unsigned>(ODK_MAJOR_VERSION));
|
EXPECT_EQ(kCurrentAPI, static_cast<unsigned>(ODK_MAJOR_VERSION));
|
||||||
|
RecordWvProperty("test_major_version", std::to_string(ODK_MAJOR_VERSION));
|
||||||
|
RecordWvProperty("test_minor_version", std::to_string(ODK_MINOR_VERSION));
|
||||||
|
|
||||||
OEMCrypto_Security_Level level = OEMCrypto_SecurityLevel();
|
OEMCrypto_Security_Level level = OEMCrypto_SecurityLevel();
|
||||||
EXPECT_GT(level, OEMCrypto_Level_Unknown);
|
EXPECT_GT(level, OEMCrypto_Level_Unknown);
|
||||||
EXPECT_LE(level, OEMCrypto_Level3);
|
EXPECT_LE(level, OEMCrypto_Level3);
|
||||||
cout << " OEMCrypto Security Level is L" << level << endl;
|
cout << " OEMCrypto Security Level is L" << level << endl;
|
||||||
|
RecordWvProperty("security_level", SecurityLevelName(level));
|
||||||
|
|
||||||
uint32_t version = OEMCrypto_APIVersion();
|
uint32_t version = OEMCrypto_APIVersion();
|
||||||
uint32_t minor_version = OEMCrypto_MinorAPIVersion();
|
uint32_t minor_version = OEMCrypto_MinorAPIVersion();
|
||||||
cout << " OEMCrypto API version is " << version << "."
|
cout << " OEMCrypto API version is " << version << "."
|
||||||
<< minor_version << endl;
|
<< minor_version << endl;
|
||||||
if (OEMCrypto_SupportsUsageTable()) {
|
RecordWvProperty("major_version", std::to_string(version));
|
||||||
|
RecordWvProperty("minor_version", std::to_string(minor_version));
|
||||||
|
|
||||||
|
const bool supports_usage_tables = OEMCrypto_SupportsUsageTable();
|
||||||
|
if (supports_usage_tables) {
|
||||||
cout << " OEMCrypto supports usage tables" << endl;
|
cout << " OEMCrypto supports usage tables" << endl;
|
||||||
} else {
|
} else {
|
||||||
cout << " OEMCrypto does not support usage tables" << endl;
|
cout << " OEMCrypto does not support usage tables" << endl;
|
||||||
}
|
}
|
||||||
|
RecordWvProperty("supports_usage_tables", BoolName(supports_usage_tables));
|
||||||
|
|
||||||
if (version >= 15) {
|
if (version >= 15) {
|
||||||
const uint32_t tier = OEMCrypto_ResourceRatingTier();
|
const uint32_t tier = OEMCrypto_ResourceRatingTier();
|
||||||
cout << " Resource Rating Tier: " << tier << endl;
|
cout << " Resource Rating Tier: " << tier << endl;
|
||||||
|
RecordWvProperty("resource_rating_tier", std::to_string(tier));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version >= 17) {
|
if (version >= 17) {
|
||||||
OEMCryptoResult sts = OEMCrypto_ProductionReady();
|
OEMCryptoResult sts = OEMCrypto_ProductionReady();
|
||||||
if (sts != OEMCrypto_SUCCESS) {
|
if (sts != OEMCrypto_SUCCESS) {
|
||||||
LOGW("Device is not production ready, returns %d", sts);
|
LOGW("Device is not production ready, returns %d", sts);
|
||||||
}
|
}
|
||||||
|
RecordWvProperty("is_production_ready", BoolName(sts == OEMCrypto_SUCCESS));
|
||||||
|
|
||||||
std::string build_info;
|
std::string build_info;
|
||||||
size_t buf_length = 0;
|
size_t buf_length = 0;
|
||||||
sts = OEMCrypto_BuildInformation(&build_info[0], &buf_length);
|
sts = OEMCrypto_BuildInformation(&build_info[0], &buf_length);
|
||||||
@@ -262,6 +352,7 @@ TEST_F(OEMCryptoClientTest, VersionNumber) {
|
|||||||
if (build_info.size() != buf_length) {
|
if (build_info.size() != buf_length) {
|
||||||
build_info.resize(buf_length);
|
build_info.resize(buf_length);
|
||||||
}
|
}
|
||||||
|
RecordWvProperty("build_information", build_info);
|
||||||
const std::string comma = ",";
|
const std::string comma = ",";
|
||||||
const std::string pretty_comma = ",\n ";
|
const std::string pretty_comma = ",\n ";
|
||||||
std::string::size_type pos = 0;
|
std::string::size_type pos = 0;
|
||||||
@@ -270,9 +361,12 @@ TEST_F(OEMCryptoClientTest, VersionNumber) {
|
|||||||
pos += pretty_comma.size();
|
pos += pretty_comma.size();
|
||||||
}
|
}
|
||||||
cout << " BuildInformation: " << build_info << endl;
|
cout << " BuildInformation: " << build_info << endl;
|
||||||
|
|
||||||
OEMCrypto_WatermarkingSupport support = OEMCrypto_GetWatermarkingSupport();
|
OEMCrypto_WatermarkingSupport support = OEMCrypto_GetWatermarkingSupport();
|
||||||
cout << " WatermarkingSupport: " << support << endl;
|
cout << " WatermarkingSupport: " << support << endl;
|
||||||
|
RecordWvProperty("watermarking_support", WatermarkingSupportName(support));
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_GE(version, 8u);
|
ASSERT_GE(version, 8u);
|
||||||
ASSERT_LE(version, kCurrentAPI);
|
ASSERT_LE(version, kCurrentAPI);
|
||||||
}
|
}
|
||||||
@@ -292,8 +386,9 @@ TEST_F(OEMCryptoClientTest, ResourceRatingAPI15) {
|
|||||||
TEST_F(OEMCryptoClientTest, ProvisioningDeclaredAPI12) {
|
TEST_F(OEMCryptoClientTest, ProvisioningDeclaredAPI12) {
|
||||||
OEMCrypto_ProvisioningMethod provisioning_method =
|
OEMCrypto_ProvisioningMethod provisioning_method =
|
||||||
OEMCrypto_GetProvisioningMethod();
|
OEMCrypto_GetProvisioningMethod();
|
||||||
cout << " Provisioning method = "
|
const char* const name = ProvisioningMethodName(provisioning_method);
|
||||||
<< ProvisioningMethodName(provisioning_method) << endl;
|
cout << " Provisioning method = " << name << endl;
|
||||||
|
RecordWvProperty("provisioning_method", name);
|
||||||
ASSERT_NE(OEMCrypto_ProvisioningError, provisioning_method);
|
ASSERT_NE(OEMCrypto_ProvisioningError, provisioning_method);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,6 +401,8 @@ TEST_F(OEMCryptoClientTest, CheckHDCPCapabilityAPI09) {
|
|||||||
static_cast<unsigned int>(current), HDCPCapabilityAsString(current));
|
static_cast<unsigned int>(current), HDCPCapabilityAsString(current));
|
||||||
printf(" Maximum HDCP Capability: 0x%02x = %s.\n",
|
printf(" Maximum HDCP Capability: 0x%02x = %s.\n",
|
||||||
static_cast<unsigned int>(maximum), HDCPCapabilityAsString(maximum));
|
static_cast<unsigned int>(maximum), HDCPCapabilityAsString(maximum));
|
||||||
|
RecordWvProperty("hdcp_current", HDCPCapabilityName(current));
|
||||||
|
RecordWvProperty("hdcp_max", HDCPCapabilityName(maximum));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(OEMCryptoClientTest, CheckSRMCapabilityV13) {
|
TEST_F(OEMCryptoClientTest, CheckSRMCapabilityV13) {
|
||||||
@@ -314,11 +411,15 @@ TEST_F(OEMCryptoClientTest, CheckSRMCapabilityV13) {
|
|||||||
OEMCryptoResult current_result = OEMCrypto_GetCurrentSRMVersion(&version);
|
OEMCryptoResult current_result = OEMCrypto_GetCurrentSRMVersion(&version);
|
||||||
if (current_result == OEMCrypto_SUCCESS) {
|
if (current_result == OEMCrypto_SUCCESS) {
|
||||||
printf(" Current SRM Version: %d.\n", version);
|
printf(" Current SRM Version: %d.\n", version);
|
||||||
|
RecordWvProperty("srm_supported", BoolName(true));
|
||||||
|
RecordWvProperty("srm_version", std::to_string(version));
|
||||||
EXPECT_NE(OEMCrypto_SUCCESS, OEMCrypto_GetCurrentSRMVersion(nullptr));
|
EXPECT_NE(OEMCrypto_SUCCESS, OEMCrypto_GetCurrentSRMVersion(nullptr));
|
||||||
} else if (current_result == OEMCrypto_LOCAL_DISPLAY_ONLY) {
|
} else if (current_result == OEMCrypto_LOCAL_DISPLAY_ONLY) {
|
||||||
printf(" Current SRM Status: Local Display Only.\n");
|
printf(" Current SRM Status: Local Display Only.\n");
|
||||||
|
RecordWvProperty("srm_supported", BoolName(false));
|
||||||
} else {
|
} else {
|
||||||
EXPECT_EQ(OEMCrypto_ERROR_NOT_IMPLEMENTED, current_result);
|
EXPECT_EQ(OEMCrypto_ERROR_NOT_IMPLEMENTED, current_result);
|
||||||
|
RecordWvProperty("srm_supported", BoolName(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -547,6 +648,9 @@ TEST_F(OEMCryptoClientTest, CheckJsonBuildInformationAPI18) {
|
|||||||
{"is_debug", JSMN_PRIMITIVE},
|
{"is_debug", JSMN_PRIMITIVE},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The prefix of every field name when logged to RecordWvProperty.
|
||||||
|
const std::string kBuildInfoRecordPrefix = "build_info_";
|
||||||
|
|
||||||
// A set of the required fields found when examining the
|
// A set of the required fields found when examining the
|
||||||
// build information, use to verify all fields are present.
|
// build information, use to verify all fields are present.
|
||||||
std::set<std::string> found_required_fields;
|
std::set<std::string> found_required_fields;
|
||||||
@@ -573,11 +677,17 @@ TEST_F(OEMCryptoClientTest, CheckJsonBuildInformationAPI18) {
|
|||||||
<< "Unexpected required field type: field = " << key
|
<< "Unexpected required field type: field = " << key
|
||||||
<< ", build_info = " << build_info;
|
<< ", build_info = " << build_info;
|
||||||
found_required_fields.insert(key);
|
found_required_fields.insert(key);
|
||||||
|
RecordWvProperty(kBuildInfoRecordPrefix + key,
|
||||||
|
build_info.substr(value_token.start,
|
||||||
|
value_token.end - value_token.start));
|
||||||
} else if (kOptionalFields.find(key) != kOptionalFields.end()) {
|
} else if (kOptionalFields.find(key) != kOptionalFields.end()) {
|
||||||
ASSERT_EQ(value_token.type, kOptionalFields.at(key))
|
ASSERT_EQ(value_token.type, kOptionalFields.at(key))
|
||||||
<< "Unexpected optional field type: field = " << key
|
<< "Unexpected optional field type: field = " << key
|
||||||
<< ", build_info = " << build_info;
|
<< ", build_info = " << build_info;
|
||||||
} // Do not validate vendor fields.
|
RecordWvProperty(kBuildInfoRecordPrefix + key,
|
||||||
|
build_info.substr(value_token.start,
|
||||||
|
value_token.end - value_token.start));
|
||||||
|
} // Do not validate or record vendor fields.
|
||||||
|
|
||||||
if (key == kSpecialCaseReeKey) {
|
if (key == kSpecialCaseReeKey) {
|
||||||
// Store the tokens of the "ree" field for additional validation.
|
// Store the tokens of the "ree" field for additional validation.
|
||||||
@@ -618,6 +728,11 @@ TEST_F(OEMCryptoClientTest, CheckJsonBuildInformationAPI18) {
|
|||||||
// If no "ree" field tokens, then end here.
|
// If no "ree" field tokens, then end here.
|
||||||
if (!has_ree_info) return;
|
if (!has_ree_info) return;
|
||||||
// Step 4a: Verify "ree" object scheme.
|
// Step 4a: Verify "ree" object scheme.
|
||||||
|
|
||||||
|
// The prefix of every REE field name when logged to RecordWvProperty.
|
||||||
|
const std::string kReeBuildInfoRecordPrefix =
|
||||||
|
kBuildInfoRecordPrefix + kSpecialCaseReeKey + "_";
|
||||||
|
|
||||||
ASSERT_FALSE(ree_tokens.empty())
|
ASSERT_FALSE(ree_tokens.empty())
|
||||||
<< "REE field was specified, but contents were empty: build_info = "
|
<< "REE field was specified, but contents were empty: build_info = "
|
||||||
<< build_info;
|
<< build_info;
|
||||||
@@ -647,7 +762,10 @@ TEST_F(OEMCryptoClientTest, CheckJsonBuildInformationAPI18) {
|
|||||||
<< "Unexpected optional REE field type: ree_field = " << key
|
<< "Unexpected optional REE field type: ree_field = " << key
|
||||||
<< ", build_info = " << build_info;
|
<< ", build_info = " << build_info;
|
||||||
found_required_fields.insert(key);
|
found_required_fields.insert(key);
|
||||||
} // Do not validate vendor fields.
|
RecordWvProperty(kReeBuildInfoRecordPrefix + key,
|
||||||
|
build_info.substr(value_token.start,
|
||||||
|
value_token.end - value_token.start));
|
||||||
|
} // Do not validate or record vendor fields.
|
||||||
|
|
||||||
// Skip potential nested tokens.
|
// Skip potential nested tokens.
|
||||||
i += JsmnAncestorCount(ree_tokens, i + 1);
|
i += JsmnAncestorCount(ree_tokens, i + 1);
|
||||||
@@ -683,6 +801,7 @@ TEST_F(OEMCryptoClientTest, CheckMaxNumberOfSessionsAPI10) {
|
|||||||
OEMCryptoResult sts = OEMCrypto_GetMaxNumberOfSessions(&maximum);
|
OEMCryptoResult sts = OEMCrypto_GetMaxNumberOfSessions(&maximum);
|
||||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||||
printf(" Max Number of Sessions: %zu.\n", maximum);
|
printf(" Max Number of Sessions: %zu.\n", maximum);
|
||||||
|
RecordWvProperty("max_number_of_sessions", std::to_string(maximum));
|
||||||
size_t required_max = GetResourceValue(kMaxConcurrentSession);
|
size_t required_max = GetResourceValue(kMaxConcurrentSession);
|
||||||
ASSERT_GE(maximum, required_max);
|
ASSERT_GE(maximum, required_max);
|
||||||
}
|
}
|
||||||
@@ -690,6 +809,7 @@ TEST_F(OEMCryptoClientTest, CheckMaxNumberOfSessionsAPI10) {
|
|||||||
TEST_F(OEMCryptoClientTest, CheckUsageTableSizeAPI16) {
|
TEST_F(OEMCryptoClientTest, CheckUsageTableSizeAPI16) {
|
||||||
const size_t maximum = OEMCrypto_MaximumUsageTableHeaderSize();
|
const size_t maximum = OEMCrypto_MaximumUsageTableHeaderSize();
|
||||||
printf(" Max Usage Table Size: %zu.\n", maximum);
|
printf(" Max Usage Table Size: %zu.\n", maximum);
|
||||||
|
RecordWvProperty("max_usage_table_size", std::to_string(maximum));
|
||||||
// A maximum of 0 means the table is constrained by dynamic memory allocation.
|
// A maximum of 0 means the table is constrained by dynamic memory allocation.
|
||||||
if (maximum > 0) {
|
if (maximum > 0) {
|
||||||
ASSERT_GE(maximum, RequiredUsageSize());
|
ASSERT_GE(maximum, RequiredUsageSize());
|
||||||
@@ -723,6 +843,7 @@ TEST_F(OEMCryptoClientTest, CheckDTCP2CapabilityAPI17) {
|
|||||||
"DTCP2 is supported.\n");
|
"DTCP2 is supported.\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
RecordWvProperty("dtcp2_capability", DTCP2CapabiityName(capability));
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ class OEMCryptoClientTest : public ::testing::Test, public SessionUtil {
|
|||||||
size_t input_buffer_size,
|
size_t input_buffer_size,
|
||||||
const OEMCrypto_DestBufferDesc* dest_buffer_descriptor,
|
const OEMCrypto_DestBufferDesc* dest_buffer_descriptor,
|
||||||
uint8_t subsample_flags);
|
uint8_t subsample_flags);
|
||||||
|
void RecordWvProperty(const std::string& key, const std::string& value);
|
||||||
};
|
};
|
||||||
} // namespace wvoec
|
} // namespace wvoec
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,13 @@
|
|||||||
|
|
||||||
#include "oemcrypto_cast_test.h"
|
#include "oemcrypto_cast_test.h"
|
||||||
|
|
||||||
#include "oemcrypto_usage_table_test.h"
|
|
||||||
|
|
||||||
using ::testing::Range;
|
using ::testing::Range;
|
||||||
|
|
||||||
namespace wvoec {
|
namespace wvoec {
|
||||||
|
|
||||||
|
/// @addtogroup cast
|
||||||
|
/// @{
|
||||||
|
|
||||||
/** If a device can load a private key with the alternate padding schemes, it
|
/** If a device can load a private key with the alternate padding schemes, it
|
||||||
* should support signing with the alternate scheme. */
|
* should support signing with the alternate scheme. */
|
||||||
TEST_F(OEMCryptoLoadsCertificateAlternates, TestSignaturePKCS1) {
|
TEST_F(OEMCryptoLoadsCertificateAlternates, TestSignaturePKCS1) {
|
||||||
@@ -262,18 +263,8 @@ class OEMCryptoCastReceiverTest : public OEMCryptoLoadsCertificateAlternates {
|
|||||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||||
ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_));
|
ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_));
|
||||||
|
|
||||||
// The application will compute the SHA-1 Hash of the message, so this
|
vector<uint8_t> digest;
|
||||||
// test must do that also.
|
ASSERT_NO_FATAL_FAILURE(PrepareCastDigestedMessage(message, digest));
|
||||||
uint8_t hash[SHA_DIGEST_LENGTH];
|
|
||||||
if (!SHA1(message.data(), message.size(), hash)) {
|
|
||||||
dump_boringssl_error();
|
|
||||||
FAIL() << "boringssl error creating SHA1 hash.";
|
|
||||||
}
|
|
||||||
|
|
||||||
// The application will prepend the digest info to the hash.
|
|
||||||
// SHA-1 digest info prefix = 0x30 0x21 0x30 ...
|
|
||||||
vector<uint8_t> digest = wvutil::a2b_hex("3021300906052b0e03021a05000414");
|
|
||||||
digest.insert(digest.end(), hash, hash + SHA_DIGEST_LENGTH);
|
|
||||||
|
|
||||||
// OEMCrypto will apply the padding, and encrypt to generate the
|
// OEMCrypto will apply the padding, and encrypt to generate the
|
||||||
// signature.
|
// signature.
|
||||||
@@ -1018,4 +1009,6 @@ TEST_P(OEMCryptoSessionTestLoadCasKeysWithHDCP, CasOnlyLoadCasKeysAPI17) {
|
|||||||
}
|
}
|
||||||
INSTANTIATE_TEST_SUITE_P(TestHDCP, OEMCryptoSessionTestLoadCasKeysWithHDCP,
|
INSTANTIATE_TEST_SUITE_P(TestHDCP, OEMCryptoSessionTestLoadCasKeysWithHDCP,
|
||||||
Range(1, 6));
|
Range(1, 6));
|
||||||
|
|
||||||
|
/// @}
|
||||||
} // namespace wvoec
|
} // namespace wvoec
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include "OEMCryptoCENC.h"
|
#include "OEMCryptoCENC.h"
|
||||||
#include "oemcrypto_provisioning_test.h"
|
#include "oemcrypto_provisioning_test.h"
|
||||||
#include "oemcrypto_session_tests_helper.h"
|
#include "oemcrypto_session_tests_helper.h"
|
||||||
|
#include "oemcrypto_usage_table_test.h"
|
||||||
|
|
||||||
namespace wvoec {
|
namespace wvoec {
|
||||||
|
|
||||||
@@ -25,6 +26,25 @@ std::string MaybeHex(const std::vector<uint8_t>& data);
|
|||||||
// This test attempts to use alternate algorithms for loaded device certs.
|
// This test attempts to use alternate algorithms for loaded device certs.
|
||||||
class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate {
|
class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate {
|
||||||
protected:
|
protected:
|
||||||
|
// The message to be signed by OEMCrypto_GenerateRSASignature() starts with a
|
||||||
|
// constant digest info prefix followed by a SHA-1 hash of the message.
|
||||||
|
void PrepareCastDigestedMessage(const std::vector<uint8_t>& message,
|
||||||
|
std::vector<uint8_t>& digest) {
|
||||||
|
// The application will compute the SHA-1 Hash of the message, so this
|
||||||
|
// test must do that also.
|
||||||
|
uint8_t hash[SHA_DIGEST_LENGTH];
|
||||||
|
if (!SHA1(message.data(), message.size(), hash)) {
|
||||||
|
dump_boringssl_error();
|
||||||
|
FAIL() << "boringssl error creating SHA1 hash.";
|
||||||
|
}
|
||||||
|
// The application will prepend the digest info to the hash.
|
||||||
|
// SHA-1 digest info prefix = 0x30 0x21 0x30 ...
|
||||||
|
static const std::vector<uint8_t> prefix =
|
||||||
|
wvutil::a2b_hex("3021300906052b0e03021a05000414");
|
||||||
|
digest.insert(digest.end(), prefix.begin(), prefix.end());
|
||||||
|
digest.insert(digest.end(), hash, hash + SHA_DIGEST_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
void TestSignature(RSA_Padding_Scheme scheme, size_t size) {
|
void TestSignature(RSA_Padding_Scheme scheme, size_t size) {
|
||||||
Session s;
|
Session s;
|
||||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||||
@@ -32,16 +52,19 @@ class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate {
|
|||||||
|
|
||||||
vector<uint8_t> licenseRequest(size);
|
vector<uint8_t> licenseRequest(size);
|
||||||
GetRandBytes(licenseRequest.data(), licenseRequest.size());
|
GetRandBytes(licenseRequest.data(), licenseRequest.size());
|
||||||
|
vector<uint8_t> digested_message;
|
||||||
|
ASSERT_NO_FATAL_FAILURE(
|
||||||
|
PrepareCastDigestedMessage(licenseRequest, digested_message));
|
||||||
size_t signature_length = 0;
|
size_t signature_length = 0;
|
||||||
OEMCryptoResult sts = OEMCrypto_GenerateRSASignature(
|
OEMCryptoResult sts = OEMCrypto_GenerateRSASignature(
|
||||||
s.session_id(), licenseRequest.data(), licenseRequest.size(), nullptr,
|
s.session_id(), digested_message.data(), digested_message.size(),
|
||||||
&signature_length, scheme);
|
nullptr, &signature_length, scheme);
|
||||||
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
|
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
|
||||||
ASSERT_NE(static_cast<size_t>(0), signature_length);
|
ASSERT_NE(static_cast<size_t>(0), signature_length);
|
||||||
|
|
||||||
std::vector<uint8_t> signature(signature_length, 0);
|
std::vector<uint8_t> signature(signature_length, 0);
|
||||||
sts = OEMCrypto_GenerateRSASignature(
|
sts = OEMCrypto_GenerateRSASignature(
|
||||||
s.session_id(), licenseRequest.data(), licenseRequest.size(),
|
s.session_id(), digested_message.data(), digested_message.size(),
|
||||||
signature.data(), &signature_length, scheme);
|
signature.data(), &signature_length, scheme);
|
||||||
|
|
||||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts)
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts)
|
||||||
@@ -51,7 +74,7 @@ class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate {
|
|||||||
ASSERT_NO_FATAL_FAILURE(s.SetRsaPublicKeyFromPrivateKeyInfo(
|
ASSERT_NO_FATAL_FAILURE(s.SetRsaPublicKeyFromPrivateKeyInfo(
|
||||||
encoded_rsa_key_.data(), encoded_rsa_key_.size()));
|
encoded_rsa_key_.data(), encoded_rsa_key_.size()));
|
||||||
ASSERT_NO_FATAL_FAILURE(s.VerifyRsaSignature(
|
ASSERT_NO_FATAL_FAILURE(s.VerifyRsaSignature(
|
||||||
licenseRequest, signature.data(), signature_length, scheme));
|
digested_message, signature.data(), signature_length, scheme));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisallowDeriveKeys() {
|
void DisallowDeriveKeys() {
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ using ::testing::Values;
|
|||||||
|
|
||||||
namespace wvoec {
|
namespace wvoec {
|
||||||
|
|
||||||
|
/// @addtogroup decrypt
|
||||||
|
/// @{
|
||||||
|
|
||||||
// Cannot decrypt without first getting a key handle.
|
// Cannot decrypt without first getting a key handle.
|
||||||
TEST_P(OEMCryptoLicenseTest, FailDecryptWithoutGettingAHandle) {
|
TEST_P(OEMCryptoLicenseTest, FailDecryptWithoutGettingAHandle) {
|
||||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||||
@@ -661,4 +664,5 @@ TEST_P(OEMCryptoLicenseTest, KeyDuration) {
|
|||||||
INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoLicenseTest,
|
INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoLicenseTest,
|
||||||
Range<uint32_t>(kCurrentAPI - 2, kCurrentAPI + 1));
|
Range<uint32_t>(kCurrentAPI - 2, kCurrentAPI + 1));
|
||||||
|
|
||||||
|
/// @}
|
||||||
} // namespace wvoec
|
} // namespace wvoec
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ using ::testing::Range;
|
|||||||
|
|
||||||
namespace wvoec {
|
namespace wvoec {
|
||||||
|
|
||||||
|
/// @addtogroup generic
|
||||||
|
/// @{
|
||||||
|
|
||||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyLoad) { EncryptAndLoadKeys(); }
|
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyLoad) { EncryptAndLoadKeys(); }
|
||||||
|
|
||||||
// Test that the Generic_Encrypt function works correctly.
|
// Test that the Generic_Encrypt function works correctly.
|
||||||
@@ -574,4 +577,4 @@ INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoGenericCryptoKeyIdLengthTest,
|
|||||||
Range<uint32_t>(kCoreMessagesAPI, kCurrentAPI + 1));
|
Range<uint32_t>(kCoreMessagesAPI, kCurrentAPI + 1));
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
} // namespace wvoec
|
} // namespace wvoec
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
#include "oemcrypto_license_test.h"
|
#include "oemcrypto_license_test.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "test_sleep.h"
|
#include "test_sleep.h"
|
||||||
|
|
||||||
@@ -12,6 +14,9 @@ using ::testing::Range;
|
|||||||
|
|
||||||
namespace wvoec {
|
namespace wvoec {
|
||||||
|
|
||||||
|
/// @addtogroup license
|
||||||
|
/// @{
|
||||||
|
|
||||||
// Function to test APIs that expect a buffer length as input
|
// Function to test APIs that expect a buffer length as input
|
||||||
// by passing huge buffer lengths up to end_buffer_length and test that the API
|
// by passing huge buffer lengths up to end_buffer_length and test that the API
|
||||||
// doesn't crash.
|
// doesn't crash.
|
||||||
@@ -758,6 +763,7 @@ TEST_P(OEMCryptoLicenseTest, MaxTotalKeysManySessions) {
|
|||||||
TEST_F(OEMCryptoSessionTests, CheckMinimumPatchLevel) {
|
TEST_F(OEMCryptoSessionTests, CheckMinimumPatchLevel) {
|
||||||
uint8_t patch_level = OEMCrypto_Security_Patch_Level();
|
uint8_t patch_level = OEMCrypto_Security_Patch_Level();
|
||||||
printf(" Current Patch Level: %u.\n", patch_level);
|
printf(" Current Patch Level: %u.\n", patch_level);
|
||||||
|
RecordWvProperty("security_patch_level", std::to_string(patch_level));
|
||||||
{
|
{
|
||||||
Session s;
|
Session s;
|
||||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||||
|
|||||||
@@ -5,6 +5,10 @@
|
|||||||
|
|
||||||
#include "oemcrypto_provisioning_test.h"
|
#include "oemcrypto_provisioning_test.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "oec_device_features.h"
|
#include "oec_device_features.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
@@ -12,6 +16,9 @@
|
|||||||
|
|
||||||
namespace wvoec {
|
namespace wvoec {
|
||||||
|
|
||||||
|
/// @addtogroup provision
|
||||||
|
/// @{
|
||||||
|
|
||||||
// This test is used to print the device ID to stdout.
|
// This test is used to print the device ID to stdout.
|
||||||
TEST_F(OEMCryptoKeyboxTest, NormalGetDeviceId) {
|
TEST_F(OEMCryptoKeyboxTest, NormalGetDeviceId) {
|
||||||
OEMCryptoResult sts;
|
OEMCryptoResult sts;
|
||||||
@@ -21,6 +28,7 @@ TEST_F(OEMCryptoKeyboxTest, NormalGetDeviceId) {
|
|||||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||||
cout << " NormalGetDeviceId: dev_id = "
|
cout << " NormalGetDeviceId: dev_id = "
|
||||||
<< MaybeHex(dev_id, dev_id_len) << " len = " << dev_id_len << endl;
|
<< MaybeHex(dev_id, dev_id_len) << " len = " << dev_id_len << endl;
|
||||||
|
RecordWvProperty("device_id", wvutil::HexEncode(dev_id, dev_id_len));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(OEMCryptoKeyboxTest, GetDeviceIdShortBuffer) {
|
TEST_F(OEMCryptoKeyboxTest, GetDeviceIdShortBuffer) {
|
||||||
@@ -50,8 +58,12 @@ TEST_F(OEMCryptoKeyboxTest, NormalGetKeyData) {
|
|||||||
sts = OEMCrypto_GetKeyData(key_data, &key_data_len);
|
sts = OEMCrypto_GetKeyData(key_data, &key_data_len);
|
||||||
|
|
||||||
uint32_t* data = reinterpret_cast<uint32_t*>(key_data);
|
uint32_t* data = reinterpret_cast<uint32_t*>(key_data);
|
||||||
|
const uint32_t system_id = htonl(data[1]);
|
||||||
|
const uint32_t version = htonl(data[0]);
|
||||||
printf(" NormalGetKeyData: system_id = %u = 0x%04X, version=%u\n",
|
printf(" NormalGetKeyData: system_id = %u = 0x%04X, version=%u\n",
|
||||||
htonl(data[1]), htonl(data[1]), htonl(data[0]));
|
system_id, system_id, version);
|
||||||
|
RecordWvProperty("system_id", std::to_string(system_id));
|
||||||
|
RecordWvProperty("key_data_version", std::to_string(version));
|
||||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,6 +118,8 @@ TEST_F(OEMCryptoProv30Test, GetDeviceId) {
|
|||||||
dev_id.resize(dev_id_len);
|
dev_id.resize(dev_id_len);
|
||||||
cout << " NormalGetDeviceId: dev_id = " << MaybeHex(dev_id)
|
cout << " NormalGetDeviceId: dev_id = " << MaybeHex(dev_id)
|
||||||
<< " len = " << dev_id_len << endl;
|
<< " len = " << dev_id_len << endl;
|
||||||
|
RecordWvProperty("device_id",
|
||||||
|
wvutil::HexEncode(dev_id.data(), dev_id.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// The OEM certificate must be valid.
|
// The OEM certificate must be valid.
|
||||||
@@ -545,13 +559,13 @@ TEST_F(OEMCryptoProv40Test, InstallOemPrivateKeyCanBeUsed) {
|
|||||||
wrapped_private_key2.resize(wrapped_private_key_size2);
|
wrapped_private_key2.resize(wrapped_private_key_size2);
|
||||||
|
|
||||||
// Verify public_key_signature2 with public_key1.
|
// Verify public_key_signature2 with public_key1.
|
||||||
if (key_type2 == OEMCrypto_PrivateKeyType::OEMCrypto_RSA_Private_Key) {
|
if (key_type1 == OEMCrypto_PrivateKeyType::OEMCrypto_RSA_Private_Key) {
|
||||||
ASSERT_NO_FATAL_FAILURE(s.SetRsaPublicKeyFromSubjectPublicKey(
|
ASSERT_NO_FATAL_FAILURE(s.SetRsaPublicKeyFromSubjectPublicKey(
|
||||||
public_key1.data(), public_key1.size()));
|
public_key1.data(), public_key1.size()));
|
||||||
ASSERT_NO_FATAL_FAILURE(
|
ASSERT_NO_FATAL_FAILURE(
|
||||||
s.VerifyRsaSignature(public_key2, public_key_signature2.data(),
|
s.VerifyRsaSignature(public_key2, public_key_signature2.data(),
|
||||||
public_key_signature2.size(), kSign_RSASSA_PSS));
|
public_key_signature2.size(), kSign_RSASSA_PSS));
|
||||||
} else if (key_type2 == OEMCrypto_PrivateKeyType::OEMCrypto_ECC_Private_Key) {
|
} else if (key_type1 == OEMCrypto_PrivateKeyType::OEMCrypto_ECC_Private_Key) {
|
||||||
ASSERT_NO_FATAL_FAILURE(s.SetEccPublicKeyFromSubjectPublicKey(
|
ASSERT_NO_FATAL_FAILURE(s.SetEccPublicKeyFromSubjectPublicKey(
|
||||||
public_key1.data(), public_key1.size()));
|
public_key1.data(), public_key1.size()));
|
||||||
ASSERT_NO_FATAL_FAILURE(s.VerifyEccSignature(public_key2,
|
ASSERT_NO_FATAL_FAILURE(s.VerifyEccSignature(public_key2,
|
||||||
@@ -619,6 +633,8 @@ TEST_F(OEMCryptoProv40Test, GetDeviceId) {
|
|||||||
dev_id.resize(dev_id_len);
|
dev_id.resize(dev_id_len);
|
||||||
cout << " NormalGetDeviceId: dev_id = " << MaybeHex(dev_id)
|
cout << " NormalGetDeviceId: dev_id = " << MaybeHex(dev_id)
|
||||||
<< " len = " << dev_id_len << endl;
|
<< " len = " << dev_id_len << endl;
|
||||||
|
RecordWvProperty("device_id",
|
||||||
|
wvutil::HexEncode(dev_id.data(), dev_id.size()));
|
||||||
// Device id should be stable. Query again.
|
// Device id should be stable. Query again.
|
||||||
std::vector<uint8_t> dev_id2(dev_id_len);
|
std::vector<uint8_t> dev_id2(dev_id_len);
|
||||||
sts = OEMCrypto_GetDeviceID(dev_id2.data(), &dev_id_len);
|
sts = OEMCrypto_GetDeviceID(dev_id2.data(), &dev_id_len);
|
||||||
@@ -1310,4 +1326,5 @@ TEST_F(OEMCryptoUsesCertificate, GenerateDerivedKeysLargeBuffer) {
|
|||||||
enc_context.data(), enc_context.size()));
|
enc_context.data(), enc_context.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
} // namespace wvoec
|
} // namespace wvoec
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -21,6 +21,9 @@
|
|||||||
|
|
||||||
namespace wvoec {
|
namespace wvoec {
|
||||||
|
|
||||||
|
/// @addtogroup android
|
||||||
|
/// @{
|
||||||
|
|
||||||
// These tests are required for LollyPop Android devices.
|
// These tests are required for LollyPop Android devices.
|
||||||
class OEMCryptoAndroidLMPTest : public ::testing::Test {
|
class OEMCryptoAndroidLMPTest : public ::testing::Test {
|
||||||
protected:
|
protected:
|
||||||
@@ -174,4 +177,5 @@ TEST_F(OEMCryptoAndroidQTest, MinVersionNumber14) {
|
|||||||
ASSERT_GE(version, 15u);
|
ASSERT_GE(version, 15u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
} // namespace wvoec
|
} // namespace wvoec
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
'oemcrypto_generic_crypto_test.cpp',
|
'oemcrypto_generic_crypto_test.cpp',
|
||||||
'oemcrypto_license_test.cpp',
|
'oemcrypto_license_test.cpp',
|
||||||
'oemcrypto_provisioning_test.cpp',
|
'oemcrypto_provisioning_test.cpp',
|
||||||
|
'oemcrypto_security_test.cpp',
|
||||||
'oemcrypto_usage_table_test.cpp',
|
'oemcrypto_usage_table_test.cpp',
|
||||||
'oemcrypto_test.cpp',
|
'oemcrypto_test.cpp',
|
||||||
'<(jsmn_dir)/jsmn.c',
|
'<(jsmn_dir)/jsmn.c',
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ using ::testing::Values;
|
|||||||
|
|
||||||
namespace wvoec {
|
namespace wvoec {
|
||||||
|
|
||||||
|
/// @addtogroup usage_table
|
||||||
|
/// @{
|
||||||
|
|
||||||
// Test that successive calls to PrepAndSignProvisioningRequest only increase
|
// Test that successive calls to PrepAndSignProvisioningRequest only increase
|
||||||
// the provisioning count in the ODK message
|
// the provisioning count in the ODK message
|
||||||
TEST_F(OEMCryptoSessionTests, Provisioning_IncrementCounterAPI18) {
|
TEST_F(OEMCryptoSessionTests, Provisioning_IncrementCounterAPI18) {
|
||||||
@@ -1757,4 +1760,5 @@ INSTANTIATE_TEST_SUITE_P(TestAPI16, OEMCryptoUsageTableDefragTest,
|
|||||||
INSTANTIATE_TEST_SUITE_P(TestAPI16, OEMCryptoUsageTableTestWallClock,
|
INSTANTIATE_TEST_SUITE_P(TestAPI16, OEMCryptoUsageTableTestWallClock,
|
||||||
Values<uint32_t>(kCurrentAPI));
|
Values<uint32_t>(kCurrentAPI));
|
||||||
|
|
||||||
|
/// @}
|
||||||
} // namespace wvoec
|
} // namespace wvoec
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
#ifndef WVCDM_UTIL_FILE_STORE_H_
|
#ifndef WVCDM_UTIL_FILE_STORE_H_
|
||||||
#define WVCDM_UTIL_FILE_STORE_H_
|
#define WVCDM_UTIL_FILE_STORE_H_
|
||||||
|
|
||||||
#include <cstdint>
|
#include <stddef.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -18,16 +19,35 @@
|
|||||||
|
|
||||||
namespace wvutil {
|
namespace wvutil {
|
||||||
|
|
||||||
|
// Fixed filename for ATSC DRM certificate pre-installed
|
||||||
|
// on ATSC devices for ATSC licenses.
|
||||||
static const std::string kAtscCertificateFileName = "atsccert.bin";
|
static const std::string kAtscCertificateFileName = "atsccert.bin";
|
||||||
|
// General filename for either global or unmapped app-origin
|
||||||
|
// DRM certificates.
|
||||||
static const std::string kCertificateFileName = "cert1.bin";
|
static const std::string kCertificateFileName = "cert1.bin";
|
||||||
|
// File extension for DRM and OEM certificate files.
|
||||||
static const std::string kCertificateFileNameExt = ".bin";
|
static const std::string kCertificateFileNameExt = ".bin";
|
||||||
static const std::string kCertificateFileNamePrefix = "cert1_";
|
// Filename prefix for mapped (scoped) DRM certificate filenames
|
||||||
|
// specific to a particular app-origin.
|
||||||
|
static const std::string kScopedCertificateFilenamePrefix = "cert1_";
|
||||||
|
// TODO(b/376533901): Replace this constant with
|
||||||
|
// kScopedCertificateFilenamePrefix in source code..
|
||||||
|
static const std::string kCertificateFileNamePrefix =
|
||||||
|
kScopedCertificateFilenamePrefix;
|
||||||
|
// Legacy general filename for either global or unmapped app-origin
|
||||||
|
// DRM certificates.
|
||||||
static const std::string kLegacyCertificateFileName = "cert.bin";
|
static const std::string kLegacyCertificateFileName = "cert.bin";
|
||||||
static const std::string kLegacyCertificateFileNamePrefix = "cert";
|
// Legacy filename prefix for mapped (scoped) DRM certificate filenames
|
||||||
|
// specific to a particular app-origin.
|
||||||
|
static const std::string kLegacyScopedCertificateFilenamePrefix = "cert";
|
||||||
|
// TODO(b/376533901): Replace this constant with
|
||||||
|
// kLegacyScopedCertificateFilenamePrefix in source code..
|
||||||
|
static const std::string kLegacyCertificateFileNamePrefix =
|
||||||
|
kLegacyScopedCertificateFilenamePrefix;
|
||||||
|
// Filename for global OEM certificates.
|
||||||
static const std::string kOemCertificateFileName = "oemcert.bin";
|
static const std::string kOemCertificateFileName = "oemcert.bin";
|
||||||
static const std::string kOemCertificateFileNamePrefix = "oemcert_";
|
|
||||||
|
|
||||||
// File class. The implementation is platform dependent.
|
// File interface. The implementation is platform dependent.
|
||||||
class File {
|
class File {
|
||||||
public:
|
public:
|
||||||
File() {}
|
File() {}
|
||||||
@@ -35,35 +55,70 @@ class File {
|
|||||||
virtual ssize_t Read(char* buffer, size_t bytes) = 0;
|
virtual ssize_t Read(char* buffer, size_t bytes) = 0;
|
||||||
virtual ssize_t Write(const char* buffer, size_t bytes) = 0;
|
virtual ssize_t Write(const char* buffer, size_t bytes) = 0;
|
||||||
|
|
||||||
friend class FileSystem;
|
|
||||||
CORE_DISALLOW_COPY_AND_ASSIGN(File);
|
CORE_DISALLOW_COPY_AND_ASSIGN(File);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// File system base class. The implementation is platform dependent.
|
||||||
class FileSystem {
|
class FileSystem {
|
||||||
public:
|
public:
|
||||||
FileSystem();
|
FileSystem();
|
||||||
FileSystem(const std::string& origin, void* extra_data);
|
FileSystem(const std::string& origin, void* extra_data);
|
||||||
virtual ~FileSystem();
|
virtual ~FileSystem();
|
||||||
|
|
||||||
|
// Concreate implementation of FileSystem.
|
||||||
|
// Depending on the platform, this may be vendor or Widevine implemented.
|
||||||
class Impl;
|
class Impl;
|
||||||
|
|
||||||
// defines as bit flag
|
// Flags for calls to Open.
|
||||||
enum OpenFlags {
|
static constexpr int kNoFlags = 0;
|
||||||
kNoFlags = 0,
|
// Create file if does not already exist, open file if it does exist.
|
||||||
kCreate = 1,
|
static constexpr int kCreate = (1 << 0);
|
||||||
kReadOnly = 2, // defaults to read and write access
|
// Open file as read-only; typically should not be used with kCreate.
|
||||||
kTruncate = 4
|
static constexpr int kReadOnly = (1 << 1);
|
||||||
};
|
// Open file and truncated. May be used with kCreate; should not
|
||||||
|
// be used with kReadOnly.
|
||||||
|
static constexpr int kTruncate = (1 << 2);
|
||||||
|
|
||||||
virtual std::unique_ptr<File> Open(const std::string& file_path, int flags);
|
virtual std::unique_ptr<File> Open(const std::string& file_path, int flags);
|
||||||
|
|
||||||
virtual bool Exists(const std::string& file_path);
|
// Checks if the |path| exists. The |path| may be a file or directory.
|
||||||
virtual bool Exists(const std::string& file_path, int* errno_value);
|
// Return true if an entry in the file system exists; false otherwise.
|
||||||
virtual bool Remove(const std::string& file_path);
|
virtual bool Exists(const std::string& path);
|
||||||
|
// Same as above, except the optional parameter of |errno_value| should
|
||||||
|
// be set to 0 or the value of C errno when attempting to check
|
||||||
|
// the existence of a file.
|
||||||
|
virtual bool Exists(const std::string& path, int* errno_value);
|
||||||
|
|
||||||
|
// Removes the specified |path|.
|
||||||
|
//
|
||||||
|
// If |path| is a regular file, the file should be removed.
|
||||||
|
// If |path| is a directory, both the directory and the directory
|
||||||
|
// contents should be removed.
|
||||||
|
//
|
||||||
|
// Implementation must support a |path| containing a single wildcard
|
||||||
|
// character in the filename component of the path.
|
||||||
|
//
|
||||||
|
// Return value:
|
||||||
|
// - true : File/directory was removed, or file/directory did not exist
|
||||||
|
// - false : File/directory could not be removed, or other error.
|
||||||
|
virtual bool Remove(const std::string& path);
|
||||||
|
|
||||||
|
// Obtain the size of a file in bytes. |file_path| must be a file,
|
||||||
|
// and not a directory.
|
||||||
|
//
|
||||||
|
// Return value:
|
||||||
|
// - non-negative : size of file in bytes if file exists
|
||||||
|
// - negative : file does not exist, or error occurred.
|
||||||
virtual ssize_t FileSize(const std::string& file_path);
|
virtual ssize_t FileSize(const std::string& file_path);
|
||||||
|
|
||||||
// Return the filenames stored at dir_path.
|
// Return the entries stored at |dir_path| (includes both files
|
||||||
// dir_path will be stripped from the returned names.
|
// and directories).
|
||||||
|
//
|
||||||
|
// Return value:
|
||||||
|
// - true : Directory exists, and directory entry names are stored
|
||||||
|
// in |names|; |names| may be empty if directory was empty.
|
||||||
|
// - false : Directory does not exist, |dir_path| is not a directory,
|
||||||
|
// or error was encountered.
|
||||||
virtual bool List(const std::string& dir_path,
|
virtual bool List(const std::string& dir_path,
|
||||||
std::vector<std::string>* names);
|
std::vector<std::string>* names);
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
|
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
|
||||||
// source code may only be used and distributed under the Widevine License
|
// source code may only be used and distributed under the Widevine License
|
||||||
// Agreement.
|
// Agreement.
|
||||||
|
|
||||||
#include "file_store.h"
|
#include "file_store.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <gmock/gmock.h>
|
#include <gmock/gmock.h>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
@@ -11,18 +16,20 @@
|
|||||||
#include "test_vectors.h"
|
#include "test_vectors.h"
|
||||||
|
|
||||||
namespace wvutil {
|
namespace wvutil {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const std::string kTestDirName = "test_dir";
|
constexpr char kTestFilename[] = "sample.txt";
|
||||||
const std::string kTestFileName = "test.txt";
|
|
||||||
const std::string kTestFileName2 = "test2.txt";
|
constexpr char kTestIdentifier1[] = "some_identifier";
|
||||||
const std::string kTestFileName3 = "test3.other";
|
constexpr char kTestIdentifier2[] = "some_other_identifier";
|
||||||
const std::string kTestFileNameExt = ".txt";
|
|
||||||
const std::string kTestFileNameExt3 = ".other";
|
constexpr int kNoError = 0;
|
||||||
const std::string kTestIdentifier1 = "some_identifier";
|
constexpr int kEntryDoesNotExist = ENOENT;
|
||||||
const std::string kTestIdentifier2 = "some_other_identifier";
|
|
||||||
const std::string kWildcard = "*";
|
bool StartsWith(const std::string& haystack, const std::string& needle) {
|
||||||
const std::string kUnderscore = "_";
|
if (needle.empty()) return true;
|
||||||
|
if (haystack.size() < needle.size()) return false;
|
||||||
|
return haystack.find(needle) == 0;
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
class FileTest : public testing::Test {
|
class FileTest : public testing::Test {
|
||||||
@@ -32,7 +39,19 @@ class FileTest : public testing::Test {
|
|||||||
void TearDown() override { RemoveTestDir(); }
|
void TearDown() override { RemoveTestDir(); }
|
||||||
|
|
||||||
void RemoveTestDir() {
|
void RemoveTestDir() {
|
||||||
EXPECT_TRUE(file_system_.Remove(wvcdm::test_vectors::kTestDir));
|
ASSERT_TRUE(file_system_.Remove(wvcdm::test_vectors::kTestDir))
|
||||||
|
<< "Failed to update test directory: " << wvcdm::test_vectors::kTestDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PathJoin(const std::string& base_path,
|
||||||
|
const std::string& add_path) {
|
||||||
|
if (base_path.empty()) return add_path;
|
||||||
|
std::string path = base_path;
|
||||||
|
if (path.back() != '/') {
|
||||||
|
path.push_back('/');
|
||||||
|
}
|
||||||
|
path.append(add_path);
|
||||||
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileSystem file_system_;
|
FileSystem file_system_;
|
||||||
@@ -40,336 +59,505 @@ class FileTest : public testing::Test {
|
|||||||
|
|
||||||
TEST_F(FileTest, FileExists) {
|
TEST_F(FileTest, FileExists) {
|
||||||
int errno_value = -1;
|
int errno_value = -1;
|
||||||
EXPECT_TRUE(file_system_.Exists(wvcdm::test_vectors::kExistentFile));
|
EXPECT_TRUE(file_system_.Exists(wvcdm::test_vectors::kExistentFile))
|
||||||
|
<< "path = " << wvcdm::test_vectors::kExistentFile;
|
||||||
EXPECT_TRUE(
|
EXPECT_TRUE(
|
||||||
file_system_.Exists(wvcdm::test_vectors::kExistentFile, &errno_value));
|
file_system_.Exists(wvcdm::test_vectors::kExistentFile, &errno_value))
|
||||||
EXPECT_EQ(0, errno_value);
|
<< "path = " << wvcdm::test_vectors::kExistentFile;
|
||||||
EXPECT_TRUE(file_system_.Exists(wvcdm::test_vectors::kExistentDir));
|
EXPECT_EQ(kNoError, errno_value);
|
||||||
|
}
|
||||||
|
|
||||||
EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kNonExistentFile));
|
TEST_F(FileTest, FileDoesNotExist) {
|
||||||
|
int errno_value = -1;
|
||||||
|
EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kNonExistentFile))
|
||||||
|
<< "path = " << wvcdm::test_vectors::kNonExistentFile;
|
||||||
EXPECT_FALSE(
|
EXPECT_FALSE(
|
||||||
file_system_.Exists(wvcdm::test_vectors::kNonExistentFile, &errno_value));
|
file_system_.Exists(wvcdm::test_vectors::kNonExistentFile, &errno_value))
|
||||||
EXPECT_EQ(ENOENT, errno_value);
|
<< "path = " << wvcdm::test_vectors::kNonExistentFile;
|
||||||
EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kNonExistentDir));
|
EXPECT_EQ(kEntryDoesNotExist, errno_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FileTest, DirectoryExists) {
|
||||||
|
int errno_value = -1;
|
||||||
|
EXPECT_TRUE(file_system_.Exists(wvcdm::test_vectors::kExistentDir))
|
||||||
|
<< "path = " << wvcdm::test_vectors::kExistentDir;
|
||||||
|
EXPECT_TRUE(
|
||||||
|
file_system_.Exists(wvcdm::test_vectors::kExistentDir, &errno_value))
|
||||||
|
<< "path = " << wvcdm::test_vectors::kExistentDir;
|
||||||
|
EXPECT_EQ(kNoError, errno_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FileTest, DirectoryDoesNotExist) {
|
||||||
|
int errno_value = -1;
|
||||||
|
EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kNonExistentDir))
|
||||||
|
<< "path = " << wvcdm::test_vectors::kNonExistentDir;
|
||||||
|
EXPECT_FALSE(
|
||||||
|
file_system_.Exists(wvcdm::test_vectors::kNonExistentDir, &errno_value))
|
||||||
|
<< "path = " << wvcdm::test_vectors::kNonExistentDir;
|
||||||
|
EXPECT_EQ(kEntryDoesNotExist, errno_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FileTest, RemoveDir) {
|
TEST_F(FileTest, RemoveDir) {
|
||||||
EXPECT_TRUE(file_system_.Remove(wvcdm::test_vectors::kTestDir));
|
EXPECT_TRUE(file_system_.Remove(wvcdm::test_vectors::kTestDir))
|
||||||
EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kTestDir));
|
<< "path = " << wvcdm::test_vectors::kTestDir;
|
||||||
|
EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kTestDir))
|
||||||
|
<< "path = " << wvcdm::test_vectors::kTestDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FileTest, OpenFile) {
|
TEST_F(FileTest, OpenFile) {
|
||||||
std::string path = wvcdm::test_vectors::kTestDir + kTestFileName;
|
const std::string path =
|
||||||
EXPECT_TRUE(file_system_.Remove(path));
|
PathJoin(wvcdm::test_vectors::kTestDir, kTestFilename);
|
||||||
|
EXPECT_TRUE(file_system_.Remove(path)) << "path = " << path;
|
||||||
|
|
||||||
std::unique_ptr<File> file = file_system_.Open(path, FileSystem::kCreate);
|
std::unique_ptr<File> file = file_system_.Open(path, FileSystem::kCreate);
|
||||||
ASSERT_TRUE(file);
|
ASSERT_TRUE(file) << "Failed to create file: " << path;
|
||||||
|
|
||||||
EXPECT_TRUE(file_system_.Exists(path));
|
EXPECT_TRUE(file_system_.Exists(path)) << "path = " << path;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FileTest, RemoveDirAndFile) {
|
TEST_F(FileTest, RemoveDirAndFile) {
|
||||||
std::string path = wvcdm::test_vectors::kTestDir + kTestFileName;
|
const std::string path =
|
||||||
|
PathJoin(wvcdm::test_vectors::kTestDir, kTestFilename);
|
||||||
|
|
||||||
std::unique_ptr<File> file = file_system_.Open(path, FileSystem::kCreate);
|
std::unique_ptr<File> file = file_system_.Open(path, FileSystem::kCreate);
|
||||||
ASSERT_TRUE(file);
|
ASSERT_TRUE(file) << "Failed to create file: " << path;
|
||||||
|
|
||||||
EXPECT_TRUE(file_system_.Exists(path));
|
EXPECT_TRUE(file_system_.Exists(path)) << "path = " << path;
|
||||||
EXPECT_TRUE(file_system_.Remove(path));
|
EXPECT_TRUE(file_system_.Remove(path)) << "path = " << path;
|
||||||
EXPECT_FALSE(file_system_.Exists(path));
|
EXPECT_FALSE(file_system_.Exists(path)) << "path = " << path;
|
||||||
|
|
||||||
file = file_system_.Open(path, FileSystem::kCreate);
|
file = file_system_.Open(path, FileSystem::kCreate);
|
||||||
ASSERT_TRUE(file);
|
ASSERT_TRUE(file) << "Failed to create file: " << path;
|
||||||
|
|
||||||
EXPECT_TRUE(file_system_.Exists(path));
|
EXPECT_TRUE(file_system_.Exists(path)) << "path = " << path;
|
||||||
RemoveTestDir();
|
ASSERT_NO_FATAL_FAILURE(RemoveTestDir());
|
||||||
EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kTestDir));
|
EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kTestDir))
|
||||||
EXPECT_FALSE(file_system_.Exists(path));
|
<< "path = " << path;
|
||||||
|
EXPECT_FALSE(file_system_.Exists(path)) << "path = " << path;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FileTest, RemoveWildcardFiles) {
|
TEST_F(FileTest, RemoveWildcardFiles) {
|
||||||
std::string path1 = wvcdm::test_vectors::kTestDir + kTestFileName;
|
const std::string path1 =
|
||||||
std::string path2 = wvcdm::test_vectors::kTestDir + kTestFileName2;
|
PathJoin(wvcdm::test_vectors::kTestDir, "first.txt");
|
||||||
std::string wildcard_path =
|
const std::string path2 =
|
||||||
wvcdm::test_vectors::kTestDir + kWildcard + kTestFileNameExt;
|
PathJoin(wvcdm::test_vectors::kTestDir, "second.txt");
|
||||||
|
const std::string wildcard_path =
|
||||||
|
PathJoin(wvcdm::test_vectors::kTestDir, "*.txt");
|
||||||
|
|
||||||
std::unique_ptr<File> file = file_system_.Open(path1, FileSystem::kCreate);
|
std::unique_ptr<File> file = file_system_.Open(path1, FileSystem::kCreate);
|
||||||
ASSERT_TRUE(file);
|
ASSERT_TRUE(file) << "Failed to create file (1): " << path1;
|
||||||
file = file_system_.Open(path2, FileSystem::kCreate);
|
file = file_system_.Open(path2, FileSystem::kCreate);
|
||||||
ASSERT_TRUE(file);
|
ASSERT_TRUE(file) << "Failed to create file (2): " << path2;
|
||||||
|
|
||||||
EXPECT_TRUE(file_system_.Exists(path1));
|
EXPECT_TRUE(file_system_.Exists(path1)) << "path = " << path1;
|
||||||
EXPECT_TRUE(file_system_.Exists(path2));
|
EXPECT_TRUE(file_system_.Exists(path2)) << "path = " << path2;
|
||||||
EXPECT_TRUE(file_system_.Remove(wildcard_path));
|
EXPECT_TRUE(file_system_.Remove(wildcard_path))
|
||||||
EXPECT_FALSE(file_system_.Exists(path1));
|
<< "wildcard_path = " << wildcard_path;
|
||||||
EXPECT_FALSE(file_system_.Exists(path2));
|
EXPECT_FALSE(file_system_.Exists(path1)) << "path = " << path1;
|
||||||
|
EXPECT_FALSE(file_system_.Exists(path2)) << "path = " << path2;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FileTest, FileSize) {
|
TEST_F(FileTest, FileSize) {
|
||||||
std::string path = wvcdm::test_vectors::kTestDir + kTestFileName;
|
const std::string path =
|
||||||
|
PathJoin(wvcdm::test_vectors::kTestDir, kTestFilename);
|
||||||
file_system_.Remove(path);
|
file_system_.Remove(path);
|
||||||
|
|
||||||
std::string write_data = CdmRandom::RandomData(600);
|
constexpr size_t kDataSize = 600;
|
||||||
size_t write_data_size = write_data.size();
|
const std::string write_data = CdmRandom::RandomData(kDataSize);
|
||||||
std::unique_ptr<File> file = file_system_.Open(path, FileSystem::kCreate);
|
ASSERT_EQ(write_data.size(), kDataSize);
|
||||||
ASSERT_TRUE(file);
|
|
||||||
EXPECT_EQ(file->Write(write_data.data(), write_data_size), write_data_size);
|
|
||||||
EXPECT_TRUE(file_system_.Exists(path));
|
|
||||||
|
|
||||||
EXPECT_EQ(static_cast<ssize_t>(write_data_size), file_system_.FileSize(path));
|
std::unique_ptr<File> file = file_system_.Open(path, FileSystem::kCreate);
|
||||||
|
ASSERT_TRUE(file) << "Failed to create file: " << path;
|
||||||
|
|
||||||
|
EXPECT_EQ(file->Write(write_data.data(), write_data.size()),
|
||||||
|
write_data.size());
|
||||||
|
file.reset(); // Close file.
|
||||||
|
|
||||||
|
EXPECT_TRUE(file_system_.Exists(path)) << "path = " << path;
|
||||||
|
|
||||||
|
EXPECT_EQ(static_cast<ssize_t>(kDataSize), file_system_.FileSize(path))
|
||||||
|
<< "path = " << path;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FileTest, WriteReadBinaryFile) {
|
TEST_F(FileTest, WriteReadBinaryFile) {
|
||||||
std::string path = wvcdm::test_vectors::kTestDir + kTestFileName;
|
const std::string path =
|
||||||
|
PathJoin(wvcdm::test_vectors::kTestDir, kTestFilename);
|
||||||
file_system_.Remove(path);
|
file_system_.Remove(path);
|
||||||
|
|
||||||
std::string write_data = CdmRandom::RandomData(600);
|
constexpr size_t kDataSize = 600;
|
||||||
size_t write_data_size = write_data.size();
|
const std::string write_data = CdmRandom::RandomData(kDataSize);
|
||||||
std::unique_ptr<File> file = file_system_.Open(path, FileSystem::kCreate);
|
ASSERT_EQ(write_data.size(), kDataSize);
|
||||||
ASSERT_TRUE(file);
|
|
||||||
EXPECT_EQ(file->Write(write_data.data(), write_data_size), write_data_size);
|
std::unique_ptr<File> file = file_system_.Open(path, FileSystem::kCreate);
|
||||||
EXPECT_TRUE(file_system_.Exists(path));
|
ASSERT_TRUE(file) << "Failed to create file: " << path;
|
||||||
|
|
||||||
|
constexpr ssize_t kExpectedFileSizeResult = static_cast<ssize_t>(kDataSize);
|
||||||
|
EXPECT_EQ(file->Write(write_data.data(), write_data.size()),
|
||||||
|
kExpectedFileSizeResult)
|
||||||
|
<< "path = " << path;
|
||||||
|
file.reset(); // Close file.
|
||||||
|
|
||||||
|
EXPECT_TRUE(file_system_.Exists(path)) << "path = " << path;
|
||||||
|
|
||||||
std::string read_data;
|
|
||||||
read_data.resize(file_system_.FileSize(path));
|
|
||||||
size_t read_data_size = read_data.size();
|
|
||||||
file = file_system_.Open(path, FileSystem::kReadOnly);
|
file = file_system_.Open(path, FileSystem::kReadOnly);
|
||||||
ASSERT_TRUE(file);
|
ASSERT_TRUE(file) << "Failed to re-open file: " << path;
|
||||||
EXPECT_EQ(file->Read(&read_data[0], read_data_size), read_data_size);
|
|
||||||
|
std::string read_data(kDataSize, '\0');
|
||||||
|
;
|
||||||
|
ASSERT_EQ(file->Read(&read_data[0], read_data.size()),
|
||||||
|
kExpectedFileSizeResult)
|
||||||
|
<< "path = " << path;
|
||||||
EXPECT_EQ(write_data, read_data);
|
EXPECT_EQ(write_data, read_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FileTest, ListFiles) {
|
TEST_F(FileTest, ListFiles) {
|
||||||
std::vector<std::string> names;
|
const std::string kTxtFilename1 = "data.txt";
|
||||||
|
const std::string kTxtFilename2 = "other.txt";
|
||||||
|
const std::string kBinFilename = "sample.bin";
|
||||||
|
|
||||||
std::string not_path("zzz");
|
const std::string dir_path = wvcdm::test_vectors::kTestDir;
|
||||||
std::string path1 = wvcdm::test_vectors::kTestDir + kTestFileName;
|
const std::string path1 = PathJoin(dir_path, kTxtFilename1);
|
||||||
std::string path2 = wvcdm::test_vectors::kTestDir + kTestFileName2;
|
const std::string path2 = PathJoin(dir_path, kTxtFilename2);
|
||||||
std::string path3 = wvcdm::test_vectors::kTestDir + kTestFileName3;
|
const std::string path3 = PathJoin(dir_path, kBinFilename);
|
||||||
std::string path_dir = wvcdm::test_vectors::kTestDir;
|
|
||||||
|
|
||||||
|
// Create files.
|
||||||
std::unique_ptr<File> file = file_system_.Open(path1, FileSystem::kCreate);
|
std::unique_ptr<File> file = file_system_.Open(path1, FileSystem::kCreate);
|
||||||
ASSERT_TRUE(file);
|
ASSERT_TRUE(file) << "Failed to create file (1): " << path1;
|
||||||
file = file_system_.Open(path2, FileSystem::kCreate);
|
file = file_system_.Open(path2, FileSystem::kCreate);
|
||||||
ASSERT_TRUE(file);
|
ASSERT_TRUE(file) << "Failed to create file (2): " << path2;
|
||||||
file = file_system_.Open(path3, FileSystem::kCreate);
|
file = file_system_.Open(path3, FileSystem::kCreate);
|
||||||
ASSERT_TRUE(file);
|
ASSERT_TRUE(file) << "Failed to create file (3): " << path3;
|
||||||
|
file.reset(); // Close file
|
||||||
|
|
||||||
EXPECT_TRUE(file_system_.Exists(path1));
|
EXPECT_TRUE(file_system_.Exists(path1));
|
||||||
EXPECT_TRUE(file_system_.Exists(path2));
|
EXPECT_TRUE(file_system_.Exists(path2));
|
||||||
EXPECT_TRUE(file_system_.Exists(path3));
|
EXPECT_TRUE(file_system_.Exists(path3));
|
||||||
|
|
||||||
// Ask for non-existent path.
|
std::vector<std::string> names;
|
||||||
EXPECT_FALSE(file_system_.List(not_path, &names));
|
ASSERT_TRUE(file_system_.List(dir_path, &names)) << "dir_path = " << dir_path;
|
||||||
|
|
||||||
// Valid path, but no way to return names.
|
size_t expected_file_count = 3;
|
||||||
EXPECT_FALSE(file_system_.List(path_dir, nullptr));
|
EXPECT_EQ(names.size(), expected_file_count);
|
||||||
|
|
||||||
// Valid path, valid return.
|
// Should find the three files. Order not important.
|
||||||
EXPECT_TRUE(file_system_.List(path_dir, &names));
|
|
||||||
|
|
||||||
// Should find three files. Order not important.
|
|
||||||
EXPECT_EQ(3u, names.size());
|
|
||||||
EXPECT_THAT(names, ::testing::UnorderedElementsAre(
|
EXPECT_THAT(names, ::testing::UnorderedElementsAre(
|
||||||
kTestFileName, kTestFileName2, kTestFileName3));
|
kTxtFilename1, kTxtFilename2, kBinFilename));
|
||||||
|
|
||||||
std::string wild_card_path = path_dir + kWildcard + kTestFileNameExt;
|
// Remove .txt files.
|
||||||
EXPECT_TRUE(file_system_.Remove(wild_card_path));
|
const std::string txt_wildcard_path = PathJoin(dir_path, "*.txt");
|
||||||
EXPECT_TRUE(file_system_.List(path_dir, &names));
|
|
||||||
|
|
||||||
EXPECT_EQ(1u, names.size());
|
EXPECT_TRUE(file_system_.Remove(txt_wildcard_path))
|
||||||
EXPECT_TRUE(names[0].compare(kTestFileName3) == 0);
|
<< "txt_wildcard_path = " << txt_wildcard_path;
|
||||||
|
EXPECT_TRUE(file_system_.List(dir_path, &names)) << "dir_path = " << dir_path;
|
||||||
|
|
||||||
std::string wild_card_path2 = path_dir + kWildcard + kTestFileNameExt3;
|
expected_file_count = 1;
|
||||||
EXPECT_TRUE(file_system_.Remove(wild_card_path2));
|
ASSERT_EQ(names.size(), expected_file_count);
|
||||||
EXPECT_TRUE(file_system_.List(path_dir, &names));
|
EXPECT_EQ(names.front(), kBinFilename);
|
||||||
|
|
||||||
EXPECT_EQ(0u, names.size());
|
const std::string bin_wildcard_path = PathJoin(dir_path, "*.bin");
|
||||||
|
EXPECT_TRUE(file_system_.Remove(bin_wildcard_path))
|
||||||
|
<< "bin_wildcard_path = " << bin_wildcard_path;
|
||||||
|
|
||||||
|
// All files should be removed, but listing should still succeed.
|
||||||
|
EXPECT_TRUE(file_system_.List(dir_path, &names)) << "dir_path = " << dir_path;
|
||||||
|
expected_file_count = 0;
|
||||||
|
EXPECT_EQ(expected_file_count, names.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FileTest, CreateGlobalCertificates) {
|
TEST_F(FileTest, ListFiles_NotAPath) {
|
||||||
// Clear directory
|
const std::string not_path("zzz/xxx");
|
||||||
std::vector<std::string> names;
|
std::vector<std::string> names;
|
||||||
std::string path_dir = wvcdm::test_vectors::kTestDir;
|
// Ask for non-existent path.
|
||||||
std::string wild_card_path = path_dir + kWildcard;
|
EXPECT_FALSE(file_system_.List(not_path, &names));
|
||||||
file_system_.Remove(wild_card_path);
|
}
|
||||||
if (file_system_.List(path_dir, &names)) {
|
|
||||||
EXPECT_EQ(0u, names.size());
|
TEST_F(FileTest, ListFiles_NullParameter) {
|
||||||
|
const std::string dir_path = wvcdm::test_vectors::kTestDir;
|
||||||
|
const std::string path = PathJoin(dir_path, kTestFilename);
|
||||||
|
|
||||||
|
std::unique_ptr<File> file = file_system_.Open(path, FileSystem::kCreate);
|
||||||
|
ASSERT_TRUE(file) << "Failed to create file: " << path;
|
||||||
|
file.reset(); // Close file.
|
||||||
|
|
||||||
|
// Valid path, but no way to return names.
|
||||||
|
EXPECT_FALSE(file_system_.List(dir_path, nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// On certain platforms, the FileSystem may perform special
|
||||||
|
// name translations on certificate filenames which make them behave
|
||||||
|
// differently from non-certificate filenames.
|
||||||
|
TEST_F(FileTest, CreateGlobalCertificates) {
|
||||||
|
ASSERT_TRUE(file_system_.IsGlobal())
|
||||||
|
<< "Test case requires global file system";
|
||||||
|
|
||||||
|
const std::string dir_path = wvcdm::test_vectors::kTestDir;
|
||||||
|
|
||||||
|
// Clear directory
|
||||||
|
const std::string all_file_wildcard_path = PathJoin(dir_path, "*");
|
||||||
|
file_system_.Remove(all_file_wildcard_path);
|
||||||
|
// Ensure directory is empty.
|
||||||
|
std::vector<std::string> names;
|
||||||
|
if (file_system_.List(dir_path, &names)) {
|
||||||
|
constexpr size_t kZero = 0;
|
||||||
|
ASSERT_EQ(kZero, names.size()) << "Test requires empty directory";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create certificates and verify that they exist
|
const std::string certificate_path = PathJoin(dir_path, kCertificateFileName);
|
||||||
std::string certificate_path =
|
const std::string legacy_certificate_path =
|
||||||
wvcdm::test_vectors::kTestDir + kCertificateFileName;
|
PathJoin(dir_path, kLegacyCertificateFileName);
|
||||||
std::string legacy_certificate_path =
|
|
||||||
wvcdm::test_vectors::kTestDir + kLegacyCertificateFileName;
|
|
||||||
|
|
||||||
|
// Create certificates and verify that they exist
|
||||||
std::unique_ptr<File> file =
|
std::unique_ptr<File> file =
|
||||||
file_system_.Open(certificate_path, FileSystem::kCreate);
|
file_system_.Open(certificate_path, FileSystem::kCreate);
|
||||||
ASSERT_TRUE(file);
|
ASSERT_TRUE(file) << "Failed to create certificate file: "
|
||||||
|
<< certificate_path;
|
||||||
|
|
||||||
file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate);
|
file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate);
|
||||||
ASSERT_TRUE(file);
|
ASSERT_TRUE(file) << "Failed to create legacy certificate file: "
|
||||||
EXPECT_TRUE(file_system_.IsGlobal());
|
<< legacy_certificate_path;
|
||||||
|
file.reset(); // Close file.
|
||||||
|
|
||||||
EXPECT_TRUE(file_system_.Exists(certificate_path));
|
EXPECT_TRUE(file_system_.Exists(certificate_path))
|
||||||
EXPECT_TRUE(file_system_.Exists(legacy_certificate_path));
|
<< "certificate_path = " << certificate_path;
|
||||||
|
EXPECT_TRUE(file_system_.Exists(legacy_certificate_path))
|
||||||
|
<< "legacy_certificate_path = " << legacy_certificate_path;
|
||||||
|
|
||||||
EXPECT_TRUE(file_system_.List(path_dir, &names));
|
ASSERT_TRUE(file_system_.List(dir_path, &names));
|
||||||
|
|
||||||
// Should find two files. Order not important.
|
// Should find two files. Order not important.
|
||||||
EXPECT_EQ(2u, names.size());
|
constexpr size_t kExpectedCount = 2;
|
||||||
|
EXPECT_EQ(kExpectedCount, names.size());
|
||||||
EXPECT_THAT(names, ::testing::UnorderedElementsAre(
|
EXPECT_THAT(names, ::testing::UnorderedElementsAre(
|
||||||
kCertificateFileName, kLegacyCertificateFileName));
|
kCertificateFileName, kLegacyCertificateFileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// On certain platforms, the FileSystem may perform special
|
||||||
|
// name translations on certificate filenames which make them behave
|
||||||
|
// differently from non-certificate filenames.
|
||||||
TEST_F(FileTest, CreateCertificates) {
|
TEST_F(FileTest, CreateCertificates) {
|
||||||
|
ASSERT_TRUE(file_system_.IsGlobal())
|
||||||
|
<< "Test case requires starting with a global file system";
|
||||||
|
const std::string dir_path = wvcdm::test_vectors::kTestDir;
|
||||||
|
|
||||||
// Clear directory
|
// Clear directory
|
||||||
|
const std::string all_file_wildcard_path = PathJoin(dir_path, "*");
|
||||||
|
file_system_.Remove(all_file_wildcard_path);
|
||||||
|
// Ensure directory is empty.
|
||||||
std::vector<std::string> names;
|
std::vector<std::string> names;
|
||||||
std::string path_dir = wvcdm::test_vectors::kTestDir;
|
if (file_system_.List(dir_path, &names)) {
|
||||||
std::string wild_card_path = path_dir + kWildcard;
|
constexpr size_t kZero = 0;
|
||||||
file_system_.Remove(wild_card_path);
|
ASSERT_EQ(kZero, names.size()) << "Test requires empty directory";
|
||||||
if (file_system_.List(path_dir, &names)) {
|
|
||||||
EXPECT_EQ(0u, names.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string certificate_path =
|
const std::string certificate_path = PathJoin(dir_path, kCertificateFileName);
|
||||||
wvcdm::test_vectors::kTestDir + kCertificateFileName;
|
const std::string legacy_certificate_path =
|
||||||
std::string legacy_certificate_path =
|
PathJoin(dir_path, kLegacyCertificateFileName);
|
||||||
wvcdm::test_vectors::kTestDir + kLegacyCertificateFileName;
|
|
||||||
|
|
||||||
// Create Global certificates
|
// Create Global certificates.
|
||||||
std::unique_ptr<File> file =
|
std::unique_ptr<File> file =
|
||||||
file_system_.Open(certificate_path, FileSystem::kCreate);
|
file_system_.Open(certificate_path, FileSystem::kCreate);
|
||||||
ASSERT_TRUE(file);
|
ASSERT_TRUE(file) << "Failed to create global certificate: "
|
||||||
|
<< certificate_path;
|
||||||
file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate);
|
file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate);
|
||||||
ASSERT_TRUE(file);
|
ASSERT_TRUE(file) << "Failed to create global legacy certificate: "
|
||||||
EXPECT_TRUE(file_system_.IsGlobal());
|
<< legacy_certificate_path;
|
||||||
|
file.reset(); // Close file.
|
||||||
|
|
||||||
|
EXPECT_TRUE(file_system_.Exists(certificate_path))
|
||||||
|
<< "Global certificate: " << certificate_path;
|
||||||
|
EXPECT_TRUE(file_system_.Exists(legacy_certificate_path))
|
||||||
|
<< "Global legacy certificate: " << legacy_certificate_path;
|
||||||
|
|
||||||
|
// Switch to first identifier.
|
||||||
|
file_system_.set_identifier(kTestIdentifier1);
|
||||||
|
ASSERT_FALSE(file_system_.IsGlobal()) << "identifier = " << kTestIdentifier1;
|
||||||
|
|
||||||
|
// Global certificates should not be visible once identifier has been
|
||||||
|
// specified.
|
||||||
|
EXPECT_FALSE(file_system_.Exists(certificate_path))
|
||||||
|
<< kTestIdentifier1 << " certificate: " << certificate_path;
|
||||||
|
EXPECT_FALSE(file_system_.Exists(legacy_certificate_path))
|
||||||
|
<< kTestIdentifier1 << " legacy certificate: " << legacy_certificate_path;
|
||||||
|
|
||||||
// Create certificates with first identifier
|
// Create certificates with first identifier
|
||||||
file_system_.set_identifier(kTestIdentifier1);
|
|
||||||
file = file_system_.Open(certificate_path, FileSystem::kCreate);
|
file = file_system_.Open(certificate_path, FileSystem::kCreate);
|
||||||
ASSERT_TRUE(file);
|
ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier1
|
||||||
|
<< " certificate: " << certificate_path;
|
||||||
file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate);
|
file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate);
|
||||||
ASSERT_TRUE(file);
|
ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier1
|
||||||
EXPECT_TRUE(!file_system_.IsGlobal());
|
<< " legacy certificate: " << legacy_certificate_path;
|
||||||
|
file.reset(); // Close file.
|
||||||
|
|
||||||
|
// Verify they now exist.
|
||||||
|
EXPECT_TRUE(file_system_.Exists(certificate_path))
|
||||||
|
<< kTestIdentifier1 << " certificate: " << certificate_path;
|
||||||
|
EXPECT_TRUE(file_system_.Exists(legacy_certificate_path))
|
||||||
|
<< kTestIdentifier1 << " legacy certificate: " << legacy_certificate_path;
|
||||||
|
|
||||||
|
// Switch to second identifier.
|
||||||
|
file_system_.set_identifier(kTestIdentifier2);
|
||||||
|
ASSERT_FALSE(file_system_.IsGlobal()) << "identifier = " << kTestIdentifier2;
|
||||||
|
|
||||||
|
// Global and first identifier certificates should not be
|
||||||
|
// visible.
|
||||||
|
EXPECT_FALSE(file_system_.Exists(certificate_path))
|
||||||
|
<< kTestIdentifier2 << " certificate: " << certificate_path;
|
||||||
|
EXPECT_FALSE(file_system_.Exists(legacy_certificate_path))
|
||||||
|
<< kTestIdentifier2 << " legacy certificate: " << legacy_certificate_path;
|
||||||
|
|
||||||
// Create certificates with second identifier
|
// Create certificates with second identifier
|
||||||
file_system_.set_identifier(kTestIdentifier2);
|
|
||||||
file = file_system_.Open(certificate_path, FileSystem::kCreate);
|
file = file_system_.Open(certificate_path, FileSystem::kCreate);
|
||||||
ASSERT_TRUE(file);
|
ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier2
|
||||||
|
<< " certificate: " << certificate_path;
|
||||||
file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate);
|
file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate);
|
||||||
ASSERT_TRUE(file);
|
ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier2
|
||||||
EXPECT_TRUE(!file_system_.IsGlobal());
|
<< " legacy certificate: " << legacy_certificate_path;
|
||||||
|
file.reset(); // Close file.
|
||||||
|
|
||||||
EXPECT_TRUE(file_system_.Exists(certificate_path));
|
// Verify they now exist.
|
||||||
EXPECT_TRUE(file_system_.Exists(legacy_certificate_path));
|
EXPECT_TRUE(file_system_.Exists(certificate_path))
|
||||||
|
<< kTestIdentifier2 << " certificate: " << certificate_path;
|
||||||
|
EXPECT_TRUE(file_system_.Exists(legacy_certificate_path))
|
||||||
|
<< kTestIdentifier2 << " legacy certificate: " << legacy_certificate_path;
|
||||||
|
|
||||||
EXPECT_TRUE(file_system_.List(path_dir, &names));
|
// FileSystem::List is expected to still return all certificate files
|
||||||
|
// (both global and scoped).
|
||||||
|
ASSERT_TRUE(file_system_.List(dir_path, &names)) << "dir_path = " << dir_path;
|
||||||
|
|
||||||
// Should find six files. Order not important.
|
// Should find six files. Order not important.
|
||||||
|
constexpr size_t kExpectedTotalCertCount = 6;
|
||||||
|
ASSERT_EQ(names.size(), kExpectedTotalCertCount);
|
||||||
|
|
||||||
bool is_global_certificate_present = false;
|
bool is_global_certificate_present = false;
|
||||||
bool is_global_legacy_certificate_present = false;
|
bool is_global_legacy_certificate_present = false;
|
||||||
size_t certificate_count = 0;
|
size_t certificate_count = 0;
|
||||||
size_t legacy_certificate_count = 0;
|
size_t legacy_certificate_count = 0;
|
||||||
EXPECT_EQ(6u, names.size());
|
for (const auto& filename : names) {
|
||||||
for (size_t i = 0; i < names.size(); ++i) {
|
if (filename == kLegacyCertificateFileName) {
|
||||||
if (names[i].size() > kCertificateFileName.size()) {
|
|
||||||
if (names[i].compare(0, kCertificateFileNamePrefix.size(),
|
|
||||||
kCertificateFileNamePrefix) == 0)
|
|
||||||
++certificate_count;
|
|
||||||
else if (names[i].compare(0, kLegacyCertificateFileNamePrefix.size(),
|
|
||||||
kLegacyCertificateFileNamePrefix) == 0)
|
|
||||||
++legacy_certificate_count;
|
|
||||||
} else if (names[i].compare(kCertificateFileName) == 0) {
|
|
||||||
is_global_certificate_present = true;
|
|
||||||
} else if (names[i].compare(kLegacyCertificateFileName) == 0) {
|
|
||||||
is_global_legacy_certificate_present = true;
|
is_global_legacy_certificate_present = true;
|
||||||
|
} else if (filename == kCertificateFileName) {
|
||||||
|
is_global_certificate_present = true;
|
||||||
|
} else if (StartsWith(filename, kScopedCertificateFilenamePrefix)) {
|
||||||
|
certificate_count++;
|
||||||
|
} else if (StartsWith(filename, kLegacyScopedCertificateFilenamePrefix)) {
|
||||||
|
legacy_certificate_count++;
|
||||||
} else {
|
} else {
|
||||||
EXPECT_TRUE(false);
|
ADD_FAILURE() << "Unexpected filename: " << filename;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EXPECT_EQ(2, certificate_count);
|
constexpr size_t kExpectedScopedCertCount = 2;
|
||||||
EXPECT_EQ(2, legacy_certificate_count);
|
EXPECT_EQ(certificate_count, kExpectedScopedCertCount)
|
||||||
EXPECT_TRUE(is_global_certificate_present);
|
<< "Missing certificates";
|
||||||
EXPECT_TRUE(is_global_legacy_certificate_present);
|
EXPECT_EQ(legacy_certificate_count, kExpectedScopedCertCount)
|
||||||
|
<< "Missing legacy certificates";
|
||||||
|
EXPECT_TRUE(is_global_certificate_present)
|
||||||
|
<< "Missing global certificate: " << kCertificateFileName;
|
||||||
|
EXPECT_TRUE(is_global_legacy_certificate_present)
|
||||||
|
<< "Missing legacy global certificate: " << kLegacyCertificateFileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// On certain platforms, the FileSystem may perform special
|
||||||
|
// name translations on certificate file names which make them behave
|
||||||
|
// differently from non-certificate file names.
|
||||||
TEST_F(FileTest, RemoveCertificates) {
|
TEST_F(FileTest, RemoveCertificates) {
|
||||||
|
ASSERT_TRUE(file_system_.IsGlobal())
|
||||||
|
<< "Test case requires starting with a global file system";
|
||||||
|
const std::string dir_path = wvcdm::test_vectors::kTestDir;
|
||||||
|
|
||||||
// Clear directory
|
// Clear directory
|
||||||
|
const std::string all_file_wildcard_path = PathJoin(dir_path, "*");
|
||||||
|
file_system_.Remove(all_file_wildcard_path);
|
||||||
|
// Ensure directory is empty.
|
||||||
std::vector<std::string> names;
|
std::vector<std::string> names;
|
||||||
std::string path_dir = wvcdm::test_vectors::kTestDir;
|
if (file_system_.List(dir_path, &names)) {
|
||||||
std::string wild_card_path = path_dir + kWildcard;
|
constexpr size_t kZero = 0;
|
||||||
file_system_.Remove(wild_card_path);
|
ASSERT_EQ(kZero, names.size()) << "Test requires empty directory";
|
||||||
if (file_system_.List(path_dir, &names)) {
|
|
||||||
EXPECT_EQ(0u, names.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string certificate_path =
|
const std::string certificate_path = PathJoin(dir_path, kCertificateFileName);
|
||||||
wvcdm::test_vectors::kTestDir + kCertificateFileName;
|
const std::string legacy_certificate_path =
|
||||||
std::string legacy_certificate_path =
|
PathJoin(dir_path, kLegacyCertificateFileName);
|
||||||
wvcdm::test_vectors::kTestDir + kLegacyCertificateFileName;
|
|
||||||
|
|
||||||
// Create Global certificates
|
// Create Global certificates.
|
||||||
std::unique_ptr<File> file =
|
std::unique_ptr<File> file =
|
||||||
file_system_.Open(certificate_path, FileSystem::kCreate);
|
file_system_.Open(certificate_path, FileSystem::kCreate);
|
||||||
ASSERT_TRUE(file);
|
ASSERT_TRUE(file) << "Failed to create global certificate: "
|
||||||
|
<< certificate_path;
|
||||||
file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate);
|
file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate);
|
||||||
ASSERT_TRUE(file);
|
ASSERT_TRUE(file) << "Failed to create global legacy certificate: "
|
||||||
EXPECT_TRUE(file_system_.IsGlobal());
|
<< legacy_certificate_path;
|
||||||
|
file.reset(); // Close file.
|
||||||
|
|
||||||
|
// Switch to first identifier.
|
||||||
|
file_system_.set_identifier(kTestIdentifier1);
|
||||||
|
ASSERT_FALSE(file_system_.IsGlobal()) << "identifier = " << kTestIdentifier1;
|
||||||
|
|
||||||
// Create certificates with first identifier
|
// Create certificates with first identifier
|
||||||
file_system_.set_identifier(kTestIdentifier1);
|
|
||||||
file = file_system_.Open(certificate_path, FileSystem::kCreate);
|
file = file_system_.Open(certificate_path, FileSystem::kCreate);
|
||||||
ASSERT_TRUE(file);
|
ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier1
|
||||||
|
<< " certificate: " << certificate_path;
|
||||||
file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate);
|
file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate);
|
||||||
ASSERT_TRUE(file);
|
ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier1
|
||||||
EXPECT_TRUE(!file_system_.IsGlobal());
|
<< " legacy certificate: " << legacy_certificate_path;
|
||||||
|
file.reset(); // Close file.
|
||||||
|
|
||||||
|
// Switch to second identifier.
|
||||||
|
file_system_.set_identifier(kTestIdentifier2);
|
||||||
|
ASSERT_FALSE(file_system_.IsGlobal()) << "identifier = " << kTestIdentifier2;
|
||||||
|
|
||||||
// Create certificates with second identifier
|
// Create certificates with second identifier
|
||||||
file_system_.set_identifier(kTestIdentifier2);
|
|
||||||
file = file_system_.Open(certificate_path, FileSystem::kCreate);
|
file = file_system_.Open(certificate_path, FileSystem::kCreate);
|
||||||
ASSERT_TRUE(file);
|
ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier2
|
||||||
|
<< " certificate: " << certificate_path;
|
||||||
file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate);
|
file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate);
|
||||||
ASSERT_TRUE(file);
|
ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier2
|
||||||
EXPECT_TRUE(!file_system_.IsGlobal());
|
<< " legacy certificate: " << legacy_certificate_path;
|
||||||
|
file.reset(); // Close file.
|
||||||
|
|
||||||
EXPECT_TRUE(file_system_.Exists(certificate_path));
|
// FileSystem::List is expected to still return all certificate files
|
||||||
EXPECT_TRUE(file_system_.Exists(legacy_certificate_path));
|
// (both global and scoped).
|
||||||
|
ASSERT_TRUE(file_system_.List(dir_path, &names)) << "dir_path = " << dir_path;
|
||||||
EXPECT_TRUE(file_system_.List(path_dir, &names));
|
// Should find six files. Order not important.
|
||||||
|
constexpr size_t kExpectedTotalCertCount = 6;
|
||||||
EXPECT_EQ(6u, names.size());
|
ASSERT_EQ(names.size(), kExpectedTotalCertCount);
|
||||||
|
|
||||||
|
std::set<std::string> removed_certs;
|
||||||
// Remove all even number listed files
|
// Remove all even number listed files
|
||||||
for (size_t i = 0; i < names.size(); ++i) {
|
for (size_t i = 0; i < names.size(); ++i) {
|
||||||
if (i % 2 == 0) {
|
if ((i % 2) != 0) continue;
|
||||||
EXPECT_TRUE(
|
const std::string& cert_filename = names[i];
|
||||||
file_system_.Remove(wvcdm::test_vectors::kTestDir + names[i]));
|
const std::string cert_path = PathJoin(dir_path, cert_filename);
|
||||||
}
|
ASSERT_TRUE(file_system_.Remove(cert_path))
|
||||||
|
<< "Failed to remove cert: " << cert_path;
|
||||||
|
removed_certs.insert(cert_filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify that they have been removed
|
// Verify that they have been removed
|
||||||
for (size_t i = 0; i < names.size(); ++i) {
|
for (const std::string& cert_filename : names) {
|
||||||
if (i % 2 == 1) {
|
const std::string cert_path = PathJoin(dir_path, cert_filename);
|
||||||
EXPECT_TRUE(
|
if (removed_certs.find(cert_filename) == removed_certs.end()) {
|
||||||
file_system_.Exists(wvcdm::test_vectors::kTestDir + names[i]));
|
// Ensure still exists.
|
||||||
|
ASSERT_TRUE(file_system_.Exists(cert_path))
|
||||||
|
<< "Cert missing: " << cert_filename;
|
||||||
} else {
|
} else {
|
||||||
EXPECT_FALSE(
|
ASSERT_FALSE(file_system_.Exists(cert_path))
|
||||||
file_system_.Exists(wvcdm::test_vectors::kTestDir + names[i]));
|
<< "Cert not removed: " << cert_filename;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all odd number listed files
|
// Remove all remaining.
|
||||||
for (size_t i = 0; i < names.size(); ++i) {
|
for (const std::string& cert_filename : names) {
|
||||||
if (i % 2 == 1) {
|
if (removed_certs.find(cert_filename) != removed_certs.end()) continue;
|
||||||
EXPECT_TRUE(
|
const std::string cert_path = PathJoin(dir_path, cert_filename);
|
||||||
file_system_.Remove(wvcdm::test_vectors::kTestDir + names[i]));
|
ASSERT_TRUE(file_system_.Remove(cert_path))
|
||||||
}
|
<< "Failed to remove cert: " << cert_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify that all have been removed
|
// Verify that all have been removed
|
||||||
for (size_t i = 0; i < names.size(); ++i) {
|
for (const std::string& cert_filename : names) {
|
||||||
EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kTestDir + names[i]));
|
const std::string cert_path = PathJoin(dir_path, cert_filename);
|
||||||
|
EXPECT_FALSE(file_system_.Exists(cert_path))
|
||||||
|
<< "Cert not removed: " << cert_filename;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace wvutil
|
} // namespace wvutil
|
||||||
|
|||||||
Reference in New Issue
Block a user