Source release 16.2.0

This commit is contained in:
John W. Bruce
2020-04-10 16:13:07 -07:00
parent 1ff9f8588a
commit b830b1d1fb
883 changed files with 509706 additions and 143739 deletions

View File

@@ -7,6 +7,8 @@
#include <limits.h> // LLONG_MAX
#include <string.h> // memcpy
#include <algorithm>
#include <iterator>
#include <memory>
#include <vector>
@@ -20,7 +22,7 @@
#include "file_store.h"
#include "license.h"
#include "log.h"
#include "metrics_collections.h"
#include "metrics.pb.h"
#include "properties.h"
#include "service_certificate.h"
#include "string_conversions.h"
@@ -57,7 +59,7 @@ struct HostType {
initialized(false) {}
} host;
class PropertySet : public CdmClientPropertySet {
class PropertySet final : public CdmClientPropertySet {
public:
PropertySet() : use_privacy_mode_(false) {}
@@ -119,7 +121,7 @@ class PropertySet : public CdmClientPropertySet {
// bugs are resolved, we can change this wrapper to return errors on write
// attempts. The wrapper itself will still be necessary, in order to prevent any
// future bugs from corrupting ATSC files.
class ReadOnlyStorage : public Cdm::IStorage {
class ReadOnlyStorage final : public Cdm::IStorage {
public:
explicit ReadOnlyStorage(Cdm::IStorage* storage) : storage_(storage) {}
~ReadOnlyStorage() override {}
@@ -158,7 +160,23 @@ class ReadOnlyStorage : public Cdm::IStorage {
Cdm::IStorage* storage_; // Lifetime is managed by the caller
};
class CdmImpl : public Cdm, public WvCdmEventListener {
// This class wraps a raw C array passed as a pointer and length in the
// appropriate interface to be used with functions that expect a C++11 range.
template <typename T>
class CArrayRangeView {
public:
CArrayRangeView(const T* data, size_t length)
: data_(data), length_(length) {}
const T* begin() const { return data_; }
const T* end() const { return data_ + length_; }
private:
const T* const data_;
const size_t length_;
};
class CdmImpl final : public Cdm, public WvCdmEventListener {
public:
CdmImpl(IEventListener* listener, IStorage* storage, bool privacy_mode,
const ReadOnlyStorage* owned_storage_object);
@@ -189,8 +207,6 @@ class CdmImpl : public Cdm, public WvCdmEventListener {
Status removeProvisioning() override;
Status removeUsageTable() override;
Status listStoredLicenses(std::vector<std::string>* key_set_ids) override;
Status listUsageRecords(std::vector<std::string>* ksids) override;
@@ -246,10 +262,10 @@ class CdmImpl : public Cdm, public WvCdmEventListener {
Status forceRemove(const std::string& session_id) override;
Status decrypt(const InputBuffer& input, const OutputBuffer& output) override;
Status decrypt(const DecryptionBatch& batch) override;
Status decrypt(const std::string& session_id, const InputBuffer& input,
const OutputBuffer& output) override;
Status decrypt(const std::string& session_id,
const DecryptionBatch& batch) override;
Status genericEncrypt(const std::string& session_id,
const std::string& in_buffer, const std::string& key_id,
@@ -272,6 +288,9 @@ class CdmImpl : public Cdm, public WvCdmEventListener {
Status setVideoResolution(const std::string& session_id, uint32_t width,
uint32_t height) override;
Status getMetrics(std::string* serialized_metrics) override;
// ITimerClient:
void onTimerExpired(void* context) override;
@@ -522,18 +541,6 @@ Cdm::Status CdmImpl::removeProvisioning() {
return kSuccess;
}
Cdm::Status CdmImpl::removeUsageTable() {
CdmResponseType result = cdm_engine_->DeleteUsageTable(kSecurityLevelL1);
if (result == SYSTEM_INVALIDATED_ERROR) {
LOGE("System invalidated");
return kSystemStateLost;
} else if (result != NO_ERROR) {
LOGE("Unexpected error %d", result);
return kUnexpectedError;
}
return kSuccess;
}
Cdm::Status CdmImpl::listStoredLicenses(std::vector<std::string>* key_set_ids) {
if (key_set_ids == nullptr) {
LOGE("Missing vector parameter to receive key_set_ids.");
@@ -881,6 +888,9 @@ Cdm::Status CdmImpl::update(const std::string& session_id,
} else if (result == STORAGE_PROHIBITED) {
LOGE("A temporary session cannot be used for a persistent usage records.");
return kRangeError;
} else if (result == NEED_PROVISIONING) {
LOGE("The device needs to reprovision.");
return kNeedsDeviceCertificate;
} else if (result != KEY_ADDED) {
LOGE("Unexpected error %d", result);
return kUnexpectedError;
@@ -1190,54 +1200,90 @@ Cdm::Status CdmImpl::forceRemove(const std::string& session_id) {
return kSuccess;
}
Cdm::Status CdmImpl::decrypt(const InputBuffer& input,
const OutputBuffer& output) {
Cdm::Status CdmImpl::decrypt(const DecryptionBatch& batch) {
std::string empty_session_id;
return decrypt(empty_session_id, input, output);
return decrypt(empty_session_id, batch);
}
Cdm::Status CdmImpl::decrypt(const std::string& session_id,
const InputBuffer& input,
const OutputBuffer& output) {
const bool is_encrypted = (input.encryption_scheme != kClear);
if (is_encrypted && input.iv_length != 16) {
LOGE("The IV must be 16 bytes long.");
return kTypeError;
const DecryptionBatch& batch) {
if (batch.encryption_scheme == kAesCtr &&
(batch.pattern.encrypted_blocks != 0 ||
batch.pattern.clear_blocks != 0)) {
LOGE("The 'cens' schema is not supported.");
return kNotSupported;
}
if (PropertiesCE::GetSecureOutputType() == kNoSecureOutput &&
output.is_secure) {
batch.is_secure) {
LOGE("The CDM is configured without secure output support.");
return kNotSupported;
}
std::string key_id(reinterpret_cast<const char*>(input.key_id),
input.key_id_length);
std::vector<uint8_t> iv(input.iv, input.iv + input.iv_length);
const CArrayRangeView<Sample> samples(batch.samples, batch.samples_length);
for (const Sample& sample : samples) {
if (sample.input.data_length >
(sample.output.data_length - sample.output.data_offset)) {
LOGE("The output buffer is too small to contain the input buffer.");
return kTypeError;
}
CdmDecryptionParameters parameters;
parameters.is_encrypted = is_encrypted;
parameters.is_secure = output.is_secure;
if (input.encryption_scheme == kAesCtr) {
const CArrayRangeView<Subsample> subsamples(sample.input.subsamples,
sample.input.subsamples_length);
const bool is_encrypted =
(batch.encryption_scheme != kClear) &&
std::any_of(std::begin(subsamples), std::end(subsamples),
[](const Subsample& subsample) -> bool {
return subsample.protected_bytes > 0;
});
if (is_encrypted && sample.input.iv_length != 16) {
LOGE("The IV must be 16 bytes long.");
return kTypeError;
}
}
// With the input validated, we may copy it into a CdmDecryptionParametersV16
CdmDecryptionParametersV16 parameters;
parameters.key_id.assign(batch.key_id, batch.key_id + batch.key_id_length);
parameters.is_secure = batch.is_secure;
if (batch.encryption_scheme == kAesCtr) {
parameters.cipher_mode = kCipherModeCtr;
} else if (input.encryption_scheme == kAesCbc) {
} else if (batch.encryption_scheme == kAesCbc) {
parameters.cipher_mode = kCipherModeCbc;
}
parameters.key_id = &key_id;
parameters.encrypt_buffer = input.data;
parameters.encrypt_length = input.data_length;
parameters.iv = &iv;
parameters.block_offset = input.block_offset;
parameters.decrypt_buffer = output.data;
parameters.decrypt_buffer_length = output.data_length;
parameters.decrypt_buffer_offset = output.data_offset;
parameters.subsample_flags =
(input.first_subsample ? OEMCrypto_FirstSubsample : 0) |
(input.last_subsample ? OEMCrypto_LastSubsample : 0);
parameters.is_video = input.is_video;
parameters.pattern_descriptor.encrypt_blocks = input.pattern.encrypted_blocks;
parameters.pattern_descriptor.skip_blocks = input.pattern.clear_blocks;
parameters.is_video = batch.is_video;
parameters.pattern.encrypt_blocks = batch.pattern.encrypted_blocks;
parameters.pattern.skip_blocks = batch.pattern.clear_blocks;
CdmResponseType result = cdm_engine_->Decrypt(session_id, parameters);
parameters.samples.reserve(batch.samples_length);
std::transform(
std::begin(samples), std::end(samples),
std::back_inserter(parameters.samples),
[](const Sample& sample) -> CdmDecryptionSample {
CdmDecryptionSample cdm_sample;
cdm_sample.encrypt_buffer = sample.input.data;
cdm_sample.encrypt_buffer_length = sample.input.data_length;
cdm_sample.decrypt_buffer = sample.output.data;
cdm_sample.decrypt_buffer_size = sample.output.data_length;
cdm_sample.decrypt_buffer_offset = sample.output.data_offset;
cdm_sample.iv.assign(sample.input.iv,
sample.input.iv + sample.input.iv_length);
const CArrayRangeView<Subsample> subsamples(
sample.input.subsamples, sample.input.subsamples_length);
cdm_sample.subsamples.reserve(sample.input.subsamples_length);
std::transform(
std::begin(subsamples), std::end(subsamples),
std::back_inserter(cdm_sample.subsamples),
[](const Subsample& subsample) -> CdmDecryptionSubsample {
return CdmDecryptionSubsample(subsample.clear_bytes,
subsample.protected_bytes);
});
return cdm_sample;
});
CdmResponseType result = cdm_engine_->DecryptV16(session_id, parameters);
if (result == NO_ERROR) {
return kSuccess;
@@ -1442,6 +1488,20 @@ Cdm::Status CdmImpl::setVideoResolution(const std::string& session_id,
}
}
Cdm::Status CdmImpl::getMetrics(std::string* serialized_metrics) {
if (serialized_metrics == nullptr) {
LOGE("Missing string parameter to receive serialized metrics.");
return kTypeError;
}
drm_metrics::WvCdmMetrics metrics;
if (!cdm_engine_->GetMetricsSnapshot(&metrics) ||
!metrics.SerializeToString(serialized_metrics)) {
return kUnexpectedError;
}
return kSuccess;
}
void CdmImpl::onTimerExpired(void* context) {
if (context == kPolicyTimerContext) {
if (policy_timer_enabled_) {
@@ -1674,21 +1734,21 @@ using namespace widevine;
int64_t Clock::GetCurrentTime() { return host.clock->now() / 1000; }
class FileImpl : public File {
class FileImpl final : public File {
public:
FileImpl() {}
~FileImpl() override {}
FileImpl(Cdm::IStorage* storage, const std::string& path, int flags)
: storage_(storage),
name_(path),
read_only_(flags & FileSystem::kReadOnly),
truncate_(flags & FileSystem::kTruncate) {
assert(storage_);
}
ssize_t Read(char* buffer, size_t bytes) override {
if (!buffer) {
LOGW("File::Read: buffer is empty");
return -1;
}
if (!storage_) {
LOGW("File::Open: buffer is empty");
return -1;
}
std::string data;
if (!storage_->read(name_, &data)) {
return -1;
@@ -1704,8 +1764,8 @@ class FileImpl : public File {
LOGW("File::Write: buffer is empty");
return -1;
}
if (!storage_) {
LOGW("File::Write: file not open");
if (read_only_) {
LOGE("File::Write: file is read-only.");
return -1;
}
if (!truncate_) {
@@ -1719,67 +1779,54 @@ class FileImpl : public File {
return bytes;
}
Cdm::IStorage* storage_;
std::string name_;
bool read_only_;
bool truncate_;
private:
Cdm::IStorage* const storage_;
const std::string name_;
const bool read_only_;
const bool truncate_;
};
class FileSystem::Impl {
public:
widevine::Cdm::IStorage* storage_;
Impl(widevine::Cdm::IStorage* storage) : storage_(storage) {
assert(storage);
}
widevine::Cdm::IStorage* const storage_;
};
FileSystem::FileSystem() : impl_(new Impl()) {
assert(nullptr != host.storage);
impl_->storage_ = host.storage;
}
FileSystem::FileSystem() : impl_(new Impl(host.storage)) {}
FileSystem::FileSystem(const std::string& origin, void* extra_data)
: impl_(new Impl()), origin_(origin) {
assert(nullptr != extra_data);
impl_->storage_ = (widevine::Cdm::IStorage*)extra_data;
}
: impl_(new Impl(reinterpret_cast<widevine::Cdm::IStorage*>(extra_data))),
origin_(origin) {}
FileSystem::~FileSystem() {}
std::unique_ptr<File> FileSystem::Open(const std::string& file_path,
int flags) {
if (!impl_ || (!(flags & kCreate) && !impl_->storage_->exists(file_path))) {
if (!(flags & kCreate) && !impl_->storage_->exists(file_path)) {
return nullptr;
}
std::unique_ptr<FileImpl> file_impl(new FileImpl());
file_impl->storage_ = impl_->storage_;
file_impl->name_ = file_path;
file_impl->read_only_ = (flags & kReadOnly);
file_impl->truncate_ = (flags & kTruncate);
return std::move(file_impl);
return std::unique_ptr<File>(new FileImpl(impl_->storage_, file_path, flags));
}
bool FileSystem::Exists(const std::string& file_path) {
if (!impl_) return false;
return !file_path.empty() && impl_->storage_->exists(file_path);
}
bool FileSystem::Remove(const std::string& file_path) {
if (!impl_) return false;
return impl_->storage_->remove(file_path);
}
ssize_t FileSystem::FileSize(const std::string& file_path) {
if (!impl_) return -1;
return impl_->storage_->size(file_path);
}
bool FileSystem::List(const std::string&,
std::vector<std::string>* file_names) {
if (!impl_ || !file_names) return false;
return impl_->storage_->list(file_names);
return file_names && impl_->storage_->list(file_names);
}
} // namespace wvcdm