Merge changes from topic "b169740403_2" into sc-dev

* changes:
  Verify DRM certificate validity
  Extract creation and expiration times from DRM cert
  Allow two DRM certificates for each identifier
This commit is contained in:
Rahul Frias
2021-03-19 21:26:33 +00:00
committed by Android (Google) Code Review
15 changed files with 2622 additions and 209 deletions

View File

@@ -54,9 +54,13 @@ class CertificateProvisioning {
// Extract serial number and system ID from a DRM Device certificate.
// Either |serial_number| or |system_id| may be null, but not both.
// Both |creation_time_seconds| and |expiration_time_seconds| may be null.
// |creation_time_seconds| and |expiration_time_seconds| will be set to -1
// if not present, 0 if unlimited and a valid time otherwise
static bool ExtractDeviceInfo(const std::string& device_certificate,
std::string* serial_number,
uint32_t* system_id);
std::string* serial_number, uint32_t* system_id,
int64_t* creation_time_seconds,
int64_t* expiration_time_seconds);
// Removes json wrapping if applicable to extract the
// SignedProvisioningMessage

View File

@@ -23,6 +23,8 @@ namespace wvcdm {
class FileSystem;
using video_widevine_client::sdk::DeviceCertificate;
class DeviceFiles {
public:
typedef enum {
@@ -31,6 +33,24 @@ class DeviceFiles {
kLicenseStateUnknown,
} LicenseState;
typedef enum {
kCertificateValid,
kCertificateExpired,
kCertificateNotFound,
kCertificateInvalid,
kCannotHandle,
} CertificateState;
// |kCertificateDefault| includes an expiration time set by the provisioning
// service. This will replace any legacy certificates, if a forced
// reprovisioning happens at the client or by the license service.
// ATSC certificates are unaffected and have an unlimited lifetime.
typedef enum {
kCertificateDefault,
kCertificateLegacy,
kCertificateAtsc,
} CertificateType;
// All error response codes start with 5000 to avoid overlap with other error
// spaces.
enum ResponseType {
@@ -100,12 +120,19 @@ class DeviceFiles {
// and used but not written or removed.
virtual bool StoreCertificate(const std::string& certificate,
const CryptoWrappedKey& private_key);
virtual bool RetrieveCertificate(bool atsc_mode_enabled,
virtual CertificateState RetrieveCertificate(bool atsc_mode_enabled,
std::string* certificate,
CryptoWrappedKey* private_key,
std::string* serial_number,
uint32_t* system_id);
virtual bool HasCertificate(bool atsc_mode_enabled);
// Retrieves the legacy DRM certificate without performing expiry
// related validation. Use this only when restoring/releasing
// licenses/usage entries
virtual bool RetrieveLegacyCertificate(std::string* certificate,
CryptoWrappedKey* private_key,
std::string* serial_number,
uint32_t* system_id);
virtual bool RemoveCertificate();
virtual bool StoreLicense(const CdmLicenseData& license_data,
@@ -247,6 +274,21 @@ class DeviceFiles {
virtual bool DeleteUsageTableInfo();
private:
// This method will retrieve the certificate and perform expiry validation
// appropriate for a given certificate type
CertificateState RetrieveCertificate(CertificateType certificate_type,
std::string* certificate,
CryptoWrappedKey* private_key,
std::string* serial_number,
uint32_t* system_id);
bool HasCertificate(CertificateType certificate_type);
bool SetDeviceCertificate(const std::string& certificate,
const CryptoWrappedKey& wrapped_private_key,
DeviceCertificate* mutable_device_certificate);
bool ExtractFromDeviceCertificate(const DeviceCertificate& device_certificate,
std::string* certificate,
CryptoWrappedKey* wrapped_private_key);
// Helpers that wrap the File interface and automatically handle hashing, as
// well as adding the device files base path to to the file name.
ResponseType StoreFileWithHash(const std::string& name,
@@ -260,7 +302,8 @@ class DeviceFiles {
bool RemoveFile(const std::string& name);
ssize_t GetFileSize(const std::string& name);
static std::string GetCertificateFileName(bool atsc_mode_enabled);
static bool GetCertificateFileName(CertificateType certificate_type,
std::string* certificate_file_name);
static std::string GetHlsAttributesFileNameExtension();
static std::string GetLicenseFileNameExtension();
static std::string GetUsageTableFileName();
@@ -268,18 +311,28 @@ class DeviceFiles {
#if defined(UNIT_TEST)
FRIEND_TEST(DeviceFilesSecurityLevelTest, SecurityLevel);
FRIEND_TEST(DeviceCertificateTest, StoreCertificate);
FRIEND_TEST(DeviceCertificateTest, ReadCertificate);
FRIEND_TEST(DeviceCertificateTest, ReadCertificateWithoutKeyType);
FRIEND_TEST(DeviceCertificateTest, HasCertificate);
FRIEND_TEST(DeviceFilesStoreTest, StoreLicense);
FRIEND_TEST(DeviceFilesHlsAttributesTest, Delete);
FRIEND_TEST(DeviceFilesHlsAttributesTest, Read);
FRIEND_TEST(DeviceFilesHlsAttributesTest, Store);
FRIEND_TEST(DeviceFilesTest, DeleteLicense);
FRIEND_TEST(DeviceFilesTest, ReserveLicenseIdsDoesNotUseFileSystem);
FRIEND_TEST(DeviceFilesTest, RetrieveLicenses);
FRIEND_TEST(DeviceFilesTest, AppParametersBackwardCompatibility);
FRIEND_TEST(DeviceFilesTest, DeleteLicense);
FRIEND_TEST(DeviceFilesTest, HasCertificateAtsc);
FRIEND_TEST(DeviceFilesTest, HasCertificateDefault);
FRIEND_TEST(DeviceFilesTest, HasCertificateLegacy);
FRIEND_TEST(DeviceFilesTest, HasCertificateNone);
FRIEND_TEST(DeviceFilesTest, ReserveLicenseIdsDoesNotUseFileSystem);
FRIEND_TEST(DeviceFilesTest, RetrieveAtscCertificate);
FRIEND_TEST(DeviceFilesTest, RetrieveAtscCertificateNotFound);
FRIEND_TEST(DeviceFilesTest, RetrieveCertificateWithoutKeyType);
FRIEND_TEST(DeviceFilesTest, RetrieveDefaultCertificate);
FRIEND_TEST(DeviceFilesTest, RetrieveDefaultCertificateNeverExpires);
FRIEND_TEST(DeviceFilesTest,
RetrieveLegacyCertificateWithClientExpirationTime);
FRIEND_TEST(DeviceFilesTest, RetrieveLegacyCertificateWithoutExpirationTime);
FRIEND_TEST(DeviceFilesTest, RetrieveLicenses);
FRIEND_TEST(DeviceFilesTest, StoreCertificateInvalidParams);
FRIEND_TEST(DeviceFilesTest, StoreLicenses);
FRIEND_TEST(DeviceFilesTest, UpdateLicenseState);
FRIEND_TEST(DeviceFilesUsageInfoTest, Delete);
@@ -289,6 +342,9 @@ class DeviceFiles {
FRIEND_TEST(DeviceFilesUsageTableTest, Read);
FRIEND_TEST(DeviceFilesUsageTableTest, Store);
FRIEND_TEST(DeviceFilesUsageTableTest, ReadWithoutLruData);
FRIEND_TEST(RetrieveDefaultCertificateTest, ErrorScenarios);
FRIEND_TEST(RetrieveLegacyCertificateTest, ErrorScenarios);
FRIEND_TEST(StoreCertificateTest, DefaultAndLegacy);
FRIEND_TEST(WvCdmRequestLicenseTest, UnprovisionTest);
FRIEND_TEST(WvCdmRequestLicenseTest, ForceL3Test);
FRIEND_TEST(WvCdmRequestLicenseTest, UsageInfoRetryTest);

View File

@@ -26,6 +26,7 @@ static const size_t CERTIFICATE_DATA_SIZE = 4 * 1024;
// (NaN in JS translates to 0 in unix timestamp).
static const int64_t NEVER_EXPIRES = 0;
static const int64_t UNLIMITED_DURATION = 0;
static const int64_t INVALID_TIME = -1;
// This is the lower limit. For OEMCrypto v16+ one can query and find how many
// are supported

View File

@@ -188,9 +188,9 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set,
bool atsc_mode_enabled = false;
if (cdm_client_property_set != nullptr)
atsc_mode_enabled = cdm_client_property_set->use_atsc_mode();
if (!file_handle_->RetrieveCertificate(atsc_mode_enabled, &client_token,
&private_key, &serial_number,
nullptr)) {
if (file_handle_->RetrieveCertificate(
atsc_mode_enabled, &client_token, &private_key, &serial_number,
nullptr) != DeviceFiles::kCertificateValid) {
return NEED_PROVISIONING;
}
CdmResponseType load_cert_sts;

View File

@@ -15,6 +15,8 @@
#include "string_conversions.h"
#include "wv_cdm_constants.h"
#include "clock.h"
namespace {
const std::string kEmptyString;
@@ -500,7 +502,8 @@ bool CertificateProvisioning::ExtractAndDecodeSignedMessageForTesting(
bool CertificateProvisioning::ExtractDeviceInfo(
const std::string& device_certificate, std::string* serial_number,
uint32_t* system_id) {
uint32_t* system_id, int64_t* creation_time_seconds,
int64_t* expiration_time_seconds) {
LOGV("Extracting device info");
if (serial_number == nullptr && system_id == nullptr) {
LOGE("Output parameters |serial_number| and |system_id| not provided");
@@ -527,6 +530,28 @@ bool CertificateProvisioning::ExtractDeviceInfo(
if (system_id != nullptr) {
*system_id = drm_certificate.system_id();
}
if (creation_time_seconds != nullptr) {
*creation_time_seconds = drm_certificate.has_creation_time_seconds()
? drm_certificate.creation_time_seconds()
: INVALID_TIME;
}
if (expiration_time_seconds != nullptr) {
*expiration_time_seconds = drm_certificate.has_expiration_time_seconds()
? drm_certificate.expiration_time_seconds()
: INVALID_TIME;
}
/*
Clock clock;
//drm_certificate.set_expiration_time_seconds(clock.GetCurrentTime() + 10*365.25*24*60*60);
drm_certificate.set_creation_time_seconds(-5);
std::string serialized_drm_certificate;
drm_certificate.SerializeToString(&serialized_drm_certificate);
signed_drm_certificate.set_drm_certificate(serialized_drm_certificate);
std::string serialized_signed_drm_certificate;
signed_drm_certificate.SerializeToString(&serialized_signed_drm_certificate);
LOGE("serialized_signed_drm_certificate: (%zu) %s", serialized_signed_drm_certificate.size(), b2a_hex(serialized_signed_drm_certificate).c_str());
*/
return true;
}

View File

@@ -4,12 +4,15 @@
#include "device_files.h"
#include <inttypes.h>
#include <string.h>
#include <algorithm>
#include <string>
#include "cdm_random.h"
#include "certificate_provisioning.h"
#include "clock.h"
#include "file_store.h"
#include "license_protocol.pb.h"
#include "log.h"
@@ -43,6 +46,18 @@ using video_widevine_client::sdk::
// Example: STRINGIFY(this_argument) -> "this_argument"
#define STRINGIFY(PARAM...) #PARAM
#define RETURN_CERTIFICATE_STATE_CANNOT_HANDLE_IF_NULL(PARAM) \
if ((PARAM) == nullptr) { \
LOGE("Output parameter |" STRINGIFY(PARAM) "| not provided"); \
return DeviceFiles::kCannotHandle; \
}
#define RETURN_CERTIFICATE_STATE_CANNOT_HANDLE_IF_UNINITIALIZED() \
if (!initialized_) { \
LOGE("Device files is not initialized"); \
return DeviceFiles::kCannotHandle; \
}
#define RETURN_FALSE_IF_NULL(PARAM) \
if ((PARAM) == nullptr) { \
LOGE("Output parameter |" STRINGIFY(PARAM) "| not provided"); \
@@ -71,8 +86,6 @@ using video_widevine_client::sdk::
namespace {
const char kAtscCertificateFileName[] = "atsccert.bin";
const char kCertificateFileName[] = "cert.bin";
const char kHlsAttributesFileNameExt[] = ".hal";
const char kUsageInfoFileNamePrefix[] = "usage";
const char kUsageInfoFileNameExt[] = ".bin";
@@ -80,6 +93,7 @@ const char kLicenseFileNameExt[] = ".lic";
const char kEmptyFileName[] = "";
const char kUsageTableFileName[] = "usgtable.bin";
const char kWildcard[] = "*";
constexpr int64_t kFourMonthsInSeconds = (2 * 30 + 2 * 31) * 24 * 60 * 60;
} // namespace
@@ -130,105 +144,259 @@ bool DeviceFiles::StoreCertificate(const std::string& certificate,
file.set_version(video_widevine_client::sdk::File::VERSION_1);
DeviceCertificate* device_certificate = file.mutable_device_certificate();
device_certificate->set_certificate(certificate);
device_certificate->set_wrapped_private_key(private_key.key());
switch (private_key.type()) {
case CryptoWrappedKey::kRsa:
device_certificate->set_key_type(DeviceCertificate::RSA);
break;
case CryptoWrappedKey::kEcc:
device_certificate->set_key_type(DeviceCertificate::ECC);
break;
case CryptoWrappedKey::kUninitialized: // Suppress compiler warnings.
default:
LOGE("Unexpected key type");
int64_t creation_time_seconds;
int64_t expiration_time_seconds;
uint32_t system_id;
if (!CertificateProvisioning::ExtractDeviceInfo(
certificate, nullptr, &system_id, &creation_time_seconds,
&expiration_time_seconds))
return false;
if (creation_time_seconds <= 0) {
LOGE("Invalid certificate creation time %" PRId64, creation_time_seconds);
return false;
}
const bool default_certificate = expiration_time_seconds >= 0;
if (!SetDeviceCertificate(certificate, private_key, device_certificate))
return false;
if (default_certificate) {
Clock clock;
device_certificate->set_acquisition_time_seconds(clock.GetCurrentTime());
} else {
// Since certificates of type kCertificateAtsc are not allowed to be
// stored, this is a certificate of type kCertificateLegacy.
// The only time when a legacy certificate is stored is when it does not
// have an expiration time. Set expiration time to 6 months +- 2 months.
Clock clock;
const int64_t current_time = clock.GetCurrentTime();
CdmRandomGenerator rng(current_time & 0xffffffff);
device_certificate->set_expiration_time_seconds(
current_time + kFourMonthsInSeconds +
rng.RandomInRange(kFourMonthsInSeconds));
}
std::string serialized_file;
file.SerializeToString(&serialized_file);
return StoreFileWithHash(GetCertificateFileName(false), serialized_file) ==
kNoError;
std::string certificate_file_name;
const CertificateType certificate_type =
default_certificate ? kCertificateDefault : kCertificateLegacy;
if (!GetCertificateFileName(certificate_type, &certificate_file_name)) {
LOGE("Unable to get certificate file name of type: %d", certificate_type);
return false;
}
return StoreFileWithHash(certificate_file_name, serialized_file) == kNoError;
}
bool DeviceFiles::RetrieveCertificate(bool atsc_mode_enabled,
std::string* certificate,
DeviceFiles::CertificateState DeviceFiles::RetrieveCertificate(
bool atsc_mode_enabled, std::string* certificate,
CryptoWrappedKey* private_key, std::string* serial_number,
uint32_t* system_id) {
RETURN_CERTIFICATE_STATE_CANNOT_HANDLE_IF_UNINITIALIZED();
RETURN_CERTIFICATE_STATE_CANNOT_HANDLE_IF_NULL(certificate);
RETURN_CERTIFICATE_STATE_CANNOT_HANDLE_IF_NULL(private_key);
if (!HasCertificate(atsc_mode_enabled)) {
LOGW("Unable to find certificate, atsc mode: %s",
atsc_mode_enabled ? "enabled" : "disabled");
return kCertificateNotFound;
}
if (atsc_mode_enabled)
return RetrieveCertificate(kCertificateAtsc, certificate, private_key,
serial_number, system_id);
if (HasCertificate(kCertificateDefault))
return RetrieveCertificate(kCertificateDefault, certificate, private_key,
serial_number, system_id);
return RetrieveCertificate(kCertificateLegacy, certificate, private_key,
serial_number, system_id);
}
DeviceFiles::CertificateState DeviceFiles::RetrieveCertificate(
CertificateType certificate_type, std::string* certificate,
CryptoWrappedKey* wrapped_private_key, std::string* serial_number,
uint32_t* system_id) {
RETURN_CERTIFICATE_STATE_CANNOT_HANDLE_IF_NULL(certificate);
RETURN_CERTIFICATE_STATE_CANNOT_HANDLE_IF_NULL(wrapped_private_key);
std::string certificate_file_name;
if (!GetCertificateFileName(certificate_type, &certificate_file_name)) {
LOGW("Unable to find certificate file name for type: %d", certificate_type);
return kCannotHandle;
}
video_widevine_client::sdk::File file;
if (RetrieveHashedFile(certificate_file_name, &file) != kNoError) {
LOGW("Unable to retrieve certificate file");
return kCertificateNotFound;
}
if (file.type() != video_widevine_client::sdk::File::DEVICE_CERTIFICATE) {
LOGE("Certificate file is of incorrect file type: type = %d",
static_cast<int>(file.type()));
return kCertificateInvalid;
}
if (file.version() != video_widevine_client::sdk::File::VERSION_1) {
LOGE("Certificate file is of incorrect file version: version = %d",
static_cast<int>(file.version()));
return kCertificateInvalid;
}
if (!file.has_device_certificate()) {
LOGE("Certificate not present");
return kCertificateInvalid;
}
const DeviceCertificate& device_certificate = file.device_certificate();
if (!ExtractFromDeviceCertificate(device_certificate, certificate,
wrapped_private_key)) {
LOGE("Unable to extract from device certificate");
return kCertificateInvalid;
}
int64_t creation_time_seconds;
int64_t expiration_time_seconds;
if (!CertificateProvisioning::ExtractDeviceInfo(
device_certificate.certificate(), serial_number, system_id,
&creation_time_seconds, &expiration_time_seconds))
return kCertificateInvalid;
Clock clock;
const int64_t current_time = clock.GetCurrentTime();
switch (certificate_type) {
case kCertificateDefault: {
// Validation check for DRM certificate that includes an expiration
// time set by the provisioning service. Since provisioning and
// client clocks may not be in sync, verify by comparing time
// elapsed since license was acquired with expiration period.
// First verify that all the fields are set to valid values.
// The service will validate certificate expiration so tampering of
// time values at the client is not a concern.
if (creation_time_seconds <= 0) {
LOGE("Invalid creation time of default certificate: %" PRId64,
creation_time_seconds);
return kCertificateInvalid;
}
if (expiration_time_seconds < 0) {
LOGE("Invalid expiration time of default certificate: %" PRId64,
expiration_time_seconds);
return kCertificateInvalid;
}
if (expiration_time_seconds == UNLIMITED_DURATION)
return kCertificateValid;
if (!device_certificate.has_acquisition_time_seconds()) {
LOGE("Acquisition time of default certificate not available");
return kCertificateInvalid;
}
const int64_t acquisition_time_seconds =
device_certificate.acquisition_time_seconds();
if (acquisition_time_seconds <= 0) {
LOGE("Invalid acquisition time of default certificate: %" PRId64,
acquisition_time_seconds);
return kCertificateInvalid;
}
if (current_time < acquisition_time_seconds) {
LOGE("Time not valid: current time: %" PRId64
", acquisition time: %" PRId64,
current_time, acquisition_time_seconds);
return kCannotHandle;
}
if (expiration_time_seconds < creation_time_seconds) {
LOGE("Time not valid: expiration time: %" PRId64
", creation time: %" PRId64,
expiration_time_seconds, creation_time_seconds);
return kCertificateInvalid;
}
if (current_time - acquisition_time_seconds >
expiration_time_seconds - creation_time_seconds) {
return kCertificateExpired;
}
return kCertificateValid;
}
case kCertificateLegacy: {
// Validation check for DRM certificate without an expiration
// time set by the provisioning service. Add an expiry time
// within the next 6 months +/- 2 months, if one has not been set.
if (!device_certificate.has_expiration_time_seconds()) {
StoreCertificate(*certificate, *wrapped_private_key);
return kCertificateValid;
}
const int64_t expiration_time_seconds =
device_certificate.expiration_time_seconds();
if (expiration_time_seconds <= 0) {
LOGE("Invalid expiration time of legacy certificate: %" PRId64,
expiration_time_seconds);
return kCertificateInvalid;
}
if (current_time > expiration_time_seconds) return kCertificateExpired;
return kCertificateValid;
}
case kCertificateAtsc:
// No expiration enforced
return kCertificateValid;
default:
// Should never happen. This should be detected earlier when fetching
// the file name
LOGE("Invalid certificate type: %d", certificate_type);
return kCertificateInvalid;
}
}
bool DeviceFiles::RetrieveLegacyCertificate(std::string* certificate,
CryptoWrappedKey* private_key,
std::string* serial_number,
uint32_t* system_id) {
RETURN_FALSE_IF_UNINITIALIZED();
RETURN_FALSE_IF_NULL(certificate);
RETURN_FALSE_IF_NULL(private_key);
if (!HasCertificate(kCertificateLegacy)) return false;
const CertificateState state = RetrieveCertificate(
kCertificateLegacy, certificate, private_key, serial_number, system_id);
if (state == kCertificateValid || state == kCertificateExpired) return true;
if (!HasCertificate(atsc_mode_enabled)) {
return false;
}
video_widevine_client::sdk::File file;
if (RetrieveHashedFile(GetCertificateFileName(atsc_mode_enabled), &file) !=
kNoError) {
LOGW("Unable to retrieve certificate file");
return false;
}
if (file.type() != video_widevine_client::sdk::File::DEVICE_CERTIFICATE) {
LOGE("Certificate file is of incorrect file type: type = %d",
static_cast<int>(file.type()));
return false;
}
if (file.version() != video_widevine_client::sdk::File::VERSION_1) {
LOGE("Certificate file is of incorrect file version: version = %d",
static_cast<int>(file.version()));
return false;
}
if (!file.has_device_certificate()) {
LOGE("Certificate not present");
return false;
}
DeviceCertificate device_certificate = file.device_certificate();
*certificate = device_certificate.certificate();
private_key->Clear();
private_key->set_key(device_certificate.wrapped_private_key());
if (device_certificate.has_key_type()) {
const DeviceCertificate::PrivateKeyType key_type =
device_certificate.key_type();
switch (key_type) {
case DeviceCertificate::RSA:
private_key->set_type(CryptoWrappedKey::kRsa);
break;
case DeviceCertificate::ECC:
private_key->set_type(CryptoWrappedKey::kEcc);
break;
default:
LOGW("Unknown DRM key type, defaulting to RSA: type = %d", key_type);
private_key->set_type(CryptoWrappedKey::kRsa);
break;
}
} else {
// Possible that device certificate is from V15, in this case, the
// only supported key of at that time was RSA.
LOGD("No key type info, assuming RSA");
private_key->set_type(CryptoWrappedKey::kRsa);
}
return CertificateProvisioning::ExtractDeviceInfo(
device_certificate.certificate(), serial_number, system_id);
}
bool DeviceFiles::HasCertificate(bool atsc_mode_enabled) {
RETURN_FALSE_IF_UNINITIALIZED();
return FileExists(GetCertificateFileName(atsc_mode_enabled));
if (atsc_mode_enabled) return HasCertificate(kCertificateAtsc);
return HasCertificate(kCertificateDefault) ||
HasCertificate(kCertificateLegacy);
}
bool DeviceFiles::RemoveCertificate() {
RETURN_FALSE_IF_UNINITIALIZED()
return RemoveFile(GetCertificateFileName(false));
std::string certificate_file_name;
if (GetCertificateFileName(kCertificateLegacy, &certificate_file_name))
RemoveFile(certificate_file_name);
if (GetCertificateFileName(kCertificateDefault, &certificate_file_name))
return RemoveFile(certificate_file_name);
return true;
}
bool DeviceFiles::StoreLicense(const CdmLicenseData& license_data,
@@ -1087,6 +1255,70 @@ bool DeviceFiles::DeleteUsageTableInfo() {
return RemoveFile(GetUsageTableFileName());
}
bool DeviceFiles::HasCertificate(CertificateType certificate_type) {
RETURN_FALSE_IF_UNINITIALIZED();
std::string certificate_file_name;
if (!GetCertificateFileName(certificate_type, &certificate_file_name))
return false;
return FileExists(certificate_file_name);
}
bool DeviceFiles::SetDeviceCertificate(
const std::string& certificate, const CryptoWrappedKey& private_key,
DeviceCertificate* mutable_device_certificate) {
RETURN_FALSE_IF_NULL(mutable_device_certificate);
mutable_device_certificate->set_certificate(certificate);
mutable_device_certificate->set_wrapped_private_key(private_key.key());
switch (private_key.type()) {
case CryptoWrappedKey::kRsa:
mutable_device_certificate->set_key_type(DeviceCertificate::RSA);
return true;
case CryptoWrappedKey::kEcc:
mutable_device_certificate->set_key_type(DeviceCertificate::ECC);
return true;
case CryptoWrappedKey::kUninitialized: // Suppress compiler warnings.
default:
LOGE("Unexpected key type: %d", private_key.type());
return false;
}
}
bool DeviceFiles::ExtractFromDeviceCertificate(
const DeviceCertificate& device_certificate, std::string* certificate,
CryptoWrappedKey* private_key) {
RETURN_FALSE_IF_NULL(certificate);
RETURN_FALSE_IF_NULL(private_key);
*certificate = device_certificate.certificate();
private_key->Clear();
private_key->set_key(device_certificate.wrapped_private_key());
if (device_certificate.has_key_type()) {
const DeviceCertificate::PrivateKeyType key_type =
device_certificate.key_type();
switch (key_type) {
case DeviceCertificate::RSA:
private_key->set_type(CryptoWrappedKey::kRsa);
break;
case DeviceCertificate::ECC:
private_key->set_type(CryptoWrappedKey::kEcc);
break;
default:
LOGW("Unknown DRM key type, defaulting to RSA: type = %d", key_type);
private_key->set_type(CryptoWrappedKey::kRsa);
break;
}
} else {
// Possible that device certificate is from V15, in this case, the
// only supported key of at that time was RSA.
LOGD("No key type info, assuming RSA");
private_key->set_type(CryptoWrappedKey::kRsa);
}
return true;
}
DeviceFiles::ResponseType DeviceFiles::StoreFileWithHash(
const std::string& name, const std::string& serialized_file) {
std::string hash = Sha256Hash(serialized_file);
@@ -1269,8 +1501,22 @@ ssize_t DeviceFiles::GetFileSize(const std::string& name) {
return file_system_->FileSize(path);
}
std::string DeviceFiles::GetCertificateFileName(bool atsc_mode_enabled) {
return atsc_mode_enabled ? kAtscCertificateFileName : kCertificateFileName;
bool DeviceFiles::GetCertificateFileName(CertificateType certificate_type,
std::string* file_name) {
RETURN_FALSE_IF_NULL(file_name);
switch (certificate_type) {
case kCertificateDefault:
*file_name = kCertificateFileName;
return true;
case kCertificateLegacy:
*file_name = kLegacyCertificateFileName;
return true;
case kCertificateAtsc:
*file_name = kAtscCertificateFileName;
return true;
default:
return false;
}
}
std::string DeviceFiles::GetUsageTableFileName() { return kUsageTableFileName; }

View File

@@ -116,8 +116,10 @@ class MockDeviceFiles : public DeviceFiles {
MockDeviceFiles() : DeviceFiles(nullptr) {}
MOCK_METHOD1(Init, bool(CdmSecurityLevel));
MOCK_METHOD5(RetrieveCertificate, bool(bool, std::string*, CryptoWrappedKey*,
std::string*, uint32_t*));
MOCK_METHOD5(RetrieveCertificate,
DeviceFiles::CertificateState(bool, std::string*,
CryptoWrappedKey*, std::string*,
uint32_t*));
};
class MockUsageTableHeader : public UsageTableHeader {
@@ -221,7 +223,7 @@ TEST_F(CdmSessionTest, InitWithBuiltInCertificate) {
EXPECT_CALL(*file_handle_,
RetrieveCertificate(false, NotNull(), NotNull(), NotNull(), _))
.WillOnce(DoAll(SetArgPointee<1>(kToken), SetArgPointee<2>(kWrappedKey),
Return(true)));
Return(DeviceFiles::kCertificateValid)));
EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(kWrappedKey))
.InSequence(crypto_session_seq)
.WillOnce(Return(NO_ERROR));
@@ -249,7 +251,7 @@ TEST_F(CdmSessionTest, InitWithCertificate) {
EXPECT_CALL(*file_handle_,
RetrieveCertificate(false, NotNull(), NotNull(), NotNull(), _))
.WillOnce(DoAll(SetArgPointee<1>(kToken), SetArgPointee<2>(kWrappedKey),
Return(true)));
Return(DeviceFiles::kCertificateValid)));
EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(kWrappedKey))
.InSequence(crypto_session_seq)
.WillOnce(Return(NO_ERROR));
@@ -276,7 +278,7 @@ TEST_F(CdmSessionTest, ReInitFail) {
EXPECT_CALL(*file_handle_,
RetrieveCertificate(false, NotNull(), NotNull(), NotNull(), _))
.WillOnce(DoAll(SetArgPointee<1>(kToken), SetArgPointee<2>(kWrappedKey),
Return(true)));
Return(DeviceFiles::kCertificateValid)));
EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(kWrappedKey))
.InSequence(crypto_session_seq)
.WillOnce(Return(NO_ERROR));
@@ -310,7 +312,7 @@ TEST_F(CdmSessionTest, InitNeedsProvisioning) {
EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true));
EXPECT_CALL(*file_handle_,
RetrieveCertificate(false, NotNull(), NotNull(), NotNull(), _))
.WillOnce(Return(false));
.WillOnce(Return(DeviceFiles::kCertificateInvalid));
ASSERT_EQ(NEED_PROVISIONING, cdm_session_->Init(nullptr));
}
@@ -331,7 +333,7 @@ TEST_F(CdmSessionTest, UpdateUsageEntry) {
EXPECT_CALL(*file_handle_,
RetrieveCertificate(false, NotNull(), NotNull(), NotNull(), _))
.WillOnce(DoAll(SetArgPointee<1>(kToken), SetArgPointee<2>(kWrappedKey),
Return(true)));
Return(DeviceFiles::kCertificateValid)));
EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(kWrappedKey))
.InSequence(crypto_session_seq)
.WillOnce(Return(NO_ERROR));

View File

@@ -17,17 +17,37 @@
namespace {
const std::string kSignedDeviceCertificate = wvcdm::a2bs_hex(
"0A350802121B7769646576696E655F746573745F73657269616C5F6E756D62657228D2093A"
"11746573742E7769646576696E652E636F6D12097369676E6174757265");
"0A3D0802121B7769646576696E655F746573745F73657269616C5F6E756D62657218C09A0C"
"28D2093A11746573742E7769646576696E652E636F6D6080B51812097369676E617475726"
"5");
const std::string kSignedDeviceCertificateCreationTimeUnlimited =
wvcdm::a2bs_hex(
"0A370802121B7769646576696E655F746573745F73657269616C5F6E756D6265721800"
"28D2093A11746573742E7769646576696E652E636F6D12097369676E6174757265");
const std::string kSignedDeviceCertificateExpirationTimeInvalid =
wvcdm::a2bs_hex(
"0A390802121B7769646576696E655F746573745F73657269616C5F6E756D62657218C0"
"9A0C28D2093A11746573742E7769646576696E652E636F6D12097369676E617475726"
"5");
const std::string kSignedDeviceCertificateExpirationTimeUnlimited =
wvcdm::a2bs_hex(
"0A3B0802121B7769646576696E655F746573745F73657269616C5F6E756D62657218C0"
"9A0C28D2093A11746573742E7769646576696E652E636F6D600012097369676E617475"
"7265");
const std::string kSignedDeviceCertificateInvalid = wvcdm::a2bs_hex(
"76340802121B7769646576696E655F746573745F73657269616C5F6E756D62657228D2093A"
"11746573742E7769646576696E652E636F6D12097369676E6174757265");
const std::string kSignedDeviceCertificateNoDrmCertificate =
wvcdm::a2bs_hex("12097369676E6174757265");
const std::string kSignedDeviceCertificateInvalidCertificateType =
wvcdm::a2bs_hex(
"0A350801121B7769646576696E655F746573745F73657269616C5F6E756D62657228D2"
"093A11746573742E7769646576696E652E636F6D12097369676E6174757265");
const std::string kSignedDeviceCertificateNoDrmCertificate =
wvcdm::a2bs_hex("12097369676E6174757265");
const std::string kSignedDeviceCertificateTimesInvalid = wvcdm::a2bs_hex(
"0A350802121B7769646576696E655F746573745F73657269616C5F6E756D62657228D2093A"
"11746573742E7769646576696E652E636F6D12097369676E6174757265");
const int64_t kCreationTime = 200000;
const int64_t kExpirationTime = 400000;
const std::string kSerialNumber = "widevine_test_serial_number";
const uint32_t kSystemId = 1234;
@@ -91,17 +111,20 @@ TEST_F(CertificateProvisioningTest, ExtractDeviceInfo_InvalidInput) {
uint32_t system_id;
EXPECT_FALSE(certificate_provisioning_->ExtractDeviceInfo(
kSignedDeviceCertificate, nullptr, nullptr));
kSignedDeviceCertificate, nullptr, nullptr, nullptr, nullptr));
int64_t creation_time_seconds, expiration_time_seconds;
EXPECT_FALSE(certificate_provisioning_->ExtractDeviceInfo(
kSignedDeviceCertificateInvalid, &serial_number, &system_id,
&creation_time_seconds, &expiration_time_seconds));
EXPECT_FALSE(certificate_provisioning_->ExtractDeviceInfo(
kSignedDeviceCertificateInvalid, &serial_number, &system_id));
EXPECT_FALSE(certificate_provisioning_->ExtractDeviceInfo(
kSignedDeviceCertificateNoDrmCertificate, &serial_number, &system_id));
kSignedDeviceCertificateNoDrmCertificate, &serial_number, &system_id,
&creation_time_seconds, &expiration_time_seconds));
EXPECT_FALSE(certificate_provisioning_->ExtractDeviceInfo(
kSignedDeviceCertificateInvalidCertificateType, &serial_number,
&system_id));
&system_id, &creation_time_seconds, &expiration_time_seconds));
}
// Tests ExtractDeviceInfo success scenarios
@@ -111,19 +134,72 @@ TEST_F(CertificateProvisioningTest, ExtractDeviceInfo_InvalidInput) {
TEST_F(CertificateProvisioningTest, ExtractDeviceInfo) {
std::string serial_number;
uint32_t system_id;
int64_t creation_time_seconds, expiration_time_seconds;
EXPECT_TRUE(certificate_provisioning_->ExtractDeviceInfo(
kSignedDeviceCertificate, &serial_number, &system_id));
kSignedDeviceCertificateTimesInvalid, &serial_number, &system_id,
&creation_time_seconds, &expiration_time_seconds));
EXPECT_EQ(kSerialNumber, serial_number);
EXPECT_EQ(kSystemId, system_id);
EXPECT_EQ(INVALID_TIME, creation_time_seconds);
EXPECT_EQ(INVALID_TIME, expiration_time_seconds);
EXPECT_TRUE(certificate_provisioning_->ExtractDeviceInfo(
kSignedDeviceCertificateTimesInvalid, nullptr, &system_id, nullptr,
nullptr));
EXPECT_EQ(kSystemId, system_id);
EXPECT_TRUE(certificate_provisioning_->ExtractDeviceInfo(
kSignedDeviceCertificate, nullptr, &system_id));
EXPECT_EQ(kSystemId, system_id);
kSignedDeviceCertificateTimesInvalid, &serial_number, nullptr, nullptr,
nullptr));
EXPECT_EQ(kSerialNumber, serial_number);
EXPECT_TRUE(certificate_provisioning_->ExtractDeviceInfo(
kSignedDeviceCertificate, &serial_number, nullptr));
kSignedDeviceCertificateCreationTimeUnlimited, &serial_number, &system_id,
&creation_time_seconds, &expiration_time_seconds));
EXPECT_EQ(kSerialNumber, serial_number);
EXPECT_EQ(kSystemId, system_id);
EXPECT_EQ(UNLIMITED_DURATION, creation_time_seconds);
EXPECT_EQ(INVALID_TIME, expiration_time_seconds);
EXPECT_TRUE(certificate_provisioning_->ExtractDeviceInfo(
kSignedDeviceCertificateExpirationTimeInvalid, &serial_number, &system_id,
&creation_time_seconds, &expiration_time_seconds));
EXPECT_EQ(kSerialNumber, serial_number);
EXPECT_EQ(kSystemId, system_id);
EXPECT_EQ(kCreationTime, creation_time_seconds);
EXPECT_EQ(INVALID_TIME, expiration_time_seconds);
EXPECT_TRUE(certificate_provisioning_->ExtractDeviceInfo(
kSignedDeviceCertificateExpirationTimeUnlimited, &serial_number,
&system_id, &creation_time_seconds, &expiration_time_seconds));
EXPECT_EQ(kSerialNumber, serial_number);
EXPECT_EQ(kSystemId, system_id);
EXPECT_EQ(kCreationTime, creation_time_seconds);
EXPECT_EQ(UNLIMITED_DURATION, expiration_time_seconds);
EXPECT_TRUE(certificate_provisioning_->ExtractDeviceInfo(
kSignedDeviceCertificate, &serial_number, &system_id,
&creation_time_seconds, &expiration_time_seconds));
EXPECT_EQ(kSerialNumber, serial_number);
EXPECT_EQ(kSystemId, system_id);
EXPECT_EQ(kCreationTime, creation_time_seconds);
EXPECT_EQ(kExpirationTime, expiration_time_seconds);
EXPECT_TRUE(certificate_provisioning_->ExtractDeviceInfo(
kSignedDeviceCertificate, &serial_number, &system_id, nullptr,
&expiration_time_seconds));
EXPECT_EQ(kSerialNumber, serial_number);
EXPECT_EQ(kSystemId, system_id);
EXPECT_EQ(kExpirationTime, expiration_time_seconds);
EXPECT_TRUE(certificate_provisioning_->ExtractDeviceInfo(
kSignedDeviceCertificateExpirationTimeUnlimited, &serial_number,
&system_id, &creation_time_seconds, nullptr));
EXPECT_EQ(kSerialNumber, serial_number);
EXPECT_EQ(kSystemId, system_id);
EXPECT_EQ(kCreationTime, creation_time_seconds);
EXPECT_EQ(kExpirationTime, expiration_time_seconds);
}
} // namespace wvcdm

File diff suppressed because it is too large Load Diff

View File

@@ -366,8 +366,8 @@ void InitVectorConstants() {
}
}
void ToVector(std::vector<CdmUsageEntryInfo>& vec,
const CdmUsageEntryInfo* arr, size_t total_size) {
void ToVector(std::vector<CdmUsageEntryInfo>& vec, const CdmUsageEntryInfo* arr,
size_t total_size) {
size_t max = total_size / sizeof(CdmUsageEntryInfo);
vec.clear();
for (size_t i = 0; i < max; i++) {
@@ -415,8 +415,7 @@ class MockDeviceFiles : public DeviceFiles {
const std::string&, const CdmUsageEntry&, uint32_t));
MOCK_METHOD2(RetrieveUsageInfo,
bool(const std::string&, std::vector<CdmUsageData>*));
MOCK_METHOD1(ListLicenses,
bool(std::vector<std::string>* key_set_ids));
MOCK_METHOD1(ListLicenses, bool(std::vector<std::string>* key_set_ids));
MOCK_METHOD1(ListUsageInfoFiles,
bool(std::vector<std::string>* usage_info_files));
@@ -472,10 +471,9 @@ class MockUsageTableHeader : public UsageTableHeader {
MockUsageTableHeader() : UsageTableHeader() {}
MOCK_METHOD4(InvalidateEntry, CdmResponseType(uint32_t, bool, DeviceFiles*,
metrics::CryptoMetrics*));
MOCK_METHOD6(AddEntry,
CdmResponseType(CryptoSession*, bool, const CdmKeySetId&,
const std::string&, const CdmKeyResponse&,
uint32_t*));
MOCK_METHOD6(AddEntry, CdmResponseType(CryptoSession*, bool,
const CdmKeySetId&, const std::string&,
const CdmKeyResponse&, uint32_t*));
CdmResponseType SuperAddEntry(CryptoSession* crypto_session,
bool persistent_license,
@@ -493,9 +491,7 @@ class MockUsageTableHeader : public UsageTableHeader {
class UsageTableHeaderTest : public WvCdmTestBase {
public:
static void SetUpTestCase() {
InitVectorConstants();
}
static void SetUpTestCase() { InitVectorConstants(); }
// Useful when UsageTableHeader is mocked
void InvalidateEntry(uint32_t usage_entry_number, bool, DeviceFiles*,
@@ -591,10 +587,7 @@ class UsageTableHeaderInitializationTest
: public UsageTableHeaderTest,
public ::testing::WithParamInterface<CdmSecurityLevel> {
public:
static void SetUpTestCase() {
InitVectorConstants();
}
static void SetUpTestCase() { InitVectorConstants(); }
};
TEST_P(UsageTableHeaderInitializationTest, CreateUsageTableHeader) {
@@ -763,8 +756,8 @@ TEST_P(UsageTableHeaderInitializationTest,
const SecurityLevel security_level =
(GetParam() == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
EXPECT_CALL(*crypto_session_,
Open(security_level)).WillOnce(Return(NO_ERROR));
EXPECT_CALL(*crypto_session_, Open(security_level))
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*crypto_session_,
LoadUsageTableHeader(security_level, kUsageTableHeader))
.WillOnce(Return(NO_ERROR));
@@ -847,8 +840,8 @@ TEST_P(UsageTableHeaderInitializationTest,
const uint32_t expect_usage_entry_number =
kOverFullUsageEntryInfoVector.size();
EXPECT_CALL(*crypto_session_, CreateUsageEntry(NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(expect_usage_entry_number),
Return(NO_ERROR)));
.WillOnce(
DoAll(SetArgPointee<0>(expect_usage_entry_number), Return(NO_ERROR)));
EXPECT_CALL(*crypto_session_, UpdateUsageEntry(NotNull(), NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(kAnotherUsageTableHeader), Return(NO_ERROR)));

View File

@@ -2151,7 +2151,8 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
}
if (!CertificateProvisioning::ExtractDeviceInfo(
prov_response.device_certificate(), serial_number, nullptr)) {
prov_response.device_certificate(), serial_number, nullptr, nullptr,
nullptr)) {
EXPECT_TRUE(false);
return false;
}
@@ -2300,13 +2301,17 @@ TEST_F(WvCdmRequestLicenseTest, UnprovisionTest) {
CryptoWrappedKey wrapped_private_key;
std::string serial_number;
uint32_t system_id;
EXPECT_TRUE(handle.RetrieveCertificate(
false, &certificate, &wrapped_private_key, &serial_number, &system_id));
EXPECT_EQ(
DeviceFiles::kCertificateValid,
handle.RetrieveCertificate(false, &certificate, &wrapped_private_key,
&serial_number, &system_id));
EXPECT_EQ(NO_ERROR,
decryptor_->Unprovision(security_level, kDefaultCdmIdentifier));
EXPECT_FALSE(handle.RetrieveCertificate(
false, &certificate, &wrapped_private_key, &serial_number, &system_id));
EXPECT_NE(
DeviceFiles::kCertificateValid,
handle.RetrieveCertificate(false, &certificate, &wrapped_private_key,
&serial_number, &system_id));
}
TEST_F(WvCdmRequestLicenseTest, ProvisioningInterposedRetryTest) {

View File

@@ -18,6 +18,13 @@
namespace wvcdm {
static const std::string kAtscCertificateFileName = "atsccert.bin";
static const std::string kCertificateFileName = "cert1.bin";
static const std::string kCertificateFileNameExt = ".bin";
static const std::string kCertificateFileNamePrefix = "cert1_";
static const std::string kLegacyCertificateFileName = "cert.bin";
static const std::string kLegacyCertificateFileNamePrefix = "cert";
// File class. The implementation is platform dependent.
class CORE_UTIL_EXPORT File {
public:

View File

@@ -29,9 +29,6 @@
namespace wvcdm {
namespace {
const char kCertificateFileNamePrefix[] = "cert";
const char kCertificateFileNameExt[] = ".bin";
const char kCertificateFileName[] = "cert.bin";
std::string GetFileNameSafeHash(const std::string& input) {
std::vector<uint8_t> hash(MD5_DIGEST_LENGTH);
@@ -54,6 +51,10 @@ std::string GetFileNameForIdentifier(const std::string path,
if (file_name == kCertificateFileName && !identifier.empty()) {
const std::string hash = GetFileNameSafeHash(identifier);
file_name = kCertificateFileNamePrefix + hash + kCertificateFileNameExt;
} else if (file_name == kLegacyCertificateFileName && !identifier.empty()) {
const std::string hash = GetFileNameSafeHash(identifier);
file_name =
kLegacyCertificateFileNamePrefix + hash + kCertificateFileNameExt;
}
if (dir_path.empty())

View File

@@ -254,7 +254,7 @@ std::vector<uint8_t> Base64SafeDecode(const std::string& b64_input) {
std::string HexEncode(const uint8_t* in_buffer, unsigned int size) {
static const char kHexChars[] = "0123456789ABCDEF";
if (size == 0) return "";
constexpr unsigned int kMaxSafeSize = 2048;
constexpr unsigned int kMaxSafeSize = 3072;
if (size > kMaxSafeSize) size = kMaxSafeSize;
// Each input byte creates two output hex characters.
std::string out_buffer(size * 2, '\0');

View File

@@ -18,7 +18,10 @@ const std::string kTestFileName2 = "test2.txt";
const std::string kTestFileName3 = "test3.other";
const std::string kTestFileNameExt = ".txt";
const std::string kTestFileNameExt3 = ".other";
const std::string kTestIdentifier1 = "some_identifier";
const std::string kTestIdentifier2 = "some_other_identifier";
const std::string kWildcard = "*";
const std::string kUnderscore = "_";
} // namespace
class FileTest : public testing::Test {
@@ -175,4 +178,182 @@ TEST_F(FileTest, ListFiles) {
EXPECT_EQ(0u, names.size());
}
TEST_F(FileTest, CreateGlobalCertificates) {
// Clear directory
std::vector<std::string> names;
std::string path_dir = test_vectors::kTestDir;
std::string wild_card_path = path_dir + kWildcard;
file_system_.Remove(wild_card_path);
if (file_system_.List(path_dir, &names)) {
EXPECT_EQ(0u, names.size());
}
// Create certificates and verify that they exist
std::string certificate_path = test_vectors::kTestDir + kCertificateFileName;
std::string legacy_certificate_path =
test_vectors::kTestDir + kLegacyCertificateFileName;
std::unique_ptr<File> file =
file_system_.Open(certificate_path, FileSystem::kCreate);
ASSERT_TRUE(file);
file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate);
ASSERT_TRUE(file);
EXPECT_TRUE(file_system_.IsGlobal());
EXPECT_TRUE(file_system_.Exists(certificate_path));
EXPECT_TRUE(file_system_.Exists(legacy_certificate_path));
EXPECT_TRUE(file_system_.List(path_dir, &names));
// Should find two files. Order not important.
EXPECT_EQ(2u, names.size());
EXPECT_THAT(names, ::testing::UnorderedElementsAre(
kCertificateFileName, kLegacyCertificateFileName));
}
TEST_F(FileTest, CreateCertificates) {
// Clear directory
std::vector<std::string> names;
std::string path_dir = test_vectors::kTestDir;
std::string wild_card_path = path_dir + kWildcard;
file_system_.Remove(wild_card_path);
if (file_system_.List(path_dir, &names)) {
EXPECT_EQ(0u, names.size());
}
std::string certificate_path = test_vectors::kTestDir + kCertificateFileName;
std::string legacy_certificate_path =
test_vectors::kTestDir + kLegacyCertificateFileName;
// Create Global certificates
std::unique_ptr<File> file =
file_system_.Open(certificate_path, FileSystem::kCreate);
ASSERT_TRUE(file);
file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate);
ASSERT_TRUE(file);
EXPECT_TRUE(file_system_.IsGlobal());
// Create certificates with first identifier
file_system_.set_identifier(kTestIdentifier1);
file = file_system_.Open(certificate_path, FileSystem::kCreate);
ASSERT_TRUE(file);
file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate);
ASSERT_TRUE(file);
EXPECT_TRUE(!file_system_.IsGlobal());
// Create certificates with second identifier
file_system_.set_identifier(kTestIdentifier2);
file = file_system_.Open(certificate_path, FileSystem::kCreate);
ASSERT_TRUE(file);
file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate);
ASSERT_TRUE(file);
EXPECT_TRUE(!file_system_.IsGlobal());
EXPECT_TRUE(file_system_.Exists(certificate_path));
EXPECT_TRUE(file_system_.Exists(legacy_certificate_path));
EXPECT_TRUE(file_system_.List(path_dir, &names));
// Should find six files. Order not important.
bool is_global_certificate_present = false;
bool is_global_legacy_certificate_present = false;
size_t certificate_count = 0;
size_t legacy_certificate_count = 0;
EXPECT_EQ(6u, names.size());
for (size_t i = 0; i < names.size(); ++i) {
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;
} else {
EXPECT_TRUE(false);
}
}
EXPECT_EQ(2, certificate_count);
EXPECT_EQ(2, legacy_certificate_count);
EXPECT_TRUE(is_global_certificate_present);
EXPECT_TRUE(is_global_legacy_certificate_present);
}
TEST_F(FileTest, RemoveCertificates) {
// Clear directory
std::vector<std::string> names;
std::string path_dir = test_vectors::kTestDir;
std::string wild_card_path = path_dir + kWildcard;
file_system_.Remove(wild_card_path);
if (file_system_.List(path_dir, &names)) {
EXPECT_EQ(0u, names.size());
}
std::string certificate_path = test_vectors::kTestDir + kCertificateFileName;
std::string legacy_certificate_path =
test_vectors::kTestDir + kLegacyCertificateFileName;
// Create Global certificates
std::unique_ptr<File> file =
file_system_.Open(certificate_path, FileSystem::kCreate);
ASSERT_TRUE(file);
file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate);
ASSERT_TRUE(file);
EXPECT_TRUE(file_system_.IsGlobal());
// Create certificates with first identifier
file_system_.set_identifier(kTestIdentifier1);
file = file_system_.Open(certificate_path, FileSystem::kCreate);
ASSERT_TRUE(file);
file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate);
ASSERT_TRUE(file);
EXPECT_TRUE(!file_system_.IsGlobal());
// Create certificates with second identifier
file_system_.set_identifier(kTestIdentifier2);
file = file_system_.Open(certificate_path, FileSystem::kCreate);
ASSERT_TRUE(file);
file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate);
ASSERT_TRUE(file);
EXPECT_TRUE(!file_system_.IsGlobal());
EXPECT_TRUE(file_system_.Exists(certificate_path));
EXPECT_TRUE(file_system_.Exists(legacy_certificate_path));
EXPECT_TRUE(file_system_.List(path_dir, &names));
EXPECT_EQ(6u, names.size());
// Remove all even number listed files
for (size_t i = 0; i < names.size(); ++i) {
if (i % 2 == 0) {
EXPECT_TRUE(file_system_.Remove(test_vectors::kTestDir + names[i]));
}
}
// Verify that they have been removed
for (size_t i = 0; i < names.size(); ++i) {
if (i % 2 == 1) {
EXPECT_TRUE(file_system_.Exists(test_vectors::kTestDir + names[i]));
} else {
EXPECT_FALSE(file_system_.Exists(test_vectors::kTestDir + names[i]));
}
}
// Remove all odd number listed files
for (size_t i = 0; i < names.size(); ++i) {
if (i % 2 == 1) {
EXPECT_TRUE(file_system_.Remove(test_vectors::kTestDir + names[i]));
}
}
// Verify that all have been removed
for (size_t i = 0; i < names.size(); ++i) {
EXPECT_FALSE(file_system_.Exists(test_vectors::kTestDir + names[i]));
}
}
} // namespace wvcdm