Snap for 7223902 from f20e2b1ee9 to tm-release

Change-Id: I096b2b421bc90fdb100e3f755c815604e16e9d87
This commit is contained in:
android-build-team Robot
2021-03-21 01:18:02 +00:00
17 changed files with 2697 additions and 210 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,
std::string* certificate,
CryptoWrappedKey* private_key,
std::string* serial_number,
uint32_t* system_id);
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");
return false;
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,
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);
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)) {
return false;
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(GetCertificateFileName(atsc_mode_enabled), &file) !=
kNoError) {
if (RetrieveHashedFile(certificate_file_name, &file) != kNoError) {
LOGW("Unable to retrieve certificate file");
return false;
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 false;
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 false;
return kCertificateInvalid;
}
if (!file.has_device_certificate()) {
LOGE("Certificate not present");
return false;
return kCertificateInvalid;
}
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;
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;
}
} 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);
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;
return false;
}
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

@@ -168,28 +168,28 @@ const size_t kUsageInfoFileArraySize = ArraySize(kUsageInfoFileArray);
std::vector<std::string> kUsageInfoFileList;
const DeviceFiles::CdmUsageData kCdmUsageData1 = {
/* provider_session_token = */ "provider_session_token_1",
/* license_request = */ "license_request_1",
/* license = */ "license_1",
/* key_set_id = */ "key_set_id_1",
/* usage_entry = */ "usage_entry_1",
/* usage_entry_number = */ 0,
/* provider_session_token = */ "provider_session_token_1",
/* license_request = */ "license_request_1",
/* license = */ "license_1",
/* key_set_id = */ "key_set_id_1",
/* usage_entry = */ "usage_entry_1",
/* usage_entry_number = */ 0,
};
const DeviceFiles::CdmUsageData kCdmUsageData2 = {
/* provider_session_token = */ "provider_session_token_2",
/* license_request = */ "license_request_2",
/* license = */ "license_2",
/* key_set_id = */ "key_set_id_2",
/* usage_entry = */ "usage_entry_2",
/* usage_entry_number = */ 0,
/* provider_session_token = */ "provider_session_token_2",
/* license_request = */ "license_request_2",
/* license = */ "license_2",
/* key_set_id = */ "key_set_id_2",
/* usage_entry = */ "usage_entry_2",
/* usage_entry_number = */ 0,
};
const DeviceFiles::CdmUsageData kCdmUsageData3 = {
/* provider_session_token = */ "provider_session_token_3",
/* license_request = */ "license_request_3",
/* license = */ "license_3",
/* key_set_id = */ "key_set_id_3",
/* usage_entry = */ "usage_entry_3",
/* usage_entry_number = */ 0,
/* provider_session_token = */ "provider_session_token_3",
/* license_request = */ "license_request_3",
/* license = */ "license_3",
/* key_set_id = */ "key_set_id_3",
/* usage_entry = */ "usage_entry_3",
/* usage_entry_number = */ 0,
};
const std::vector<DeviceFiles::CdmUsageData> kEmptyUsageInfoUsageDataList;
@@ -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));
@@ -468,34 +467,31 @@ class MockCryptoSession : public TestCryptoSession {
// Partial mock of the UsageTableHeader. This is to test when dependency
// exist on internal methods which would require complex expectations
class MockUsageTableHeader : public UsageTableHeader {
public:
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*));
public:
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*));
CdmResponseType SuperAddEntry(CryptoSession* crypto_session,
bool persistent_license,
const CdmKeySetId& key_set_id,
const std::string& usage_info_filename,
const CdmKeyResponse& license_message,
uint32_t* usage_entry_number) {
return UsageTableHeader::AddEntry(crypto_session, persistent_license,
key_set_id, usage_info_filename,
license_message, usage_entry_number);
}
CdmResponseType SuperAddEntry(CryptoSession* crypto_session,
bool persistent_license,
const CdmKeySetId& key_set_id,
const std::string& usage_info_filename,
const CdmKeyResponse& license_message,
uint32_t* usage_entry_number) {
return UsageTableHeader::AddEntry(crypto_session, persistent_license,
key_set_id, usage_info_filename,
license_message, usage_entry_number);
}
};
} // namespace
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) {
@@ -629,7 +622,7 @@ TEST_P(UsageTableHeaderInitializationTest, Upgrade_UnableToRetrieveLicenses) {
.WillOnce(
DoAll(SetArgPointee<1>(kEmptyUsageTableHeader), Return(NO_ERROR)));
// TODO: Why not being called?
//EXPECT_CALL(*device_files_, DeleteAllLicenses()).WillOnce(Return(true));
// EXPECT_CALL(*device_files_, DeleteAllLicenses()).WillOnce(Return(true));
EXPECT_CALL(*device_files_, StoreUsageTableInfo(kEmptyUsageTableHeader,
kEmptyUsageEntryInfoVector))
.WillOnce(Return(true));
@@ -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

View File

@@ -2,7 +2,7 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Compute CRC32 Checksum. Needed for verification of WV Keybox.
// Compute CRC32/MPEG2 Checksum. Needed for verification of WV Keybox.
//
#include "platform.h"
#include "wvcrc32.h"

View File

@@ -0,0 +1,74 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#include <gtest/gtest.h>
#include "wvcrc32.h"
namespace wvoec_ref {
uint32_t ComputeCrc32(const std::string& s) {
return wvcrc32(reinterpret_cast<const uint8_t*>(s.data()), s.size());
}
uint32_t ComputeCrc32Cont(const std::string& s, uint32_t prev_crc) {
return wvcrc32Cont(reinterpret_cast<const uint8_t*>(s.data()), s.size(),
prev_crc);
}
TEST(OEMCryptoWvCrc32Test, BasicTest) {
EXPECT_EQ(0xF88AC628, ComputeCrc32("abcdefg"));
EXPECT_EQ(0xDF520F72, ComputeCrc32("Widevine"));
EXPECT_EQ(0x0376E6E7, ComputeCrc32("123456789"));
EXPECT_EQ(0xBA62119E,
ComputeCrc32("The quick brown fox jumps over the lazy dog"));
}
TEST(OEMCryptoWvCrc32Test, StreamTest) {
const std::vector<std::string> parts = {"The ", "quick", " brown ",
"fox", " jumps ", "over",
" the ", "lazy", " dog"};
uint32_t crc = wvcrc32Init();
for (const auto& part : parts) {
crc = ComputeCrc32Cont(part, crc);
}
EXPECT_EQ(0xBA62119E, crc);
}
TEST(OEMCryptoWvCrc32Test, Keybox) {
// clang-format off
const uint8_t kKeyboxData[128] = {
// deviceID = WidevineCRCTestKeyBox
0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65,
0x43, 0x52, 0x43, 0x54, 0x65, 0x73, 0x74, 0x4b,
0x65, 0x79, 0x62, 0x6f, 0x78, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// key = random
0x8a, 0x7c, 0xda, 0x3e, 0x09, 0xd9, 0x8e, 0xd5,
0x47, 0x47, 0x00, 0x84, 0x5a, 0x1f, 0x52, 0xd4,
// data = random
0x98, 0xa5, 0x00, 0x19, 0x8b, 0xfe, 0x54, 0xfd,
0xca, 0x4d, 0x26, 0xa3, 0xfa, 0xaa, 0x3b, 0x6c,
0x35, 0xfe, 0x03, 0x7c, 0xbf, 0x35, 0xba, 0xce,
0x31, 0xb5, 0x1e, 0x3c, 0x49, 0xd6, 0x3f, 0x9c,
0x3a, 0xde, 0x9b, 0x58, 0xcc, 0x54, 0x8d, 0xc0,
0x4b, 0x04, 0xcc, 0xee, 0xae, 0x4d, 0x9f, 0x90,
0xd3, 0xf3, 0xfe, 0x23, 0x26, 0x13, 0x56, 0x80,
0xe4, 0x3b, 0x79, 0x22, 0x69, 0x5d, 0xd6, 0xb7,
0xa0, 0x0e, 0x7e, 0x07, 0xcd, 0x1a, 0x15, 0xca,
// magic
'k', 'b', 'o', 'x',
// crc
0x09, 0x7b, 0x7e, 0xcc
};
// clang-format on
const uint32_t crc_computed = wvcrc32n(kKeyboxData, 124);
uint32_t crc_current;
memcpy(&crc_current, &kKeyboxData[124], 4);
EXPECT_EQ(crc_computed, crc_current);
}
} // namespace wvoec_ref