Source release v2.1.1-0-738 + third_party libs
Change-Id: I76e298f8092951d4214c776d6bbcad6b763eb5b2
This commit is contained in:
@@ -5,7 +5,6 @@
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "buffer_reader.h"
|
||||
#include "cdm_session.h"
|
||||
#include "license_protocol.pb.h"
|
||||
#include "log.h"
|
||||
@@ -94,8 +93,9 @@ CdmResponseType CdmEngine::CloseSession(const CdmSessionId& session_id) {
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
delete iter->second;
|
||||
CdmSession* session = iter->second;
|
||||
sessions_.erase(session_id);
|
||||
delete session;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ CdmResponseType CdmEngine::CloseKeySetSession(const CdmKeySetId& key_set_id) {
|
||||
CdmResponseType CdmEngine::GenerateKeyRequest(
|
||||
const CdmSessionId& session_id,
|
||||
const CdmKeySetId& key_set_id,
|
||||
const CdmInitData& init_data,
|
||||
const InitializationData& init_data,
|
||||
const CdmLicenseType license_type,
|
||||
CdmAppParameterMap& app_parameters,
|
||||
CdmKeyMessage* key_request,
|
||||
@@ -433,6 +433,8 @@ CdmResponseType CdmEngine::QueryKeyControlInfo(
|
||||
* Returns NO_ERROR for success and UNKNOWN_ERROR if fails.
|
||||
*/
|
||||
CdmResponseType CdmEngine::GetProvisioningRequest(
|
||||
CdmCertificateType cert_type,
|
||||
const std::string& cert_authority,
|
||||
CdmProvisioningRequest* request,
|
||||
std::string* default_url) {
|
||||
if (!request || !default_url) {
|
||||
@@ -441,6 +443,8 @@ CdmResponseType CdmEngine::GetProvisioningRequest(
|
||||
}
|
||||
return cert_provisioning_.GetProvisioningRequest(
|
||||
cert_provisioning_requested_security_level_,
|
||||
cert_type,
|
||||
cert_authority,
|
||||
request,
|
||||
default_url);
|
||||
}
|
||||
@@ -453,12 +457,35 @@ CdmResponseType CdmEngine::GetProvisioningRequest(
|
||||
* Returns NO_ERROR for success and UNKNOWN_ERROR if fails.
|
||||
*/
|
||||
CdmResponseType CdmEngine::HandleProvisioningResponse(
|
||||
CdmProvisioningResponse& response) {
|
||||
CdmProvisioningResponse& response,
|
||||
std::string* cert,
|
||||
std::string* wrapped_key) {
|
||||
if (response.empty()) {
|
||||
LOGE("CdmEngine::HandleProvisioningResponse: Empty provisioning response.");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
return cert_provisioning_.HandleProvisioningResponse(response);
|
||||
if (NULL == cert) {
|
||||
LOGE("CdmEngine::HandleProvisioningResponse: invalid certificate "
|
||||
"destination");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
if (NULL == wrapped_key) {
|
||||
LOGE("CdmEngine::HandleProvisioningResponse: invalid wrapped key "
|
||||
"destination");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
return cert_provisioning_.HandleProvisioningResponse(response, cert,
|
||||
wrapped_key);
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::GetSecureStops(
|
||||
CdmSecureStops* secure_stops) {
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::ReleaseSecureStops(
|
||||
const CdmSecureStopReleaseMessage& message) {
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::Decrypt(
|
||||
@@ -489,8 +516,6 @@ CdmResponseType CdmEngine::Decrypt(
|
||||
|
||||
CdmSessionMap::iterator iter;
|
||||
if (session_id.empty()) {
|
||||
if (!Properties::decrypt_with_empty_session_support()) return KEY_ERROR;
|
||||
|
||||
// Loop through the sessions to find the session containing the key_id.
|
||||
for (iter = sessions_.begin(); iter != sessions_.end(); ++iter) {
|
||||
if (iter->second->IsKeyLoaded(*parameters.key_id)) {
|
||||
@@ -501,7 +526,7 @@ CdmResponseType CdmEngine::Decrypt(
|
||||
iter = sessions_.find(session_id);
|
||||
}
|
||||
if (iter == sessions_.end()) {
|
||||
LOGE("CdmEngine::Decrypt: session_id not found[%d] = %s",
|
||||
LOGE("CdmEngine::Decrypt: session not found: id=%s, id size=%d",
|
||||
session_id.size(),
|
||||
session_id.c_str());
|
||||
return KEY_ERROR;
|
||||
@@ -578,94 +603,6 @@ bool CdmEngine::ValidateKeySystem(const CdmKeySystem& key_system) {
|
||||
return (key_system.find("widevine") != std::string::npos);
|
||||
}
|
||||
|
||||
// Parse a blob of multiple concatenated PSSH atoms to extract the first
|
||||
// widevine pssh
|
||||
bool CdmEngine::ExtractWidevinePssh(
|
||||
const CdmInitData& init_data, CdmInitData* output) {
|
||||
|
||||
BufferReader reader(
|
||||
reinterpret_cast<const uint8_t*>(init_data.data()), init_data.length());
|
||||
|
||||
static const uint8_t kWidevineSystemId[] = {
|
||||
0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE,
|
||||
0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED,
|
||||
};
|
||||
|
||||
// one PSSH blob consists of:
|
||||
// 4 byte size of the PSSH atom, inclusive
|
||||
// "pssh"
|
||||
// 4 byte flags, value 0
|
||||
// 16 byte system id
|
||||
// 4 byte size of PSSH data, exclusive
|
||||
while (1) {
|
||||
// size of PSSH atom, used for skipping
|
||||
uint32_t size;
|
||||
if (!reader.Read4(&size)) {
|
||||
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH atom size");
|
||||
return false;
|
||||
}
|
||||
|
||||
// "pssh"
|
||||
std::vector<uint8_t> pssh;
|
||||
if (!reader.ReadVec(&pssh, 4)) {
|
||||
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH literal");
|
||||
return false;
|
||||
}
|
||||
if (memcmp(&pssh[0], "pssh", 4)) {
|
||||
LOGW("CdmEngine::ExtractWidevinePssh: PSSH literal not present");
|
||||
return false;
|
||||
}
|
||||
|
||||
// flags
|
||||
uint32_t flags;
|
||||
if (!reader.Read4(&flags)) {
|
||||
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH flags");
|
||||
return false;
|
||||
}
|
||||
if (flags != 0) {
|
||||
LOGW("CdmEngine::ExtractWidevinePssh: PSSH flags not zero");
|
||||
return false;
|
||||
}
|
||||
|
||||
// system id
|
||||
std::vector<uint8_t> system_id;
|
||||
if (!reader.ReadVec(&system_id, sizeof(kWidevineSystemId))) {
|
||||
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read system ID");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (memcmp(&system_id[0], kWidevineSystemId,
|
||||
sizeof(kWidevineSystemId))) {
|
||||
// skip the remaining contents of the atom,
|
||||
// after size field, atom name, flags and system id
|
||||
if (!reader.SkipBytes(
|
||||
size - 4 - 4 - 4 - sizeof(kWidevineSystemId))) {
|
||||
LOGW("CdmEngine::ExtractWidevinePssh: Unable to rest of PSSH atom");
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// size of PSSH box
|
||||
uint32_t pssh_length;
|
||||
if (!reader.Read4(&pssh_length)) {
|
||||
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH box size");
|
||||
return false;
|
||||
}
|
||||
|
||||
output->clear();
|
||||
if (!reader.ReadString(output, pssh_length)) {
|
||||
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// we did not find a matching record
|
||||
return false;
|
||||
}
|
||||
|
||||
void CdmEngine::OnTimerEvent() {
|
||||
for (CdmSessionMap::iterator iter = sessions_.begin();
|
||||
iter != sessions_.end(); ++iter) {
|
||||
|
||||
@@ -78,7 +78,7 @@ CdmResponseType CdmSession::RestoreOfflineSession(
|
||||
|
||||
DeviceFiles::LicenseState license_state;
|
||||
|
||||
if (!handle.RetrieveLicense(key_set_id, &license_state, &offline_pssh_data_,
|
||||
if (!handle.RetrieveLicense(key_set_id, &license_state, &offline_init_data_,
|
||||
&offline_key_request_, &offline_key_response_,
|
||||
&offline_key_renewal_request_,
|
||||
&offline_key_renewal_response_,
|
||||
@@ -114,7 +114,7 @@ CdmResponseType CdmSession::RestoreOfflineSession(
|
||||
}
|
||||
|
||||
CdmResponseType CdmSession::GenerateKeyRequest(
|
||||
const CdmInitData& init_data, const CdmLicenseType license_type,
|
||||
const InitializationData& init_data, const CdmLicenseType license_type,
|
||||
const CdmAppParameterMap& app_parameters, CdmKeyMessage* key_request,
|
||||
std::string* server_url) {
|
||||
if (reinitialize_session_) {
|
||||
@@ -140,20 +140,16 @@ CdmResponseType CdmSession::GenerateKeyRequest(
|
||||
if (license_type_ == kLicenseTypeRelease) {
|
||||
return GenerateReleaseRequest(key_request, server_url);
|
||||
} else if (license_received_) { // renewal
|
||||
return Properties::require_explicit_renew_request()
|
||||
? UNKNOWN_ERROR
|
||||
: GenerateRenewalRequest(key_request, server_url);
|
||||
return GenerateRenewalRequest(key_request, server_url);
|
||||
} else {
|
||||
if (init_data.empty() && !license_parser_.HasInitData()) {
|
||||
LOGW("CdmSession::GenerateKeyRequest: init data absent");
|
||||
if (!init_data.is_supported()) {
|
||||
LOGW("CdmSession::GenerateKeyRequest: unsupported init data type (%s)",
|
||||
init_data.type().c_str());
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
CdmInitData pssh_data = init_data;
|
||||
if (Properties::extract_pssh_data()) {
|
||||
if (!CdmEngine::ExtractWidevinePssh(init_data, &pssh_data)) {
|
||||
return KEY_ERROR;
|
||||
}
|
||||
if (init_data.IsEmpty() && !license_parser_.HasInitData()) {
|
||||
LOGW("CdmSession::GenerateKeyRequest: init data absent");
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
if (Properties::use_certificates_as_identification()) {
|
||||
@@ -166,14 +162,14 @@ CdmResponseType CdmSession::GenerateKeyRequest(
|
||||
}
|
||||
}
|
||||
|
||||
if (!license_parser_.PrepareKeyRequest(pssh_data, license_type,
|
||||
if (!license_parser_.PrepareKeyRequest(init_data, license_type,
|
||||
app_parameters, session_id_,
|
||||
key_request, server_url)) {
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
if (license_type_ == kLicenseTypeOffline) {
|
||||
offline_pssh_data_ = pssh_data;
|
||||
offline_init_data_ = init_data.data();
|
||||
offline_key_request_ = *key_request;
|
||||
offline_release_server_url_ = *server_url;
|
||||
}
|
||||
@@ -198,9 +194,7 @@ CdmResponseType CdmSession::AddKey(const CdmKeyResponse& key_response,
|
||||
if (license_type_ == kLicenseTypeRelease) {
|
||||
return ReleaseKey(key_response);
|
||||
} else if (license_received_) { // renewal
|
||||
return Properties::require_explicit_renew_request()
|
||||
? UNKNOWN_ERROR
|
||||
: RenewKey(key_response);
|
||||
return RenewKey(key_response);
|
||||
} else {
|
||||
CdmResponseType sts = license_parser_.HandleKeyResponse(key_response);
|
||||
|
||||
@@ -296,18 +290,7 @@ CdmResponseType CdmSession::CancelKeyRequest() {
|
||||
CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) {
|
||||
if (crypto_session_.get() == NULL || !crypto_session_->IsOpen())
|
||||
return UNKNOWN_ERROR;
|
||||
|
||||
CdmResponseType status = crypto_session_->Decrypt(params);
|
||||
if (UNKNOWN_ERROR == status) {
|
||||
// Decrypt failed - check status of license and keys.
|
||||
Clock clock;
|
||||
int64_t current_time = clock.GetCurrentTime();
|
||||
if (policy_engine_.IsLicenseDurationExpired(current_time) ||
|
||||
policy_engine_.IsPlaybackDurationExpired(current_time)) {
|
||||
return NEED_KEY;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
return crypto_session_->Decrypt(params);
|
||||
}
|
||||
|
||||
// License renewal
|
||||
@@ -404,7 +387,7 @@ bool CdmSession::StoreLicense(DeviceFiles::LicenseState state) {
|
||||
return false;
|
||||
|
||||
return handle.StoreLicense(
|
||||
key_set_id_, state, offline_pssh_data_, offline_key_request_,
|
||||
key_set_id_, state, offline_init_data_, offline_key_request_,
|
||||
offline_key_response_, offline_key_renewal_request_,
|
||||
offline_key_renewal_response_, offline_release_server_url_);
|
||||
}
|
||||
|
||||
@@ -6,12 +6,13 @@
|
||||
#include "license_protocol.pb.h"
|
||||
#include "log.h"
|
||||
#include "string_conversions.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// WHAT: URL for Google Provisioning Server.
|
||||
// WHY: The provisioning server supplies the certificate that is needed
|
||||
// to communicate with the License Server.
|
||||
// URL for Google Provisioning Server.
|
||||
// The provisioning server supplies the certificate that is needed
|
||||
// to communicate with the License Server.
|
||||
const std::string kProvisioningServerUrl =
|
||||
"https://www.googleapis.com/"
|
||||
"certificateprovisioning/v1/devicecertificates/create"
|
||||
@@ -21,6 +22,7 @@ const std::string kProvisioningServerUrl =
|
||||
namespace wvcdm {
|
||||
// Protobuf generated classes.
|
||||
using video_widevine_server::sdk::ClientIdentification;
|
||||
using video_widevine_server::sdk::ProvisioningOptions;
|
||||
using video_widevine_server::sdk::ProvisioningRequest;
|
||||
using video_widevine_server::sdk::ProvisioningResponse;
|
||||
using video_widevine_server::sdk::SignedProvisioningMessage;
|
||||
@@ -58,6 +60,8 @@ void CertificateProvisioning::ComposeJsonRequestAsQueryString(
|
||||
*/
|
||||
CdmResponseType CertificateProvisioning::GetProvisioningRequest(
|
||||
SecurityLevel requested_security_level,
|
||||
CdmCertificateType cert_type,
|
||||
const std::string& cert_authority,
|
||||
CdmProvisioningRequest* request,
|
||||
std::string* default_url) {
|
||||
if (!default_url) {
|
||||
@@ -95,6 +99,24 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequest(
|
||||
std::string the_nonce(reinterpret_cast<char*>(&nonce), sizeof(nonce));
|
||||
provisioning_request.set_nonce(the_nonce);
|
||||
|
||||
ProvisioningOptions* options = provisioning_request.mutable_options();
|
||||
switch (cert_type) {
|
||||
case kCertificateWidevine:
|
||||
options->set_certificate_type(
|
||||
video_widevine_server::sdk::ProvisioningOptions_CertificateType_RSA_WIDEVINE);
|
||||
break;
|
||||
case kCertificateX509:
|
||||
options->set_certificate_type(
|
||||
video_widevine_server::sdk::ProvisioningOptions_CertificateType_X509);
|
||||
break;
|
||||
default:
|
||||
LOGE("GetProvisioningRequest: unknown certificate type %ld", cert_type);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
cert_type_ = cert_type;
|
||||
options->set_certificate_authority(cert_authority);
|
||||
|
||||
std::string serialized_message;
|
||||
provisioning_request.SerializeToString(&serialized_message);
|
||||
|
||||
@@ -164,7 +186,9 @@ bool CertificateProvisioning::ParseJsonResponse(
|
||||
* Returns NO_ERROR for success and UNKNOWN_ERROR if fails.
|
||||
*/
|
||||
CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
||||
CdmProvisioningResponse& response) {
|
||||
CdmProvisioningResponse& response,
|
||||
std::string* cert,
|
||||
std::string* wrapped_key) {
|
||||
|
||||
// Extracts signed response from JSON string, decodes base64 signed response
|
||||
const std::string kMessageStart = "\"signedResponse\": \"";
|
||||
@@ -229,6 +253,12 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
||||
|
||||
crypto_session_.Close();
|
||||
|
||||
if (cert_type_ == kCertificateX509) {
|
||||
*cert = provisioning_response.device_certificate();
|
||||
*wrapped_key = wrapped_rsa_key;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
const std::string& device_certificate =
|
||||
provisioning_response.device_certificate();
|
||||
|
||||
|
||||
@@ -235,7 +235,6 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
|
||||
sizeof(request_id_base_));
|
||||
++request_id_index_;
|
||||
return NO_ERROR;
|
||||
|
||||
}
|
||||
|
||||
void CryptoSession::Close() {
|
||||
@@ -271,9 +270,9 @@ bool CryptoSession::PrepareRequest(const std::string& message,
|
||||
if (!Properties::use_certificates_as_identification() || is_provisioning) {
|
||||
if (!GenerateDerivedKeys(message)) return false;
|
||||
|
||||
if (!GenerateSignature(message, false, signature)) return false;
|
||||
if (!GenerateSignature(message, signature)) return false;
|
||||
} else {
|
||||
if (!GenerateSignature(message, true, signature)) return false;
|
||||
if (!GenerateRsaSignature(message, signature)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -285,12 +284,13 @@ bool CryptoSession::PrepareRenewalRequest(const std::string& message,
|
||||
AutoLock auto_lock(crypto_lock_);
|
||||
|
||||
if (!signature) {
|
||||
LOGE("CryptoSession::PrepareRenewalRequest : No output destination "
|
||||
"provided.");
|
||||
LOGE(
|
||||
"CryptoSession::PrepareRenewalRequest : No output destination "
|
||||
"provided.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!GenerateSignature(message, false, signature)) {
|
||||
if (!GenerateSignature(message, signature)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -316,8 +316,9 @@ void CryptoSession::GenerateMacContext(const std::string& input_context,
|
||||
void CryptoSession::GenerateEncryptContext(const std::string& input_context,
|
||||
std::string* deriv_context) {
|
||||
if (!deriv_context) {
|
||||
LOGE("CryptoSession::GenerateEncryptContext : No output destination "
|
||||
"provided.");
|
||||
LOGE(
|
||||
"CryptoSession::GenerateEncryptContext : No output destination "
|
||||
"provided.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -380,7 +381,7 @@ CdmResponseType CryptoSession::LoadKeys(const std::string& message,
|
||||
OEMCryptoResult sts = OEMCrypto_LoadKeys(
|
||||
oec_session_id_, msg, message.size(),
|
||||
reinterpret_cast<const uint8_t*>(signature.data()), signature.size(),
|
||||
enc_mac_key_iv, enc_mac_key, num_keys, &load_key_array[0]);
|
||||
enc_mac_key_iv, enc_mac_key, num_keys, &load_key_array[0], NULL, 0);
|
||||
|
||||
if (OEMCrypto_SUCCESS == sts) {
|
||||
return KEY_ADDED;
|
||||
@@ -502,48 +503,77 @@ bool CryptoSession::GenerateDerivedKeys(const std::string& message,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CryptoSession::GenerateSignature(const std::string& message, bool use_rsa,
|
||||
bool CryptoSession::GenerateSignature(const std::string& message,
|
||||
std::string* signature) {
|
||||
LOGV("GenerateSignature: id=%ld", (uint32_t)oec_session_id_);
|
||||
if (!signature) return false;
|
||||
|
||||
size_t length = 0;
|
||||
OEMCryptoResult sts = OEMCrypto_SUCCESS;
|
||||
if (use_rsa) {
|
||||
sts = OEMCrypto_GenerateRSASignature(
|
||||
oec_session_id_, reinterpret_cast<const uint8_t*>(message.data()),
|
||||
message.size(), NULL, &length);
|
||||
if (OEMCrypto_ERROR_SHORT_BUFFER != sts) {
|
||||
LOGD("GenerateSignature: OEMCrypto_GenerateRSASignature err=%d", sts);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
sts = OEMCrypto_GenerateSignature(
|
||||
oec_session_id_, reinterpret_cast<const uint8_t*>(message.data()),
|
||||
message.size(), NULL, &length);
|
||||
}
|
||||
|
||||
signature->resize(length);
|
||||
|
||||
if (use_rsa) {
|
||||
sts = OEMCrypto_GenerateRSASignature(
|
||||
oec_session_id_, reinterpret_cast<const uint8_t*>(message.data()),
|
||||
message.size(),
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(signature->data())),
|
||||
&length);
|
||||
} else {
|
||||
sts = OEMCrypto_GenerateSignature(
|
||||
oec_session_id_, reinterpret_cast<const uint8_t*>(message.data()),
|
||||
message.size(),
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(signature->data())),
|
||||
&length);
|
||||
}
|
||||
size_t length = signature->size();
|
||||
OEMCryptoResult sts = OEMCrypto_GenerateSignature(
|
||||
oec_session_id_, reinterpret_cast<const uint8_t*>(message.data()),
|
||||
message.size(),
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(signature->data())),
|
||||
&length);
|
||||
|
||||
if (OEMCrypto_SUCCESS != sts) {
|
||||
LOGD("GenerateSignature: OEMCrypto_GenerateSignature err=%d", sts);
|
||||
return false;
|
||||
if (OEMCrypto_ERROR_SHORT_BUFFER != sts) {
|
||||
LOGD("GenerateSignature: OEMCrypto_GenerateSignature err=%d", sts);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Retry with proper-sized signature buffer
|
||||
signature->resize(length);
|
||||
sts = OEMCrypto_GenerateSignature(
|
||||
oec_session_id_, reinterpret_cast<const uint8_t*>(message.data()),
|
||||
message.size(),
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(signature->data())),
|
||||
&length);
|
||||
|
||||
if (OEMCrypto_SUCCESS != sts) {
|
||||
LOGD("GenerateSignature: OEMCrypto_GenerateSignature err=%d", sts);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Trim signature buffer
|
||||
signature->resize(length);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CryptoSession::GenerateRsaSignature(const std::string& message,
|
||||
std::string* signature) {
|
||||
LOGV("GenerateRsaSignature: id=%ld", (uint32_t)oec_session_id_);
|
||||
if (!signature) return false;
|
||||
|
||||
size_t length = signature->size();
|
||||
OEMCryptoResult sts = OEMCrypto_GenerateRSASignature(
|
||||
oec_session_id_, reinterpret_cast<const uint8_t*>(message.data()),
|
||||
message.size(),
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(signature->data())),
|
||||
&length, kSign_RSASSA_PSS);
|
||||
|
||||
if (OEMCrypto_SUCCESS != sts) {
|
||||
if (OEMCrypto_ERROR_SHORT_BUFFER != sts) {
|
||||
LOGD("GenerateRsaSignature: OEMCrypto_GenerateRSASignature err=%d", sts);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Retry with proper-sized signature buffer
|
||||
signature->resize(length);
|
||||
sts = OEMCrypto_GenerateRSASignature(
|
||||
oec_session_id_, reinterpret_cast<const uint8_t*>(message.data()),
|
||||
message.size(),
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(signature->data())),
|
||||
&length, kSign_RSASSA_PSS);
|
||||
|
||||
if (OEMCrypto_SUCCESS != sts) {
|
||||
LOGD("GenerateRsaSignature: OEMCrypto_GenerateRSASignature err=%d", sts);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Trim signature buffer
|
||||
signature->resize(length);
|
||||
|
||||
return true;
|
||||
|
||||
@@ -459,15 +459,17 @@ bool DeviceFiles::RetrieveFile(const char* name, std::string* data) {
|
||||
void DeviceFiles::SecurityLevelPathBackwardCompatibility() {
|
||||
std::string path;
|
||||
if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) {
|
||||
LOGW("DeviceFiles::SecurityLevelPathBackwardCompatibility: Unable to "
|
||||
"get base path");
|
||||
LOGW(
|
||||
"DeviceFiles::SecurityLevelPathBackwardCompatibility: Unable to "
|
||||
"get base path");
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> security_dirs;
|
||||
if (!Properties::GetSecurityLevelDirectories(&security_dirs)) {
|
||||
LOGW("DeviceFiles::SecurityLevelPathBackwardCompatibility: Unable to "
|
||||
"get security directories");
|
||||
LOGW(
|
||||
"DeviceFiles::SecurityLevelPathBackwardCompatibility: Unable to "
|
||||
"get security directories");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -482,8 +484,9 @@ void DeviceFiles::SecurityLevelPathBackwardCompatibility() {
|
||||
}
|
||||
|
||||
if (pos == std::string::npos) {
|
||||
LOGV("DeviceFiles::SecurityLevelPathBackwardCompatibility: Security level "
|
||||
"specific path not found. Check properties?");
|
||||
LOGV(
|
||||
"DeviceFiles::SecurityLevelPathBackwardCompatibility: Security level "
|
||||
"specific path not found. Check properties?");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
125
core/src/initialization_data.cpp
Normal file
125
core/src/initialization_data.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
|
||||
#include "initialization_data.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "buffer_reader.h"
|
||||
#include "log.h"
|
||||
#include "properties.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
InitializationData::InitializationData(const std::string& type,
|
||||
const CdmInitData& data)
|
||||
: type_(type), is_cenc_(false), is_webm_(false) {
|
||||
if (type == ISO_BMFF_VIDEO_MIME_TYPE ||
|
||||
type == ISO_BMFF_AUDIO_MIME_TYPE ||
|
||||
type == CENC_INIT_DATA_FORMAT) {
|
||||
is_cenc_ = true;
|
||||
} else if (type == WEBM_VIDEO_MIME_TYPE ||
|
||||
type == WEBM_AUDIO_MIME_TYPE ||
|
||||
type == WEBM_INIT_DATA_FORMAT) {
|
||||
is_webm_ = true;
|
||||
}
|
||||
|
||||
if (is_supported()) {
|
||||
if (is_cenc()) {
|
||||
ExtractWidevinePssh(data, &data_);
|
||||
} else {
|
||||
data_ = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse a blob of multiple concatenated PSSH atoms to extract the first
|
||||
// Widevine PSSH.
|
||||
bool InitializationData::ExtractWidevinePssh(
|
||||
const CdmInitData& init_data, CdmInitData* output) {
|
||||
BufferReader reader(
|
||||
reinterpret_cast<const uint8_t*>(init_data.data()), init_data.length());
|
||||
|
||||
// TODO(kqyang): Extracted from an actual init_data;
|
||||
// Need to find out where it comes from.
|
||||
static const uint8_t kWidevineSystemId[] = {
|
||||
0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE,
|
||||
0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED,
|
||||
};
|
||||
|
||||
// one PSSH blob consists of:
|
||||
// 4 byte size of the PSSH atom, inclusive
|
||||
// "pssh"
|
||||
// 4 byte flags, value 0
|
||||
// 16 byte system id
|
||||
// 4 byte size of PSSH data, exclusive
|
||||
while (1) {
|
||||
// size of PSSH atom, used for skipping
|
||||
uint32_t size;
|
||||
if (!reader.Read4(&size)) {
|
||||
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH atom size");
|
||||
return false;
|
||||
}
|
||||
|
||||
// "pssh"
|
||||
std::vector<uint8_t> pssh;
|
||||
if (!reader.ReadVec(&pssh, 4)) {
|
||||
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH literal");
|
||||
return false;
|
||||
}
|
||||
if (memcmp(&pssh[0], "pssh", 4)) {
|
||||
LOGW("CdmEngine::ExtractWidevinePssh: PSSH literal not present");
|
||||
return false;
|
||||
}
|
||||
|
||||
// flags
|
||||
uint32_t flags;
|
||||
if (!reader.Read4(&flags)) {
|
||||
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH flags");
|
||||
return false;
|
||||
}
|
||||
if (flags != 0) {
|
||||
LOGW("CdmEngine::ExtractWidevinePssh: PSSH flags not zero");
|
||||
return false;
|
||||
}
|
||||
|
||||
// system id
|
||||
std::vector<uint8_t> system_id;
|
||||
if (!reader.ReadVec(&system_id, sizeof(kWidevineSystemId))) {
|
||||
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read system ID");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (memcmp(&system_id[0], kWidevineSystemId,
|
||||
sizeof(kWidevineSystemId))) {
|
||||
// skip the remaining contents of the atom,
|
||||
// after size field, atom name, flags and system id
|
||||
if (!reader.SkipBytes(
|
||||
size - 4 - 4 - 4 - sizeof(kWidevineSystemId))) {
|
||||
LOGW("CdmEngine::ExtractWidevinePssh: Unable to rest of PSSH atom");
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// size of PSSH box
|
||||
uint32_t pssh_length;
|
||||
if (!reader.Read4(&pssh_length)) {
|
||||
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH box size");
|
||||
return false;
|
||||
}
|
||||
|
||||
output->clear();
|
||||
if (!reader.ReadString(output, pssh_length)) {
|
||||
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// we did not find a matching record
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace wvcdm
|
||||
@@ -84,6 +84,7 @@ using video_widevine_server::sdk::EncryptedClientIdentification;
|
||||
using video_widevine_server::sdk::LicenseRequest;
|
||||
using video_widevine_server::sdk::LicenseRequest_ContentIdentification;
|
||||
using video_widevine_server::sdk::LicenseRequest_ContentIdentification_CENC;
|
||||
using video_widevine_server::sdk::LicenseRequest_ContentIdentification_WebM;
|
||||
using video_widevine_server::sdk::
|
||||
LicenseRequest_ContentIdentification_ExistingLicense;
|
||||
using video_widevine_server::sdk::License;
|
||||
@@ -157,7 +158,7 @@ bool CdmLicense::Init(const std::string& token, CryptoSession* session,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CdmLicense::PrepareKeyRequest(const CdmInitData& init_data,
|
||||
bool CdmLicense::PrepareKeyRequest(const InitializationData& init_data,
|
||||
const CdmLicenseType license_type,
|
||||
const CdmAppParameterMap& app_parameters,
|
||||
const CdmSessionId& session_id,
|
||||
@@ -167,7 +168,12 @@ bool CdmLicense::PrepareKeyRequest(const CdmInitData& init_data,
|
||||
LOGE("CdmLicense::PrepareKeyRequest: not initialized");
|
||||
return false;
|
||||
}
|
||||
if (init_data.empty() && init_data_.empty()) {
|
||||
if (!init_data.is_supported()) {
|
||||
LOGE("CdmLicense::PrepareKeyRequest: unsupported init data type (%s)",
|
||||
init_data.type().c_str());
|
||||
return false;
|
||||
}
|
||||
if (init_data.IsEmpty() && stored_init_data_.empty()) {
|
||||
LOGE("CdmLicense::PrepareKeyRequest: empty init data provided");
|
||||
return false;
|
||||
}
|
||||
@@ -192,7 +198,7 @@ bool CdmLicense::PrepareKeyRequest(const CdmInitData& init_data,
|
||||
serialized_service_certificate = service_certificate_;
|
||||
|
||||
if (privacy_mode_enabled && serialized_service_certificate.empty()) {
|
||||
init_data_ = init_data;
|
||||
stored_init_data_ = init_data.data();
|
||||
return PrepareServiceCertificateRequest(signed_request, server_url);
|
||||
}
|
||||
|
||||
@@ -259,15 +265,18 @@ bool CdmLicense::PrepareKeyRequest(const CdmInitData& init_data,
|
||||
DeviceCertificate service_certificate;
|
||||
|
||||
if (!service_certificate.ParseFromString(serialized_service_certificate)) {
|
||||
LOGE("CdmLicense::PrepareKeyRequest: unable to parse retrieved "
|
||||
"service certificate");
|
||||
LOGE(
|
||||
"CdmLicense::PrepareKeyRequest: unable to parse retrieved "
|
||||
"service certificate");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (service_certificate.type() !=
|
||||
video_widevine_server::sdk::DeviceCertificate_CertificateType_SERVICE) {
|
||||
LOGE("CdmLicense::PrepareKeyRequest: retrieved certificate not of type"
|
||||
" service, %d", service_certificate.type());
|
||||
LOGE(
|
||||
"CdmLicense::PrepareKeyRequest: retrieved certificate not of type"
|
||||
" service, %d",
|
||||
service_certificate.type());
|
||||
return false;
|
||||
}
|
||||
encrypted_client_id->set_service_id(service_certificate.service_id());
|
||||
@@ -304,33 +313,44 @@ bool CdmLicense::PrepareKeyRequest(const CdmInitData& init_data,
|
||||
LicenseRequest_ContentIdentification* content_id =
|
||||
license_request.mutable_content_id();
|
||||
|
||||
LicenseRequest_ContentIdentification_CENC* cenc_content_id =
|
||||
content_id->mutable_cenc_id();
|
||||
if (init_data.is_cenc()) {
|
||||
LicenseRequest_ContentIdentification_CENC* cenc_content_id =
|
||||
content_id->mutable_cenc_id();
|
||||
|
||||
if (!init_data.empty()) {
|
||||
cenc_content_id->add_pssh(init_data);
|
||||
} else if (privacy_mode_enabled && !init_data_.empty()) {
|
||||
cenc_content_id->add_pssh(init_data_);
|
||||
if (!init_data.IsEmpty()) {
|
||||
cenc_content_id->add_pssh(init_data.data());
|
||||
} else if (privacy_mode_enabled && !stored_init_data_.empty()) {
|
||||
cenc_content_id->add_pssh(stored_init_data_);
|
||||
} else {
|
||||
LOGE("CdmLicense::PrepareKeyRequest: ISO-CENC init data not available");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!PrepareContentId(license_type, request_id, cenc_content_id)) {
|
||||
return false;
|
||||
}
|
||||
} else if (init_data.is_webm()) {
|
||||
LicenseRequest_ContentIdentification_WebM* webm_content_id =
|
||||
content_id->mutable_webm_id();
|
||||
|
||||
if (!init_data.IsEmpty()) {
|
||||
webm_content_id->set_header(init_data.data());
|
||||
} else if (privacy_mode_enabled && !stored_init_data_.empty()) {
|
||||
webm_content_id->set_header(stored_init_data_);
|
||||
} else {
|
||||
LOGE("CdmLicense::PrepareKeyRequest: WebM init data not available");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!PrepareContentId(license_type, request_id, webm_content_id)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
LOGD("CdmLicense::PrepareKeyRequest: init data not available");
|
||||
LOGE("CdmLicense::PrepareKeyRequest: no support for init data type (%s)",
|
||||
init_data.type().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (license_type) {
|
||||
case kLicenseTypeOffline:
|
||||
cenc_content_id->set_license_type(video_widevine_server::sdk::OFFLINE);
|
||||
break;
|
||||
case kLicenseTypeStreaming:
|
||||
cenc_content_id->set_license_type(video_widevine_server::sdk::STREAMING);
|
||||
break;
|
||||
default:
|
||||
LOGD("CdmLicense::PrepareKeyRequest: Unknown license type = %d",
|
||||
license_type);
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
cenc_content_id->set_request_id(request_id);
|
||||
|
||||
// The time field will be updated once the cdm wrapper
|
||||
// has been updated to pass us in the time.
|
||||
license_request.set_request_time(0);
|
||||
@@ -427,8 +447,9 @@ bool CdmLicense::PrepareKeyUpdateRequest(bool is_renewal,
|
||||
return false;
|
||||
|
||||
if (license_request_signature.empty()) {
|
||||
LOGE("CdmLicense::PrepareKeyUpdateRequest: empty license request"
|
||||
" signature");
|
||||
LOGE(
|
||||
"CdmLicense::PrepareKeyUpdateRequest: empty license request"
|
||||
" signature");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -456,8 +477,9 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
||||
|
||||
SignedMessage signed_response;
|
||||
if (!signed_response.ParseFromString(license_response)) {
|
||||
LOGE("CdmLicense::HandleKeyResponse: unable to parse signed license"
|
||||
" response");
|
||||
LOGE(
|
||||
"CdmLicense::HandleKeyResponse: unable to parse signed license"
|
||||
" response");
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
@@ -510,9 +532,10 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
||||
}
|
||||
|
||||
if (mac_key_iv.size() != KEY_IV_SIZE || mac_key.size() != MAC_KEY_SIZE) {
|
||||
LOGE("CdmLicense::HandleKeyResponse: mac key/iv size error"
|
||||
"(key/iv size expected: %d/%d, actual: %d/%d",
|
||||
MAC_KEY_SIZE, KEY_IV_SIZE, mac_key.size(), mac_key_iv.size());
|
||||
LOGE(
|
||||
"CdmLicense::HandleKeyResponse: mac key/iv size error"
|
||||
"(key/iv size expected: %d/%d, actual: %d/%d",
|
||||
MAC_KEY_SIZE, KEY_IV_SIZE, mac_key.size(), mac_key_iv.size());
|
||||
return KEY_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -575,8 +598,9 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
|
||||
|
||||
License license;
|
||||
if (!license.ParseFromString(signed_response.msg())) {
|
||||
LOGE("CdmLicense::HandleKeyUpdateResponse: Unable to parse license"
|
||||
" from signed message");
|
||||
LOGE(
|
||||
"CdmLicense::HandleKeyUpdateResponse: Unable to parse license"
|
||||
" from signed message");
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
@@ -611,9 +635,10 @@ bool CdmLicense::RestoreOfflineLicense(
|
||||
CdmKeyResponse& license_renewal_response) {
|
||||
|
||||
if (license_request.empty() || license_response.empty()) {
|
||||
LOGE("CdmLicense::RestoreOfflineLicense: key_request or response empty: "
|
||||
"%u %u",
|
||||
license_request.size(), license_response.size());
|
||||
LOGE(
|
||||
"CdmLicense::RestoreOfflineLicense: key_request or response empty: "
|
||||
"%u %u",
|
||||
license_request.size(), license_response.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -624,9 +649,10 @@ bool CdmLicense::RestoreOfflineLicense(
|
||||
}
|
||||
|
||||
if (signed_request.type() != SignedMessage::LICENSE_REQUEST) {
|
||||
LOGE("CdmLicense::RestoreOfflineLicense: license request type: expected = "
|
||||
"%d, actual = %d",
|
||||
SignedMessage::LICENSE_REQUEST, signed_request.type());
|
||||
LOGE(
|
||||
"CdmLicense::RestoreOfflineLicense: license request type: expected = "
|
||||
"%d, actual = %d",
|
||||
SignedMessage::LICENSE_REQUEST, signed_request.type());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -656,13 +682,15 @@ bool CdmLicense::PrepareServiceCertificateRequest(CdmKeyMessage* signed_request,
|
||||
return false;
|
||||
}
|
||||
if (!signed_request) {
|
||||
LOGE("CdmLicense::PrepareServiceCertificateRequest: no signed request"
|
||||
" provided");
|
||||
LOGE(
|
||||
"CdmLicense::PrepareServiceCertificateRequest: no signed request"
|
||||
" provided");
|
||||
return false;
|
||||
}
|
||||
if (!server_url) {
|
||||
LOGE("CdmLicense::PrepareServiceCertificateRequest: no server url"
|
||||
" provided");
|
||||
LOGE(
|
||||
"CdmLicense::PrepareServiceCertificateRequest: no server url"
|
||||
" provided");
|
||||
return false;
|
||||
}
|
||||
SignedMessage signed_message;
|
||||
@@ -678,8 +706,9 @@ CdmResponseType CdmLicense::HandleServiceCertificateResponse(
|
||||
|
||||
SignedDeviceCertificate signed_service_certificate;
|
||||
if (!signed_service_certificate.ParseFromString(signed_response.msg())) {
|
||||
LOGE("CdmLicense::HandleServiceCertificateResponse: unable to parse"
|
||||
"signed device certificate");
|
||||
LOGE(
|
||||
"CdmLicense::HandleServiceCertificateResponse: unable to parse"
|
||||
"signed device certificate");
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
@@ -688,32 +717,36 @@ CdmResponseType CdmLicense::HandleServiceCertificateResponse(
|
||||
&kServiceCertificateCAPublicKey[0],
|
||||
&kServiceCertificateCAPublicKey[sizeof(kServiceCertificateCAPublicKey)]);
|
||||
if (!root_ca_key.Init(ca_public_key)) {
|
||||
LOGE("CdmLicense::HandleServiceCertificateResponse: public key "
|
||||
"initialization failed");
|
||||
LOGE(
|
||||
"CdmLicense::HandleServiceCertificateResponse: public key "
|
||||
"initialization failed");
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
if (!root_ca_key.VerifySignature(
|
||||
signed_service_certificate.device_certificate(),
|
||||
signed_service_certificate.signature())) {
|
||||
LOGE("CdmLicense::HandleServiceCertificateResponse: service "
|
||||
"certificate verification failed");
|
||||
LOGE(
|
||||
"CdmLicense::HandleServiceCertificateResponse: service "
|
||||
"certificate verification failed");
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
DeviceCertificate service_certificate;
|
||||
if (!service_certificate.ParseFromString(
|
||||
signed_service_certificate.device_certificate())) {
|
||||
LOGE("CdmLicense::HandleServiceCertificateResponse: unable to parse "
|
||||
"retrieved service certificate");
|
||||
LOGE(
|
||||
"CdmLicense::HandleServiceCertificateResponse: unable to parse "
|
||||
"retrieved service certificate");
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
if (service_certificate.type() !=
|
||||
video_widevine_server::sdk::DeviceCertificate_CertificateType_SERVICE) {
|
||||
LOGE("CdmLicense::HandleServiceCertificateResponse: certificate not of type"
|
||||
" service, %d",
|
||||
service_certificate.type());
|
||||
LOGE(
|
||||
"CdmLicense::HandleServiceCertificateResponse: certificate not of type"
|
||||
" service, %d",
|
||||
service_certificate.type());
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
@@ -743,6 +776,28 @@ CdmResponseType CdmLicense::HandleKeyErrorResponse(
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool CdmLicense::PrepareContentId(const CdmLicenseType license_type,
|
||||
const std::string& request_id,
|
||||
T* content_id) {
|
||||
switch (license_type) {
|
||||
case kLicenseTypeOffline:
|
||||
content_id->set_license_type(video_widevine_server::sdk::OFFLINE);
|
||||
break;
|
||||
case kLicenseTypeStreaming:
|
||||
content_id->set_license_type(
|
||||
video_widevine_server::sdk::STREAMING);
|
||||
break;
|
||||
default:
|
||||
LOGD("CdmLicense::PrepareKeyRequest: Unknown license type = %d",
|
||||
license_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
content_id->set_request_id(request_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CdmLicense::IsKeyLoaded(const KeyId& key_id) {
|
||||
return loaded_keys_.find(key_id) != loaded_keys_.end();
|
||||
}
|
||||
|
||||
@@ -276,12 +276,29 @@ message SessionState {
|
||||
// Public protocol buffer definitions for Widevine Device Certificate
|
||||
// Provisioning protocol.
|
||||
|
||||
// ProvisioningOptions specifies the type of certificate to specify and
|
||||
// in the case of X509 certificates, the certificate authority to use.
|
||||
message ProvisioningOptions {
|
||||
enum CertificateType {
|
||||
RSA_WIDEVINE = 0; // Default. The original certificate type.
|
||||
X509 = 1; // X.509 certificate.
|
||||
}
|
||||
|
||||
optional CertificateType certificate_type = 1;
|
||||
|
||||
// It is recommended that the certificate_authority specify the X.509
|
||||
// Subject of the signing certificate.
|
||||
optional string certificate_authority = 2;
|
||||
}
|
||||
|
||||
// Provisioning request sent by client devices to provisioning service.
|
||||
message ProvisioningRequest {
|
||||
// Device root of trust and other client identification. Required.
|
||||
optional ClientIdentification client_id = 1;
|
||||
// Nonce value used to prevent replay attacks. Required.
|
||||
optional bytes nonce = 2;
|
||||
// Options for type of certificate to generate. Optional.
|
||||
optional ProvisioningOptions options = 3;
|
||||
}
|
||||
|
||||
// Provisioning response sent by the provisioning server to client devices.
|
||||
|
||||
127
core/src/oemcrypto_adapter_static_v8.cpp
Normal file
127
core/src/oemcrypto_adapter_static_v8.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Wrapper of OEMCrypto APIs for platforms that support Level 1 only.
|
||||
* This should be used when liboemcrypto.so is linked with the CDM code at
|
||||
* compile time.
|
||||
* An implementation should compile either oemcrypto_adapter_dynamic.cpp or
|
||||
* oemcrypto_adapter_static.cpp, but not both.
|
||||
* This version contains shim code to allow an older, version 8 API, oemcrypto,
|
||||
* to be linked with CDM.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "oemcrypto_adapter.h"
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult OEMCrypto_LoadKeys_V8(OEMCrypto_SESSION session,
|
||||
const uint8_t* message,
|
||||
size_t message_length,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length,
|
||||
const uint8_t* enc_mac_keys_iv,
|
||||
const uint8_t* enc_mac_keys,
|
||||
size_t num_keys,
|
||||
const OEMCrypto_KeyObject* key_array);
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult OEMCrypto_GenerateRSASignature_V8(OEMCrypto_SESSION session,
|
||||
const uint8_t* message,
|
||||
size_t message_length,
|
||||
uint8_t* signature,
|
||||
size_t *signature_length);
|
||||
|
||||
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session,
|
||||
SecurityLevel level) {
|
||||
return ::OEMCrypto_OpenSession(session);
|
||||
}
|
||||
|
||||
OEMCryptoResult OEMCrypto_IsKeyboxValid(SecurityLevel level) {
|
||||
return ::OEMCrypto_IsKeyboxValid();
|
||||
}
|
||||
|
||||
OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID, size_t* idLength,
|
||||
SecurityLevel level) {
|
||||
return ::OEMCrypto_GetDeviceID(deviceID, idLength);
|
||||
}
|
||||
|
||||
OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData, size_t* keyDataLength,
|
||||
SecurityLevel level) {
|
||||
return ::OEMCrypto_GetKeyData(keyData, keyDataLength);
|
||||
}
|
||||
|
||||
OEMCryptoResult OEMCrypto_InstallKeybox(const uint8_t* keybox,
|
||||
size_t keyBoxLength,
|
||||
SecurityLevel level) {
|
||||
return ::OEMCrypto_InstallKeybox(keybox, keyBoxLength);
|
||||
}
|
||||
|
||||
uint32_t OEMCrypto_APIVersion(SecurityLevel level) {
|
||||
return ::OEMCrypto_APIVersion();
|
||||
}
|
||||
|
||||
const char* OEMCrypto_SecurityLevel(SecurityLevel level) {
|
||||
return ::OEMCrypto_SecurityLevel();
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_LoadKeys(
|
||||
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
|
||||
const uint8_t* signature, size_t signature_length,
|
||||
const uint8_t* enc_mac_key_iv, const uint8_t* enc_mac_key, size_t num_keys,
|
||||
const OEMCrypto_KeyObject* key_array,
|
||||
const uint8_t* pst, size_t pst_length) {
|
||||
return OEMCrypto_LoadKeys_V8(session, message, message_length, signature,
|
||||
signature_length, enc_mac_key_iv, enc_mac_key,
|
||||
num_keys, key_array);
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_GenerateRSASignature(
|
||||
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
|
||||
uint8_t* signature, size_t* signature_length, RSA_Padding_Scheme padding_scheme) {
|
||||
return OEMCrypto_GenerateRSASignature_V8(session, message, message_length,
|
||||
signature, signature_length);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult OEMCrypto_GetHDCPCapability(OEMCrypto_HDCP_Capability *current,
|
||||
OEMCrypto_HDCP_Capability *maximum) {
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
extern "C" bool OEMCrypto_SupportsUsageTable() {
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_UpdateUsageTable() {
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_DeactivateUsageEntry(const uint8_t *pst,
|
||||
size_t pst_length) {
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_ReportUsage(OEMCrypto_SESSION session,
|
||||
const uint8_t *pst,
|
||||
size_t pst_length,
|
||||
OEMCrypto_PST_Report *buffer,
|
||||
size_t *buffer_length) {
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_DeleteUsageEntry(OEMCrypto_SESSION session,
|
||||
const uint8_t* pst,
|
||||
size_t pst_length,
|
||||
const uint8_t *message,
|
||||
size_t message_length,
|
||||
const uint8_t *signature,
|
||||
size_t signature_length) {
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
}; // namespace wvcdm
|
||||
@@ -158,33 +158,18 @@ void PolicyEngine::UpdateLicense(
|
||||
policy_max_duration_seconds_ = policy_.license_duration_seconds();
|
||||
}
|
||||
|
||||
if (Properties::begin_license_usage_when_received())
|
||||
playback_start_time_ = current_time;
|
||||
|
||||
// Update state
|
||||
if (Properties::begin_license_usage_when_received()) {
|
||||
if (policy_.renew_with_usage()) {
|
||||
license_state_ = kLicenseStateNeedRenewal;
|
||||
}
|
||||
else {
|
||||
license_state_ = kLicenseStateCanPlay;
|
||||
can_decrypt_ = true;
|
||||
}
|
||||
if (license_state_ == kLicenseStateInitial) {
|
||||
license_state_ = kLicenseStateInitialPendingUsage;
|
||||
}
|
||||
else {
|
||||
if (license_state_ == kLicenseStateInitial) {
|
||||
license_state_ = kLicenseStateInitialPendingUsage;
|
||||
}
|
||||
else {
|
||||
license_state_ = kLicenseStateCanPlay;
|
||||
can_decrypt_ = true;
|
||||
}
|
||||
license_state_ = kLicenseStateCanPlay;
|
||||
can_decrypt_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void PolicyEngine::BeginDecryption() {
|
||||
if ((playback_start_time_ == 0) &&
|
||||
(!Properties::begin_license_usage_when_received())) {
|
||||
if (playback_start_time_ == 0) {
|
||||
switch (license_state_) {
|
||||
case kLicenseStateInitialPendingUsage:
|
||||
case kLicenseStateNeedRenewal:
|
||||
|
||||
@@ -9,27 +9,21 @@ const char* kSecurityLevelDirs[] = {"L1/", "L3/"};
|
||||
} // namespace
|
||||
|
||||
namespace wvcdm {
|
||||
bool Properties::begin_license_usage_when_received_;
|
||||
bool Properties::require_explicit_renew_request_;
|
||||
bool Properties::oem_crypto_use_secure_buffers_;
|
||||
bool Properties::oem_crypto_use_fifo_;
|
||||
bool Properties::oem_crypto_use_userspace_buffers_;
|
||||
bool Properties::oem_crypto_require_usage_tables_;
|
||||
bool Properties::use_certificates_as_identification_;
|
||||
bool Properties::extract_pssh_data_;
|
||||
bool Properties::decrypt_with_empty_session_support_;
|
||||
bool Properties::security_level_path_backward_compatibility_support_;
|
||||
scoped_ptr<CdmClientPropertySetMap> Properties::session_property_set_;
|
||||
|
||||
void Properties::Init() {
|
||||
begin_license_usage_when_received_ = kPropertyBeginLicenseUsageWhenReceived;
|
||||
require_explicit_renew_request_ = kPropertyRequireExplicitRenewRequest;
|
||||
oem_crypto_use_secure_buffers_ = kPropertyOemCryptoUseSecureBuffers;
|
||||
oem_crypto_use_fifo_ = kPropertyOemCryptoUseFifo;
|
||||
oem_crypto_use_userspace_buffers_ = kPropertyOemCryptoUseUserSpaceBuffers;
|
||||
oem_crypto_require_usage_tables_ = kPropertyOemCryptoRequireUsageTable;
|
||||
use_certificates_as_identification_ =
|
||||
kPropertyUseCertificatesAsIdentification;
|
||||
extract_pssh_data_ = kExtractPsshData;
|
||||
decrypt_with_empty_session_support_ = kDecryptWithEmptySessionSupport;
|
||||
security_level_path_backward_compatibility_support_ =
|
||||
kSecurityLevelPathBackwardCompatibilitySupport;
|
||||
session_property_set_.reset(new CdmClientPropertySetMap());
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "string_conversions.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <ctype.h>
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
@@ -50,6 +51,16 @@ std::vector<uint8_t> a2b_hex(const std::string& byte) {
|
||||
return array;
|
||||
}
|
||||
|
||||
// converts an ascii hex string(2 bytes per digit) into a decimal byte string
|
||||
// dump the string with the label.
|
||||
std::vector<uint8_t> a2b_hex(const std::string& label, const std::string& byte) {
|
||||
|
||||
std::cout << std::endl << "[[DUMP: " << label << " ]= \"" << byte << "\"]"
|
||||
<< std::endl << std::endl;
|
||||
|
||||
return a2b_hex(byte);
|
||||
}
|
||||
|
||||
std::string a2bs_hex(const std::string& byte) {
|
||||
std::vector<uint8_t> array = a2b_hex(byte);
|
||||
return std::string(array.begin(), array.end());
|
||||
@@ -157,4 +168,21 @@ std::string UintToString(unsigned int value) {
|
||||
return out_string;
|
||||
}
|
||||
|
||||
int64_t htonll64(int64_t x) { // Convert to big endian (network-byte-order)
|
||||
union {
|
||||
uint32_t array[2];
|
||||
int64_t number;
|
||||
} mixed;
|
||||
mixed.number = 1;
|
||||
if (mixed.array[0] == 1) {
|
||||
mixed.number = x; // Little Endian.
|
||||
uint32_t temp = mixed.array[0];
|
||||
mixed.array[0] = htonl(mixed.array[1]);
|
||||
mixed.array[1] = htonl(temp);
|
||||
return mixed.number;
|
||||
} else {
|
||||
return x; // Big Endian.
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace wvcdm
|
||||
|
||||
Reference in New Issue
Block a user