Widevine MediaCas client code that works with Android R

This commit is contained in:
Lu Chen
2020-08-13 15:18:12 -07:00
parent ff9728aaa2
commit 0f6db6f751
243 changed files with 47012 additions and 0 deletions

View File

@@ -0,0 +1,132 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#include "widevine_cas_session.h"
#include <cstring>
#include <memory>
#include "log.h"
namespace wvcas {
KeySlot& CasKeySlotData::operator[](KeySlotId slot_id) {
return keys_[static_cast<int>(slot_id)];
}
const KeySlot& CasKeySlotData::operator[](KeySlotId slot_id) const {
return keys_[static_cast<int>(slot_id)];
}
WidevineCasSession::~WidevineCasSession() {
if (crypto_session_ != nullptr) {
crypto_session_->RemoveEntitledKeySession(key_session_id_);
}
}
CasStatus WidevineCasSession::initialize(
std::shared_ptr<CryptoSession> crypto_session, uint32_t* session_id) {
if (crypto_session == nullptr || session_id == nullptr) {
LOGE("WidevineCasSession::initialize: missing input parameters");
return CasStatus(CasStatusCode::kInvalidParameter,
"missing input parameters");
}
crypto_session_ = std::move(crypto_session);
crypto_session_->CreateEntitledKeySession(&key_session_id_);
*session_id = key_session_id_;
return CasStatusCode::kNoError;
}
const KeySlot& WidevineCasSession::key(KeySlotId slot_id) const {
// TODO(): Make this function private and assume the mutex is locked.
// std::unique_lock<std::mutex> lock(lock_);
const KeySlot& key_slot = keys_[slot_id];
return key_slot;
}
CasStatus WidevineCasSession::processEcm(const CasEcm& ecm,
uint8_t parental_control_age) {
if (ecm != current_ecm_) {
LOGD("WidevineCasSession::processEcm: received new ecm");
std::unique_ptr<const EcmParser> ecm_parser = getEcmParser(ecm);
if (!ecm_parser) {
return CasStatus(CasStatusCode::kInvalidParameter, "invalid ecm");
}
ecm_age_restriction_ = ecm_parser->age_restriction();
// Parental control check.
if (parental_control_age > 0 &&
parental_control_age < ecm_age_restriction_) {
const std::string message(1, parental_control_age);
return CasStatus(CasStatusCode::kAccessDeniedByParentalControl, message);
}
bool load_even = false;
bool load_odd = false;
std::unique_lock<std::mutex> lock(lock_);
KeySlotId keyslot_id = KeySlotId::kEvenKeySlot;
// Temporary key slots to only have successfully loaded keys in |keys_|.
CasKeySlotData keys;
do {
if (keys_[keyslot_id].key_id != ecm_parser->content_key_id(keyslot_id)) {
KeySlot& key = keys[keyslot_id];
key.key_id = ecm_parser->content_key_id(keyslot_id);
key.wrapped_key = ecm_parser->wrapped_key_data(keyslot_id);
key.wrapped_key_iv = ecm_parser->wrapped_key_iv(keyslot_id);
key.entitlement_key_id = ecm_parser->entitlement_key_id(keyslot_id);
key.cipher_mode = ecm_parser->crypto_mode();
key.content_iv = ecm_parser->content_iv(keyslot_id);
if (keyslot_id == KeySlotId::kEvenKeySlot) {
load_even = true;
} else {
load_odd = true;
}
if (key.content_iv.size() == 8) {
key.content_iv.resize(16, 0);
}
}
if (!ecm_parser->rotation_enabled() ||
keyslot_id == KeySlotId::kOddKeySlot) {
break;
}
keyslot_id = KeySlotId::kOddKeySlot;
} while (true);
if (load_even || load_odd) {
CasStatus status = crypto_session_->LoadCasECMKeys(
key_session_id_,
(load_even ? &keys[KeySlotId::kEvenKeySlot] : nullptr),
(load_odd ? &keys[KeySlotId::kOddKeySlot] : nullptr));
if (status.status_code() != CasStatusCode::kNoError) {
LOGE("WidevineCasSession::processEcm: error %d, msg %s",
status.status_code(), status.error_string().c_str());
return status;
}
// Don't update on failure, to not to lose still working key_id.
if (load_even) {
keys_[KeySlotId::kEvenKeySlot] = keys[KeySlotId::kEvenKeySlot];
}
if (load_odd) {
keys_[KeySlotId::kOddKeySlot] = keys[KeySlotId::kOddKeySlot];
}
}
current_ecm_ = ecm;
}
return CasStatusCode::kNoError;
}
std::unique_ptr<const EcmParser> WidevineCasSession::getEcmParser(
const CasEcm& ecm) const {
std::unique_ptr<const EcmParser> new_ecm_parser;
if (!EcmParser::create(ecm, &new_ecm_parser)) {
return std::unique_ptr<const EcmParser>();
}
return new_ecm_parser;
}
const char* WidevineCasSession::securityLevel() {
return crypto_session_->SecurityLevel();
}
} // namespace wvcas