Source release v3.0.1 + third_party

This commit is contained in:
Joey Parrish
2015-09-11 16:15:34 -07:00
parent 0546ee6732
commit b5d6be97cb
32 changed files with 1344 additions and 129 deletions

Binary file not shown.

View File

@@ -32,6 +32,7 @@
# Make sure that a valid config.h for your target is in the source tree.
'protobuf_config%': 'source',
'protobuf_source%': '../third_party/protobuf',
'protoc_host_target%': 'dummy',
}, # variables
'conditions': [
['protobuf_config=="source"', {
@@ -187,5 +188,9 @@
],
},
},
{
'target_name': 'dummy',
'type': 'none',
},
],
}

View File

@@ -19,6 +19,9 @@
'test/test_host.cpp',
'test/test_host.h',
],
'variables': {
'cdm_dir': '..',
},
'includes': [
'oemcrypto_unittests.gypi',
'core_unittests.gypi',

View File

@@ -27,6 +27,10 @@
'CORE_TESTS',
],
'dependencies': [
'cdm.gyp:license_protocol',
# This gypi may be included from outside this folder, and dependencies in
# a gypi are relative to the gyp file doing the including.
# cdm_dir is a variable the including file must set to help us find the
# correct path.
'<(cdm_dir)/cdm/cdm.gyp:license_protocol',
],
}

View File

@@ -34,7 +34,17 @@ typedef __int64 int64_t;
namespace widevine {
class CDM_EXPORT Cdm {
class CDM_EXPORT ITimerClient {
public:
// Called by ITimer when a timer expires.
virtual void onTimerExpired(void* context) = 0;
protected:
ITimerClient() {}
virtual ~ITimerClient() {}
};
class CDM_EXPORT Cdm : public ITimerClient {
public:
// Session types defined by EME.
typedef enum {
@@ -179,21 +189,17 @@ class CDM_EXPORT Cdm {
// See Cdm::initialize().
class ITimer {
public:
class IClient {
public:
// Called by ITimer when a timer expires.
virtual void onTimerExpired(void* context) = 0;
protected:
IClient() {}
virtual ~IClient() {}
};
// This typedef is for backward compatibility with v3.0.0.
typedef ITimerClient IClient;
// Call |client->onTimerExpired(context)| after a delay of |delay_ms| ms.
virtual void setTimeout(int64_t delay_ms,
IClient* client,
void* context) = 0;
// Cancel all timers associated with |client|.
virtual void cancel(IClient *client) = 0;
protected:
ITimer() {}
virtual ~ITimer() {}
@@ -425,6 +431,27 @@ class CDM_EXPORT Cdm {
virtual Status decrypt(const InputBuffer& input,
const OutputBuffer& output) = 0;
// Sets a value in the custom app settings. These are settings
// that are sent with any message to the license server. These methods
// should only be used by advanced users maintaining existing systems.
// The |key| cannot be empty.
virtual Status setAppParameter(const std::string& key,
const std::string& value) = 0;
// Gets the current value in the custom app settings. If the key is
// not present, then kInvalidAccess is returned. The |key| cannot be
// empty. |result| cannot be null. See setAppParameter().
virtual Status getAppParameter(const std::string& key,
std::string* result) = 0;
// Removes the value in the custom app settings. If the key is not
// present, then kInvalidAccess is returned. The |key| cannot be empty.
// See setAppParameter().
virtual Status removeAppParameter(const std::string& key) = 0;
// Clears all the values in the custom app settings. See setAppParameter().
virtual Status clearAppParameters() = 0;
protected:
Cdm() {}
};

View File

@@ -1,2 +1,2 @@
// Widevine CE CDM Version
#define CDM_VERSION "v3.0.0-0-g8d3792b-ce"
#define CDM_VERSION "v3.0.1-0-g41710d9-ce"

View File

@@ -105,7 +105,6 @@ class PropertySet : public CdmClientPropertySet {
};
class CdmImpl : public Cdm,
public Cdm::ITimer::IClient,
public WvCdmEventListener {
public:
CdmImpl(IEventListener* listener,
@@ -134,6 +133,16 @@ class CdmImpl : public Cdm,
virtual Status getKeyStatuses(const std::string& session_id,
KeyStatusMap* key_statuses) OVERRIDE;
virtual Status setAppParameter(const std::string& key,
const std::string& value) OVERRIDE;
virtual Status getAppParameter(const std::string& key,
std::string* result) OVERRIDE;
virtual Status removeAppParameter(const std::string& key) OVERRIDE;
virtual Status clearAppParameters() OVERRIDE;
virtual Status close(const std::string& session_id) OVERRIDE;
virtual Status remove(const std::string& session_id) OVERRIDE;
@@ -141,7 +150,7 @@ class CdmImpl : public Cdm,
virtual Status decrypt(const InputBuffer& input,
const OutputBuffer& output) OVERRIDE;
// ITimer::IClient:
// ITimerClient:
virtual void onTimerExpired(void* context) OVERRIDE;
// WvCdmEventListener:
@@ -160,6 +169,7 @@ class CdmImpl : public Cdm,
CdmEngine cdm_engine_;
PropertySet property_set_;
CdmAppParameterMap app_parameters_;
std::map<std::string, SessionType> new_session_types_;
std::map<std::string, int64_t> session_expirations_;
@@ -173,7 +183,9 @@ CdmImpl::CdmImpl(IEventListener* listener,
property_set_.set_use_privacy_mode(privacy_mode);
}
CdmImpl::~CdmImpl() {}
CdmImpl::~CdmImpl() {
host.timer->cancel(this);
}
Cdm::Status CdmImpl::setServerCertificate(const std::string& certificate) {
if (!property_set_.use_privacy_mode()) {
@@ -283,14 +295,13 @@ Cdm::Status CdmImpl::generateRequest(const std::string& session_id,
return kInvalidAccess;
}
CdmAppParameterMap empty_app_parameters;
std::string key_request;
CdmKeyRequestType key_request_type;
std::string ignored_server_url;
CdmResponseType result = cdm_engine_.GenerateKeyRequest(
session_id, session_id, init_data_obj,
license_type, empty_app_parameters, &key_request, &key_request_type,
license_type, app_parameters_, &key_request, &key_request_type,
&ignored_server_url, NULL);
if (result != KEY_MESSAGE) {
@@ -349,13 +360,12 @@ Cdm::Status CdmImpl::load(const std::string& session_id) {
// This was partially removed already.
// The EME spec states that we should send a release message right away.
InitializationData empty_initialization_data;
CdmAppParameterMap empty_app_parameters;
CdmKeyMessage key_request;
std::string ignored_server_url;
CdmResponseType result = cdm_engine_.GenerateKeyRequest(
session_id, session_id, empty_initialization_data,
kLicenseTypeRelease, empty_app_parameters, &key_request, NULL,
kLicenseTypeRelease, app_parameters_, &key_request, NULL,
&ignored_server_url, NULL);
if (result != KEY_MESSAGE) {
LOGE("Unexpected error %d", result);
@@ -412,14 +422,13 @@ Cdm::Status CdmImpl::update(const std::string& session_id,
// The underlying session in CdmEngine has stored a copy of the original
// init data, so we can use an empty one this time.
InitializationData empty_init_data;
CdmAppParameterMap empty_app_parameters;
std::string key_request;
CdmKeyRequestType key_request_type;
std::string ignored_server_url;
CdmResponseType result = cdm_engine_.GenerateKeyRequest(
session_id, session_id, empty_init_data, kLicenseTypeDeferred,
empty_app_parameters, &key_request, &key_request_type,
app_parameters_, &key_request, &key_request_type,
&ignored_server_url, NULL);
if (result != KEY_MESSAGE) {
@@ -476,6 +485,42 @@ Cdm::Status CdmImpl::getKeyStatuses(const std::string& session_id,
return kSuccess;
}
Cdm::Status CdmImpl::setAppParameter(const std::string& key,
const std::string& value) {
if (key.empty()) {
return kInvalidAccess;
}
app_parameters_[key] = value;
return kSuccess;
}
Cdm::Status CdmImpl::getAppParameter(const std::string& key,
std::string* result) {
if (NULL == result || key.empty() ||
app_parameters_.find(key) == app_parameters_.end()) {
return kInvalidAccess;
}
*result = app_parameters_[key];
return kSuccess;
}
Cdm::Status CdmImpl::removeAppParameter(const std::string& key) {
if (key.empty()) {
return kInvalidAccess;
}
CdmAppParameterMap::iterator it = app_parameters_.find(key);
if (it == app_parameters_.end()) {
return kInvalidAccess;
}
app_parameters_.erase(it);
return kSuccess;
}
Cdm::Status CdmImpl::clearAppParameters() {
app_parameters_.clear();
return kSuccess;
}
Cdm::Status CdmImpl::close(const std::string& session_id) {
if (!cdm_engine_.IsOpenSession(session_id)) {
LOGE("No such session: %s", session_id.c_str());
@@ -507,13 +552,12 @@ Cdm::Status CdmImpl::remove(const std::string& session_id) {
}
InitializationData empty_initialization_data;
CdmAppParameterMap empty_app_parameters;
CdmKeyMessage key_request;
std::string ignored_server_url;
CdmResponseType result = cdm_engine_.GenerateKeyRequest(
session_id, session_id, empty_initialization_data,
kLicenseTypeRelease, empty_app_parameters, &key_request, NULL,
kLicenseTypeRelease, app_parameters_, &key_request, NULL,
&ignored_server_url, NULL);
if (result != KEY_MESSAGE) {
LOGE("Unexpected error %d", result);

View File

@@ -10,6 +10,7 @@
#include "cdm_test_printers.h"
#include "license_request.h"
#include "log.h"
#include "OEMCryptoCENC.h"
#include "override.h"
#include "properties_ce.h"
#include "scoped_ptr.h"
@@ -103,6 +104,12 @@ const std::vector<uint8_t> kOutput1 = a2b_hex(
"4884604c8da8a53ce33db9ff8f1c5bb6bb97f37b39906bf41596555c1bcce9ed"
"08a899cd760ff0899a1170c2f224b9c52997a0785b7fe170805fd3e8b1127659");
const std::string kValue = "A Value";
const std::string kNewValue = "A New Value";
const std::string kParamName = "PARAM";
const std::string kParamName2 = "PARAM2";
class CdmTest : public Test,
public Cdm::IEventListener {
@@ -423,6 +430,20 @@ TEST_F(CdmTest, Initialize) {
}
TEST_F(CdmTest, DeviceCertificateRequest) {
uint32_t nonce = 0;
uint8_t buffer[1];
size_t size = 0;
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize());
int result = OEMCrypto_RewrapDeviceRSAKey(
0, buffer, 0, buffer, 0, &nonce, buffer, 0, buffer, buffer, &size);
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Terminate());
if (result == OEMCrypto_ERROR_NOT_IMPLEMENTED) {
LOGW("WARNING: Skipping DeviceCertificateRequest because the device does "
"not support provisioning. If you are using a baked-in certificate, "
"this is expected. Otherwise, something is wrong.");
return;
}
// Clear any existing certificates.
g_host->remove("cert.bin");
@@ -1075,4 +1096,84 @@ TEST_F(CdmTest, ServerCertificateProvisioning) {
Mock::VerifyAndClear(this);
}
TEST_F(CdmTest, SetAppParameters) {
// Must use privacy_mode = false to ensure that the message is in plain-text.
std::string session_id;
ASSERT_NO_FATAL_FAILURE(RecreateCdm(false /* privacy_mode */));
Cdm::Status status = cdm_->createSession(Cdm::kTemporary, &session_id);
ASSERT_EQ(Cdm::kSuccess, status);
// Set a new app parameter, and check by getting.
std::string result;
status = cdm_->setAppParameter(kParamName, kValue);
ASSERT_EQ(Cdm::kSuccess, status);
status = cdm_->getAppParameter(kParamName, &result);
ASSERT_EQ(Cdm::kSuccess, status);
ASSERT_EQ(kValue, result);
// Try to get using a null result.
status = cdm_->getAppParameter(kParamName, NULL);
ASSERT_EQ(Cdm::kInvalidAccess, status);
// Try to get using an empty key.
status = cdm_->getAppParameter("", &result);
ASSERT_EQ(Cdm::kInvalidAccess, status);
// Try to set using an empty key.
status = cdm_->setAppParameter("", kValue);
ASSERT_EQ(Cdm::kInvalidAccess, status);
// Try to remove using an empty key.
status = cdm_->removeAppParameter("");
ASSERT_EQ(Cdm::kInvalidAccess, status);
// Change an existing app parameter.
status = cdm_->setAppParameter(kParamName, kNewValue);
ASSERT_EQ(Cdm::kSuccess, status);
status = cdm_->getAppParameter(kParamName, &result);
ASSERT_EQ(Cdm::kSuccess, status);
ASSERT_EQ(kNewValue, result);
// Remove an existing app parameter, check for invalid access when it's gone.
status = cdm_->removeAppParameter(kParamName);
ASSERT_EQ(Cdm::kSuccess, status);
status = cdm_->getAppParameter(kParamName, &result);
ASSERT_EQ(Cdm::kInvalidAccess, status);
// Try to remove an absent value.
status = cdm_->removeAppParameter(kParamName2);
ASSERT_EQ(Cdm::kInvalidAccess, status);
// Set some values to check for.
status = cdm_->setAppParameter(kParamName, kValue);
ASSERT_EQ(Cdm::kSuccess, status);
status = cdm_->setAppParameter(kParamName2, kNewValue);
ASSERT_EQ(Cdm::kSuccess, status);
// Send a generate request to ensure the parameter is in the message.
std::string message;
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _)).WillOnce(
SaveArg<2>(&message));
status = cdm_->generateRequest(session_id, Cdm::kCenc, kCencInitData);
EXPECT_EQ(Cdm::kSuccess, status);
EXPECT_TRUE(!message.empty() && message.find(kValue) != std::string::npos);
Mock::VerifyAndClear(this);
// Ensure that the value is still present and correct.
status = cdm_->getAppParameter(kParamName, &result);
ASSERT_EQ(Cdm::kSuccess, status);
ASSERT_EQ(kValue, result);
status = cdm_->getAppParameter(kParamName2, &result);
ASSERT_EQ(Cdm::kSuccess, status);
ASSERT_EQ(kNewValue, result);
// Clear all the parameters.
status = cdm_->clearAppParameters();
ASSERT_EQ(Cdm::kSuccess, status);
status = cdm_->getAppParameter(kParamName, &result);
ASSERT_EQ(Cdm::kInvalidAccess, status);
status = cdm_->getAppParameter(kParamName2, &result);
ASSERT_EQ(Cdm::kInvalidAccess, status);
}
} // namespace widevine

View File

@@ -91,3 +91,20 @@ void TestHost::setTimeout(int64_t delay_ms,
int64_t expiry_time = now_ + delay_ms;
timers_.push(Timer(expiry_time, client, context));
}
void TestHost::cancel(IClient* client) {
// Filter out the timers for this client and put the rest into |others|.
std::priority_queue<Timer> others;
while (timers_.size()) {
Timer t = timers_.top();
timers_.pop();
if (t.client != client) {
others.push(t);
}
}
// Now swap the queues.
timers_.swap(others);
}

View File

@@ -30,6 +30,7 @@ class TestHost : public widevine::Cdm::IStorage,
virtual void setTimeout(int64_t delay_ms,
IClient* client,
void* context) OVERRIDE;
virtual void cancel(IClient* client) OVERRIDE;
private:
struct Timer {

View File

@@ -24,9 +24,9 @@ namespace wvcdm {
class BufferReader {
public:
BufferReader(const uint8_t* buf, size_t size)
: buf_(buf), size_(size), pos_(0) {}
: buf_(buf), size_(buf != NULL ? size : 0), pos_(0) {}
bool HasBytes(int count) { return (pos() + count <= size()); }
bool HasBytes(size_t count) { return (pos() + count <= size()); }
// Read a value from the stream, performing endian correction,
// and advance the stream pointer.
@@ -38,8 +38,8 @@ class BufferReader {
bool Read8(uint64_t* v) WARN_UNUSED_RESULT;
bool Read8s(int64_t* v) WARN_UNUSED_RESULT;
bool ReadString(std::string* str, int count) WARN_UNUSED_RESULT;
bool ReadVec(std::vector<uint8_t>* t, int count) WARN_UNUSED_RESULT;
bool ReadString(std::string* str, size_t count) WARN_UNUSED_RESULT;
bool ReadVec(std::vector<uint8_t>* t, size_t count) WARN_UNUSED_RESULT;
// These variants read a 4-byte integer of the corresponding signedness and
// store it in the 8-byte return type.
@@ -47,7 +47,7 @@ class BufferReader {
bool Read4sInto8s(int64_t* v) WARN_UNUSED_RESULT;
// Advance the stream by this many bytes.
bool SkipBytes(int nbytes) WARN_UNUSED_RESULT;
bool SkipBytes(size_t nbytes) WARN_UNUSED_RESULT;
const uint8_t* data() const { return buf_; }
size_t size() const { return size_; }

View File

@@ -137,6 +137,7 @@ class DeviceFiles {
FRIEND_TEST(WvCdmRequestLicenseTest, ForceL3Test);
FRIEND_TEST(WvCdmRequestLicenseTest, UsageInfoRetryTest);
FRIEND_TEST(WvCdmUsageInfoTest, UsageInfo);
FRIEND_TEST(WvCdmUsageTest, WithClientId);
FRIEND_TEST(WvCdmExtendedDurationTest, UsageOverflowTest);
#endif

View File

@@ -57,6 +57,8 @@ static const std::string QUERY_KEY_NUMBER_OF_OPEN_SESSIONS =
"NumberOfOpenSessions";
static const std::string QUERY_KEY_MAX_NUMBER_OF_SESSIONS =
"MaxNumberOfSessions";
static const std::string QUERY_KEY_OEMCRYPTO_API_VERSION =
"OemCryptoApiVersion";
static const std::string QUERY_VALUE_TRUE = "True";
static const std::string QUERY_VALUE_FALSE = "False";

View File

@@ -83,7 +83,7 @@ enum CdmResponseType {
EMPTY_LICENSE_RENEWAL,
EMPTY_LICENSE_RESPONSE_1,
EMPTY_LICENSE_RESPONSE_2,
EMPTY_PROVISIONING_CERTIFICATE,
EMPTY_PROVISIONING_CERTIFICATE_1,
EMPTY_PROVISIONING_RESPONSE,
EMPTY_SESSION_ID,
GENERATE_DERIVED_KEYS_ERROR,
@@ -186,8 +186,8 @@ enum CdmResponseType {
CLIENT_ID_RSA_INIT_ERROR,
CLIENT_ID_RSA_ENCRYPT_ERROR,
INVALID_QUERY_STATUS,
DUPLICATE_SESSION_ID_SPECIFIED,
EMPTY_PROVISIONING_CERTIFICATE_2,
UNUSED_3, /* previously EMPTY_PROVISIONING_CERTIFICATE_2 on mnc-dev, */
/* DUPLICATE_SESSION_ID_SPECIFIED on master */
LICENSE_PARSER_NOT_INITIALIZED_4,
INVALID_PARAMETERS_LIC_3,
INVALID_PARAMETERS_LIC_4,
@@ -203,6 +203,8 @@ enum CdmResponseType {
LICENSE_REQUEST_NONCE_GENERATION_ERROR,
LICENSE_REQUEST_SIGNING_ERROR,
EMPTY_LICENSE_REQUEST,
EMPTY_PROVISIONING_CERTIFICATE_2,
DUPLICATE_SESSION_ID_SPECIFIED,
};
enum CdmKeyStatus {

View File

@@ -7,8 +7,15 @@
namespace wvcdm {
bool BufferReader::Read1(uint8_t* v) {
if (v == NULL) {
LOGE("BufferReader::Read1 : Failure during parse: Null output parameter "
"when expecting non-null");
return false;
}
if (!HasBytes(1)) {
LOGW("BufferReader::Read1 : Failure while parsing: Not enough bytes (1)");
LOGV("BufferReader::Read1 : Failure while parsing: "
"Not enough bytes (1)");
return false;
}
@@ -19,9 +26,15 @@ bool BufferReader::Read1(uint8_t* v) {
// Internal implementation of multi-byte reads
template <typename T>
bool BufferReader::Read(T* v) {
if (v == NULL) {
LOGE("BufferReader::Read<T> : Failure during parse: Null output parameter "
"when expecting non-null (%s)", __PRETTY_FUNCTION__);
return false;
}
if (!HasBytes(sizeof(T))) {
LOGW("BufferReader::Read<T> : Failure during parse: Not enough bytes (%u)",
sizeof(T));
LOGV("BufferReader::Read<T> : Failure during parse: "
"Not enough bytes (%u)", sizeof(T));
return false;
}
@@ -41,10 +54,16 @@ bool BufferReader::Read4s(int32_t* v) { return Read(v); }
bool BufferReader::Read8(uint64_t* v) { return Read(v); }
bool BufferReader::Read8s(int64_t* v) { return Read(v); }
bool BufferReader::ReadString(std::string* str, int count) {
bool BufferReader::ReadString(std::string* str, size_t count) {
if (str == NULL) {
LOGE("BufferReader::ReadString : Failure during parse: Null output "
"parameter when expecting non-null");
return false;
}
if (!HasBytes(count)) {
LOGW("BufferReader::ReadString : Parse Failure: Not enough bytes (%d)",
count);
LOGV("BufferReader::ReadString : Parse Failure: "
"Not enough bytes (%d)", count);
return false;
}
@@ -53,9 +72,16 @@ bool BufferReader::ReadString(std::string* str, int count) {
return true;
}
bool BufferReader::ReadVec(std::vector<uint8_t>* vec, int count) {
bool BufferReader::ReadVec(std::vector<uint8_t>* vec, size_t count) {
if (vec == NULL) {
LOGE("BufferReader::ReadVec : Failure during parse: Null output parameter "
"when expecting non-null");
return false;
}
if (!HasBytes(count)) {
LOGW("BufferReader::ReadVec : Parse Failure: Not enough bytes (%d)", count);
LOGV("BufferReader::ReadVec : Parse Failure: "
"Not enough bytes (%d)", count);
return false;
}
@@ -65,10 +91,10 @@ bool BufferReader::ReadVec(std::vector<uint8_t>* vec, int count) {
return true;
}
bool BufferReader::SkipBytes(int bytes) {
bool BufferReader::SkipBytes(size_t bytes) {
if (!HasBytes(bytes)) {
LOGW("BufferReader::SkipBytes : Parse Failure: Not enough bytes (%d)",
bytes);
LOGV("BufferReader::SkipBytes : Parse Failure: "
"Not enough bytes (%d)", bytes);
return false;
}
@@ -77,6 +103,12 @@ bool BufferReader::SkipBytes(int bytes) {
}
bool BufferReader::Read4Into8(uint64_t* v) {
if (v == NULL) {
LOGE("BufferReader::Read4Into8 : Failure during parse: Null output "
"parameter when expecting non-null");
return false;
}
uint32_t tmp;
if (!Read4(&tmp)) {
return false;
@@ -86,6 +118,12 @@ bool BufferReader::Read4Into8(uint64_t* v) {
}
bool BufferReader::Read4sInto8s(int64_t* v) {
if (v == NULL) {
LOGE("BufferReader::Read4sInto8s : Failure during parse: Null output "
"parameter when expecting non-null");
return false;
}
// Beware of the need for sign extension.
int32_t tmp;
if (!Read4s(&tmp)) {
@@ -94,5 +132,4 @@ bool BufferReader::Read4sInto8s(int64_t* v) {
*v = tmp;
return true;
}
} // namespace wvcdm

View File

@@ -484,6 +484,14 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
max_sessions_stream.str();
}
uint32_t api_version;
success = crypto_session.GetApiVersion(&api_version);
if (success) {
std::ostringstream api_version_stream;
api_version_stream << api_version;
(*key_info)[QUERY_KEY_OEMCRYPTO_API_VERSION] = api_version_stream.str();
}
return NO_ERROR;
}
@@ -605,12 +613,33 @@ CdmResponseType CdmEngine::HandleProvisioningResponse(
return INVALID_PROVISIONING_PARAMETERS_2;
}
if (NULL == cert_provisioning_.get()) {
LOGE("CdmEngine::HandleProvisioningResponse: provisioning object missing.");
return EMPTY_PROVISIONING_CERTIFICATE;
// Certificate provisioning object has been released. Check if a concurrent
// provisioning attempt has succeeded before declaring failure.
CryptoSession crypto_session;
CdmResponseType status =
crypto_session.Open(cert_provisioning_requested_security_level_);
if (NO_ERROR != status) {
LOGE(
"CdmEngine::HandleProvisioningResponse: provisioning object "
"missing and crypto session open failed.");
return EMPTY_PROVISIONING_CERTIFICATE_2;
}
CdmSecurityLevel security_level = crypto_session.GetSecurityLevel();
if (!IsProvisioned(security_level, origin)) {
LOGE(
"CdmEngine::HandleProvisioningResponse: provisioning object "
"missing.");
return EMPTY_PROVISIONING_CERTIFICATE_1;
}
return NO_ERROR;
}
CdmResponseType ret = cert_provisioning_->HandleProvisioningResponse(
origin, response, cert, wrapped_key);
cert_provisioning_.reset(NULL); // Release resources.
// Release resources only on success. It is possible that a provisioning
// attempt was made after this one was requested but before the response was
// received, which will cause this attempt to fail. Not releasing will
// allow for the possibility that the later attempt succeeds.
if (NO_ERROR == ret) cert_provisioning_.reset(NULL);
return ret;
}

View File

@@ -539,12 +539,6 @@ bool CdmSession::DeleteLicense() {
if (!is_offline_ && license_parser_->provider_session_token().empty())
return false;
if (!license_parser_->provider_session_token().empty()) {
if (crypto_session_->DeleteUsageInformation(
license_parser_->provider_session_token()) != NO_ERROR) {
LOGE("CdmSession::DeleteLicense: error deleting usage info");
}
}
if (!file_handle_->Reset(security_level_)) {
LOGE("CdmSession::DeleteLicense: Unable to initialize device files");
return false;

View File

@@ -268,7 +268,6 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
LOGE("HandleProvisioningResponse: failed to save provisioning certificate");
return CERT_PROVISIONING_RESPONSE_ERROR_8;
}
handle.DeleteAllLicenses();
return NO_ERROR;
}

View File

@@ -16,6 +16,8 @@
#include <CommonCrypto/CommonDigest.h>
#define SHA256 CC_SHA256
#define SHA256_DIGEST_LENGTH CC_SHA256_DIGEST_LENGTH
#define MD5 CC_MD5
#define MD5_DIGEST_LENGTH CC_MD5_DIGEST_LENGTH
#else
#include <openssl/sha.h>
#include <openssl/md5.h>

View File

@@ -61,18 +61,18 @@ bool InitializationData::ExtractWidevinePssh(const CdmInitData& init_data,
// atom size, used for skipping.
uint64_t size;
if (!reader.Read4Into8(&size)) {
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read atom size.");
LOGV("CdmEngine::ExtractWidevinePssh: Unable to read atom size.");
return false;
}
std::vector<uint8_t> atom_type;
if (!reader.ReadVec(&atom_type, 4)) {
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read atom type.");
LOGV("CdmEngine::ExtractWidevinePssh: Unable to read atom type.");
return false;
}
if (size == 1) {
if (!reader.Read8(&size)) {
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read 64-bit atom "
LOGV("CdmEngine::ExtractWidevinePssh: Unable to read 64-bit atom "
"size.");
return false;
}
@@ -82,10 +82,10 @@ bool InitializationData::ExtractWidevinePssh(const CdmInitData& init_data,
// "pssh"
if (memcmp(&atom_type[0], "pssh", 4)) {
LOGW("CdmEngine::ExtractWidevinePssh: PSSH literal not present.");
LOGV("CdmEngine::ExtractWidevinePssh: PSSH literal not present.");
if (!reader.SkipBytes(size - (reader.pos() - start_pos))) {
LOGW("CdmEngine::ExtractWidevinePssh: Unable to skip the rest of the "
"atom.");
LOGV("CdmEngine::ExtractWidevinePssh: Unable to skip the rest of "
"the atom.");
return false;
}
continue;
@@ -94,15 +94,15 @@ bool InitializationData::ExtractWidevinePssh(const CdmInitData& init_data,
// version
uint8_t version;
if (!reader.Read1(&version)) {
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH version.");
LOGV("CdmEngine::ExtractWidevinePssh: Unable to read PSSH version.");
return false;
}
if (version > 1) {
// unrecognized version - skip.
if (!reader.SkipBytes(size - (reader.pos() - start_pos))) {
LOGW("CdmEngine::ExtractWidevinePssh: Unable to skip the rest of the "
"atom.");
LOGV("CdmEngine::ExtractWidevinePssh: Unable to skip the rest of "
"the atom.");
return false;
}
continue;
@@ -110,22 +110,22 @@ bool InitializationData::ExtractWidevinePssh(const CdmInitData& init_data,
// flags
if (!reader.SkipBytes(3)) {
LOGW("CdmEngine::ExtractWidevinePssh: Unable to skip the PSSH flags.");
LOGV("CdmEngine::ExtractWidevinePssh: Unable to skip the PSSH flags.");
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.");
LOGV("CdmEngine::ExtractWidevinePssh: Unable to read system ID.");
return false;
}
if (memcmp(&system_id[0], kWidevineSystemId, sizeof(kWidevineSystemId))) {
// skip non-Widevine PSSH boxes.
if (!reader.SkipBytes(size - (reader.pos() - start_pos))) {
LOGW("CdmEngine::ExtractWidevinePssh: Unable to skip the rest of the "
"atom.");
LOGV("CdmEngine::ExtractWidevinePssh: Unable to skip the rest of "
"the atom.");
return false;
}
continue;
@@ -135,11 +135,11 @@ bool InitializationData::ExtractWidevinePssh(const CdmInitData& init_data,
// v1 has additional fields for key IDs. We can skip them.
uint32_t num_key_ids;
if (!reader.Read4(&num_key_ids)) {
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read num key IDs.");
LOGV("CdmEngine::ExtractWidevinePssh: Unable to read num key IDs.");
return false;
}
if (!reader.SkipBytes(num_key_ids * 16)) {
LOGW("CdmEngine::ExtractWidevinePssh: Unable to skip key IDs.");
LOGV("CdmEngine::ExtractWidevinePssh: Unable to skip key IDs.");
return false;
}
}
@@ -147,13 +147,13 @@ bool InitializationData::ExtractWidevinePssh(const CdmInitData& init_data,
// size of PSSH data
uint32_t data_length;
if (!reader.Read4(&data_length)) {
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH data size.");
LOGV("CdmEngine::ExtractWidevinePssh: Unable to read PSSH data size.");
return false;
}
output->clear();
if (!reader.ReadString(output, data_length)) {
LOGW("CdmEngine::ExtractWidevinePssh: Unable to read PSSH data.");
LOGV("CdmEngine::ExtractWidevinePssh: Unable to read PSSH data.");
return false;
}

View File

@@ -773,6 +773,9 @@ bool CdmLicense::RestoreLicenseForRelease(
if (license.id().has_provider_session_token())
provider_session_token_ = license.id().provider_session_token();
if (license.policy().has_renew_with_client_id())
renew_with_client_id_ = license.policy().renew_with_client_id();
if (Properties::use_certificates_as_identification()) {
if (!signed_response.has_session_key()) {
LOGE("CdmLicense::RestoreLicenseForRelease: no session keys present");

View File

@@ -27,7 +27,7 @@ extern "C" OEMCryptoResult OEMCrypto_QueryKeyControl(
}
extern "C" OEMCryptoResult OEMCrypto_CopyBuffer(
SecurityLevel level, const uint8_t* data_addr, size_t data_length,
const uint8_t* data_addr, size_t data_length,
OEMCrypto_DestBufferDesc* out_buffer, uint8_t subsample_flags) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}

View File

@@ -41,7 +41,7 @@ extern "C" OEMCryptoResult OEMCrypto_GenerateRSASignature(
signature, signature_length);
}
extern "C" OEMCryptoResult OEMCrypto_GetHDCPCapability(
extern "C" OEMCryptoResult OEMCrypto_GetHDCPCapability_V9(
OEMCrypto_HDCP_Capability* current, OEMCrypto_HDCP_Capability* maximum) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
@@ -71,3 +71,7 @@ extern "C" OEMCryptoResult OEMCrypto_DeleteUsageEntry(
size_t signature_length) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
extern "C" OEMCryptoResult OEMCrypto_DeleteUsageTable(){
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}

View File

@@ -0,0 +1,838 @@
// Copyright 2015 Google Inc. All Rights Reserved.
#include <string>
#include <errno.h>
#include <getopt.h>
#include <gtest/gtest.h>
#include "buffer_reader.h"
namespace wvcdm {
class BufferReaderTest : public testing::Test {
public:
template <typename T>
void WriteToBuffer(uint8_t* buffer, T v) {
for (size_t i = 0; i < sizeof(T); ++i) {
size_t insertAt = (sizeof(T) - i) - 1; // reverse the order of i
size_t shiftAmount = 8 * i;
buffer[insertAt] = (uint8_t)((v >> shiftAmount) & 0xff);
}
}
// populate and validate data by cycling through the alphabet
// (lower case) so that it will work for strings and raw bytes
void PopulateData(uint8_t* dest, size_t byte_count) {
for (size_t i = 0; i < byte_count; i++) {
dest[i] = (uint8_t)(i % 26 + 'a');
}
}
bool ValidateData(const uint8_t* data, size_t byte_count) {
for (size_t i = 0; i < byte_count; i++) {
if (data[i] != (uint8_t)(i % 26 + 'a')) {
return false;
}
}
return true;
}
bool ValidateReader(const BufferReader& reader,
const uint8_t* expectedAddress, size_t expectedSize,
size_t expectedPosition) {
return reader.data() == expectedAddress && reader.size() == expectedSize &&
reader.pos() == expectedPosition;
}
bool CheckRead1(uint8_t input) {
uint8_t raw_data[sizeof(input)];
WriteToBuffer(raw_data, input);
BufferReader reader(raw_data, sizeof(raw_data));
uint8_t read;
return reader.Read1(&read) && input == read &&
ValidateReader(reader, raw_data, sizeof(raw_data), sizeof(input));
}
bool CheckRead2(uint16_t input) {
uint8_t raw_data[sizeof(input)];
WriteToBuffer(raw_data, input);
BufferReader reader(raw_data, sizeof(raw_data));
uint16_t read;
return reader.Read2(&read) && input == read &&
ValidateReader(reader, raw_data, sizeof(raw_data), sizeof(input));
}
bool CheckRead2s(int16_t input) {
uint8_t raw_data[sizeof(input)];
WriteToBuffer(raw_data, input);
BufferReader reader(raw_data, sizeof(raw_data));
int16_t read;
return reader.Read2s(&read) && input == read &&
ValidateReader(reader, raw_data, sizeof(raw_data), sizeof(input));
}
bool CheckRead4(uint32_t input) {
uint8_t raw_data[sizeof(input)];
WriteToBuffer(raw_data, input);
BufferReader reader(raw_data, sizeof(raw_data));
uint32_t read;
return reader.Read4(&read) && input == read &&
ValidateReader(reader, raw_data, sizeof(raw_data), sizeof(input));
}
bool CheckRead4s(int32_t input) {
uint8_t raw_data[sizeof(input)];
WriteToBuffer(raw_data, input);
BufferReader reader(raw_data, sizeof(raw_data));
int32_t read;
return reader.Read4s(&read) && input == read &&
ValidateReader(reader, raw_data, sizeof(raw_data), sizeof(input));
}
bool CheckRead8(uint64_t input) {
uint8_t raw_data[sizeof(input)];
WriteToBuffer(raw_data, input);
BufferReader reader(raw_data, sizeof(raw_data));
uint64_t read;
return reader.Read8(&read) && input == read &&
ValidateReader(reader, raw_data, sizeof(raw_data), sizeof(input));
}
bool CheckRead8s(int64_t input) {
uint8_t raw_data[sizeof(input)];
WriteToBuffer(raw_data, input);
BufferReader reader(raw_data, sizeof(raw_data));
int64_t read;
return reader.Read8s(&read) && input == read &&
ValidateReader(reader, raw_data, sizeof(raw_data), sizeof(input));
}
bool CheckRead4Into8(uint32_t input) {
uint8_t raw_data[sizeof(input)];
WriteToBuffer(raw_data, input);
BufferReader reader(raw_data, sizeof(raw_data));
uint64_t read;
return reader.Read4Into8(&read) && read == input &&
ValidateReader(reader, raw_data, sizeof(raw_data), sizeof(input));
}
bool CheckRead4sInto8s(int32_t input) {
uint8_t raw_data[sizeof(input)];
WriteToBuffer(raw_data, input);
BufferReader reader(raw_data, sizeof(raw_data));
int64_t read;
return reader.Read4sInto8s(&read) && read == input &&
ValidateReader(reader, raw_data, sizeof(raw_data), sizeof(input));
}
};
TEST_F(BufferReaderTest, InitializeGoodDataAndGoodSize) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, sizeof(raw_data));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, sizeof(raw_data), 0));
}
TEST_F(BufferReaderTest, InitializeGoodDataAndNoSize) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, 0);
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, 0, 0));
}
TEST_F(BufferReaderTest, InitializeNoDataNoSize) {
BufferReader reader(NULL, 0);
ASSERT_TRUE(ValidateReader(reader, NULL, 0, 0));
}
TEST_F(BufferReaderTest, InitializeNoDataBadSize) {
BufferReader reader(NULL, 16);
// Buffer reader should default to a size of 0 when given
// NULL data to ensure no reading of bad data
ASSERT_TRUE(ValidateReader(reader, NULL, 0, 0));
}
TEST_F(BufferReaderTest, HasBytesWithBytes) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, sizeof(raw_data));
// the reader should have enough bytes from 0 to the size of the buffer
for (size_t i = 0; i <= sizeof(raw_data); i++) {
ASSERT_TRUE(reader.HasBytes(i));
}
ASSERT_FALSE(reader.HasBytes(sizeof(raw_data) + 1));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, sizeof(raw_data), 0));
}
TEST_F(BufferReaderTest, HasBytesWithEmptyBuffer) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, 0);
ASSERT_FALSE(reader.HasBytes(1));
ASSERT_TRUE(reader.HasBytes(0));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, 0, 0));
}
TEST_F(BufferReaderTest, HasBytesWithNullBuffer) {
BufferReader reader(NULL, 8);
ASSERT_FALSE(reader.HasBytes(1));
ASSERT_TRUE(reader.HasBytes(0));
ASSERT_TRUE(ValidateReader(reader, NULL, 0, 0));
}
TEST_F(BufferReaderTest, HasBytesAfterAllRead) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, sizeof(raw_data));
for (size_t i = 0; i < sizeof(raw_data); i++) {
uint8_t read;
ASSERT_TRUE(reader.Read1(&read));
}
ASSERT_FALSE(reader.HasBytes(1));
ASSERT_TRUE(reader.HasBytes(0));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(
ValidateReader(reader, raw_data, sizeof(raw_data), sizeof(raw_data)));
}
TEST_F(BufferReaderTest, Read1LargeNumber) { ASSERT_TRUE(CheckRead1(0xFF)); }
TEST_F(BufferReaderTest, Read1SmallNumber) { ASSERT_TRUE(CheckRead1(0x0F)); }
TEST_F(BufferReaderTest, Read1Zero) { ASSERT_TRUE(CheckRead1(0)); }
TEST_F(BufferReaderTest, Read1WithNoData) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, 0);
uint8_t read;
ASSERT_FALSE(reader.Read1(&read));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, 0, 0));
}
TEST_F(BufferReaderTest, Read1WithNullBuffer) {
BufferReader reader(NULL, 16);
uint8_t read;
ASSERT_FALSE(reader.Read1(&read));
ASSERT_TRUE(ValidateReader(reader, NULL, 0, 0));
}
TEST_F(BufferReaderTest, Read1WithNullReturn) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, sizeof(raw_data));
ASSERT_FALSE(reader.Read1(NULL));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, sizeof(raw_data), 0));
}
TEST_F(BufferReaderTest, Read2LargeNumber) { ASSERT_TRUE(CheckRead2(30000)); }
TEST_F(BufferReaderTest, Read2SmallNumber) { ASSERT_TRUE(CheckRead2(10)); }
TEST_F(BufferReaderTest, Read2Zero) { ASSERT_TRUE(CheckRead2(0)); }
TEST_F(BufferReaderTest, Read2WithNoData) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, 0);
uint16_t read;
ASSERT_FALSE(reader.Read2(&read));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, 0, 0));
}
TEST_F(BufferReaderTest, Read2WithNullBuffer) {
BufferReader reader(NULL, 16);
uint16_t read;
ASSERT_FALSE(reader.Read2(&read));
ASSERT_TRUE(ValidateReader(reader, NULL, 0, 0));
}
TEST_F(BufferReaderTest, Read2WithNullReturn) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, sizeof(raw_data));
ASSERT_FALSE(reader.Read2(NULL));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, sizeof(raw_data), 0));
}
TEST_F(BufferReaderTest, Read2sLargePositive) {
ASSERT_TRUE(CheckRead2s(30000));
}
TEST_F(BufferReaderTest, Read2sSmallPositive) { ASSERT_TRUE(CheckRead2s(10)); }
TEST_F(BufferReaderTest, Read2sZero) { ASSERT_TRUE(CheckRead2s(0)); }
TEST_F(BufferReaderTest, Read2sSmallNegative) { ASSERT_TRUE(CheckRead2s(-10)); }
TEST_F(BufferReaderTest, Read2sLargeNegative) {
ASSERT_TRUE(CheckRead2s(-30000));
}
TEST_F(BufferReaderTest, Read2sWithNoData) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, 0);
int16_t read;
ASSERT_FALSE(reader.Read2s(&read));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, 0, 0));
}
TEST_F(BufferReaderTest, Read2sWithNullBuffer) {
BufferReader reader(NULL, 16);
int16_t read;
ASSERT_FALSE(reader.Read2s(&read));
ASSERT_TRUE(ValidateReader(reader, NULL, 0, 0));
}
TEST_F(BufferReaderTest, Read2sWithNullReturn) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, sizeof(raw_data));
ASSERT_FALSE(reader.Read2s(NULL));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, sizeof(raw_data), 0));
}
TEST_F(BufferReaderTest, Read4LargeNumber) {
// a number near uint32's max value
ASSERT_TRUE(CheckRead4(2000000000));
}
TEST_F(BufferReaderTest, Read4SmallNumber) { ASSERT_TRUE(CheckRead4(10)); }
TEST_F(BufferReaderTest, Read4Zero) { ASSERT_TRUE(CheckRead4(0)); }
TEST_F(BufferReaderTest, Read4WithNoData) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, 0);
uint32_t read;
ASSERT_FALSE(reader.Read4(&read));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, 0, 0));
}
TEST_F(BufferReaderTest, Read4WithNullBuffer) {
BufferReader reader(NULL, 16);
uint32_t read;
ASSERT_FALSE(reader.Read4(&read));
ASSERT_TRUE(ValidateReader(reader, NULL, 0, 0));
}
TEST_F(BufferReaderTest, Read4WithNullReturn) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, sizeof(raw_data));
ASSERT_FALSE(reader.Read4(NULL));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, sizeof(raw_data), 0));
}
TEST_F(BufferReaderTest, Read4sLargePositive) {
// a number near int32's max value
ASSERT_TRUE(CheckRead4s(2000000000));
}
TEST_F(BufferReaderTest, Read4sSmallPositive) { ASSERT_TRUE(CheckRead4s(10)); }
TEST_F(BufferReaderTest, Read4sZero) { ASSERT_TRUE(CheckRead4s(0)); }
TEST_F(BufferReaderTest, Read4sSmallNegative) { ASSERT_TRUE(CheckRead4s(-10)); }
TEST_F(BufferReaderTest, Read4sLargeNegative) {
// a number near int32's max negative value
ASSERT_TRUE(CheckRead4s(-2000000000));
}
TEST_F(BufferReaderTest, Read4sWithNoData) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, 0);
int32_t read;
ASSERT_FALSE(reader.Read4s(&read));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, 0, 0));
}
TEST_F(BufferReaderTest, Read4sWithNullBuffer) {
BufferReader reader(NULL, 16);
int32_t read;
ASSERT_FALSE(reader.Read4s(&read));
ASSERT_TRUE(ValidateReader(reader, NULL, 0, 0));
}
TEST_F(BufferReaderTest, Read4sWithNullReturn) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, sizeof(raw_data));
ASSERT_FALSE(reader.Read4s(NULL));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, sizeof(raw_data), 0));
}
TEST_F(BufferReaderTest, Read8LargeNumber) {
// a number near uint64's max value
ASSERT_TRUE(CheckRead8(9000000000000000000));
}
TEST_F(BufferReaderTest, Read8SmallNumber) { ASSERT_TRUE(CheckRead8(10)); }
TEST_F(BufferReaderTest, Read8Zero) { ASSERT_TRUE(CheckRead8(0)); }
TEST_F(BufferReaderTest, Read8WithNoData) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, 0);
uint64_t read;
ASSERT_FALSE(reader.Read8(&read));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, 0, 0));
}
TEST_F(BufferReaderTest, Read8WithNullBuffer) {
BufferReader reader(NULL, 16);
uint64_t read;
ASSERT_FALSE(reader.Read8(&read));
ASSERT_TRUE(ValidateReader(reader, NULL, 0, 0));
}
TEST_F(BufferReaderTest, Read8WithNullReturn) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, sizeof(raw_data));
ASSERT_FALSE(reader.Read8(NULL));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, sizeof(raw_data), 0));
}
TEST_F(BufferReaderTest, Read8sLargePositive) {
// a number near int64's max value
ASSERT_TRUE(CheckRead8s(9000000000000000000));
}
TEST_F(BufferReaderTest, Read8sSmallPositive) { ASSERT_TRUE(CheckRead8s(10)); }
TEST_F(BufferReaderTest, Read8sZero) { ASSERT_TRUE(CheckRead8s(0)); }
TEST_F(BufferReaderTest, Read8sSmallNegative) { ASSERT_TRUE(CheckRead8s(-10)); }
TEST_F(BufferReaderTest, Read8sLargeNegative) {
// a number near int64's max negative value
ASSERT_TRUE(CheckRead8s(-9000000000000000000));
}
TEST_F(BufferReaderTest, Read8sWithNoData) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, 0);
int64_t read;
ASSERT_FALSE(reader.Read8s(&read));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, 0, 0));
}
TEST_F(BufferReaderTest, Read8sWithNullBuffer) {
BufferReader reader(NULL, 16);
int64_t read;
ASSERT_FALSE(reader.Read8s(&read));
ASSERT_TRUE(ValidateReader(reader, NULL, 0, 0));
}
TEST_F(BufferReaderTest, Read8sWithNullReturn) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, sizeof(raw_data));
ASSERT_FALSE(reader.Read8s(NULL));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, sizeof(raw_data), 0));
}
TEST_F(BufferReaderTest, ReadString) {
uint8_t raw_data[5];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, sizeof(raw_data));
std::string read;
ASSERT_TRUE(reader.ReadString(&read, sizeof(raw_data)));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(read.length() == sizeof(raw_data));
ASSERT_TRUE(ValidateData((const uint8_t*)read.c_str(), read.length()));
ASSERT_TRUE(
ValidateReader(reader, raw_data, sizeof(raw_data), sizeof(raw_data)));
}
TEST_F(BufferReaderTest, ReadStringNullSource) {
BufferReader reader(NULL, 5);
std::string read;
ASSERT_FALSE(reader.ReadString(&read, 5));
ASSERT_TRUE(ValidateReader(reader, NULL, 0, 0));
}
TEST_F(BufferReaderTest, ReadStringNullReturn) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, sizeof(raw_data));
ASSERT_FALSE(reader.ReadString(NULL, 5));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, sizeof(raw_data), 0));
}
TEST_F(BufferReaderTest, ReadStringZeroCount) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, sizeof(raw_data));
std::string read;
ASSERT_TRUE(reader.ReadString(&read, 0));
ASSERT_TRUE(0 == read.length());
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, sizeof(raw_data), 0));
}
TEST_F(BufferReaderTest, ReadStringTooLarge) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, sizeof(raw_data));
std::string read;
ASSERT_FALSE(reader.ReadString(&read, sizeof(raw_data) * 2));
ASSERT_TRUE(0 == read.length());
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, sizeof(raw_data), 0));
}
TEST_F(BufferReaderTest, ReadVector) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, sizeof(raw_data));
std::vector<uint8_t> read;
ASSERT_TRUE(reader.ReadVec(&read, 4));
ASSERT_TRUE(read.size() == 4);
for (size_t i = 0; i < 4; i++) {
ASSERT_TRUE(raw_data[i] == read[i]);
}
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, sizeof(raw_data), 4));
}
TEST_F(BufferReaderTest, ReadVectorTooLarge) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, sizeof(raw_data));
std::vector<uint8_t> read;
ASSERT_FALSE(reader.ReadVec(&read, sizeof(raw_data) * 2));
ASSERT_TRUE(0 == read.size());
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, sizeof(raw_data), 0));
}
TEST_F(BufferReaderTest, ReadVectorNullSource) {
BufferReader reader(NULL, 16);
std::vector<uint8_t> read;
ASSERT_FALSE(reader.ReadVec(&read, 4));
ASSERT_TRUE(0 == read.size());
ASSERT_TRUE(ValidateReader(reader, NULL, 0, 0));
}
TEST_F(BufferReaderTest, ReadVectorNullReturn) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, sizeof(raw_data));
ASSERT_FALSE(reader.ReadVec(NULL, 4));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, sizeof(raw_data), 0));
}
TEST_F(BufferReaderTest, ReadVectorNone) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, sizeof(raw_data));
std::vector<uint8_t> read;
ASSERT_TRUE(reader.ReadVec(&read, 0));
ASSERT_TRUE(0 == read.size());
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, sizeof(raw_data), 0));
}
TEST_F(BufferReaderTest, Read4Into84Bytes) {
ASSERT_TRUE(CheckRead4Into8(0xFFFFFF));
}
TEST_F(BufferReaderTest, Read4Into83Bytes) {
ASSERT_TRUE(CheckRead4Into8(0xFFFF));
}
TEST_F(BufferReaderTest, Read4Into82Bytes) {
ASSERT_TRUE(CheckRead4Into8(0xFF));
}
TEST_F(BufferReaderTest, Read4Into8Zero) { ASSERT_TRUE(CheckRead4Into8(0)); }
TEST_F(BufferReaderTest, Read4Into8NullSource) {
BufferReader reader(NULL, 4);
uint64_t read;
ASSERT_FALSE(reader.Read4Into8(&read));
ASSERT_TRUE(ValidateReader(reader, NULL, 0, 0));
}
TEST_F(BufferReaderTest, Read4Into8TooLittleData) {
uint8_t raw_data[2];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, sizeof(raw_data));
uint64_t read;
ASSERT_FALSE(reader.Read4Into8(&read));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, sizeof(raw_data), 0));
}
TEST_F(BufferReaderTest, Read4Into8NoReturn) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, sizeof(raw_data));
ASSERT_FALSE(reader.Read4Into8(NULL));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, sizeof(raw_data), 0));
}
TEST_F(BufferReaderTest, Read4sInto8s4Bytes) {
ASSERT_TRUE(CheckRead4sInto8s(0x0FFFFFFF));
}
TEST_F(BufferReaderTest, Read4sInto8s3Bytes) {
ASSERT_TRUE(CheckRead4sInto8s(0xFFFFFF));
}
TEST_F(BufferReaderTest, Read4sInto8s2Bytes) {
ASSERT_TRUE(CheckRead4sInto8s(0xFFFF));
}
TEST_F(BufferReaderTest, Read4sInto8s1Bytes) {
ASSERT_TRUE(CheckRead4sInto8s(0xFF));
}
TEST_F(BufferReaderTest, Read4sInto8sZero) {
ASSERT_TRUE(CheckRead4sInto8s(0));
}
TEST_F(BufferReaderTest, Read4sInto8sNegative) {
ASSERT_TRUE(CheckRead4sInto8s(-100));
}
TEST_F(BufferReaderTest, Read4sInto8sNullSource) {
BufferReader reader(NULL, 4);
int64_t read;
ASSERT_FALSE(reader.Read4sInto8s(&read));
ASSERT_TRUE(ValidateReader(reader, NULL, 0, 0));
}
TEST_F(BufferReaderTest, Read4sInto8sTooLittleData) {
uint8_t raw_data[2];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, sizeof(raw_data));
int64_t read;
ASSERT_FALSE(reader.Read4sInto8s(&read));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, sizeof(raw_data), 0));
}
TEST_F(BufferReaderTest, Read4sInto8sNoReturn) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, sizeof(raw_data));
ASSERT_FALSE(reader.Read4sInto8s(NULL));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, sizeof(raw_data), 0));
}
TEST_F(BufferReaderTest, SkipBytesNone) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, sizeof(raw_data));
ASSERT_TRUE(reader.SkipBytes(0));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, sizeof(raw_data), 0));
}
TEST_F(BufferReaderTest, SkipBytes) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, sizeof(raw_data));
ASSERT_TRUE(reader.SkipBytes(4));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, sizeof(raw_data), 4));
}
TEST_F(BufferReaderTest, SkipBytesTooLarge) {
uint8_t raw_data[16];
PopulateData(raw_data, sizeof(raw_data));
BufferReader reader(raw_data, sizeof(raw_data));
ASSERT_FALSE(reader.SkipBytes(sizeof(raw_data) * 2));
ASSERT_TRUE(ValidateData(raw_data, sizeof(raw_data)));
ASSERT_TRUE(ValidateReader(reader, raw_data, sizeof(raw_data), 0));
}
} // namespace

View File

@@ -13,6 +13,7 @@
#include "initialization_data.h"
#include "license_request.h"
#include "log.h"
#include "OEMCryptoCENC.h"
#include "properties.h"
#include "scoped_ptr.h"
#include "string_conversions.h"
@@ -43,7 +44,7 @@ const std::string kWebmMimeType = "video/webm";
class WvCdmEngineTest : public testing::Test {
public:
static void SetUpTestCase() {
ConfigTestEnv config(kContentProtectionServer);
ConfigTestEnv config(kContentProtectionUatServer);
g_client_auth.assign(config.client_auth());
g_key_system.assign(config.key_system());
g_wrong_key_id.assign(config.wrong_key_id());
@@ -178,6 +179,18 @@ class WvCdmEngineTest : public testing::Test {
// Test that provisioning works, even if device is already provisioned.
TEST_F(WvCdmEngineTest, ProvisioningTest) {
uint32_t nonce = 0;
uint8_t buffer[1];
size_t size = 0;
int result = OEMCrypto_RewrapDeviceRSAKey(
0, buffer, 0, buffer, 0, &nonce, buffer, 0, buffer, buffer, &size);
if (result == OEMCrypto_ERROR_NOT_IMPLEMENTED) {
LOGW("WARNING: Skipping ProvisioningTest because the device does not "
"support provisioning. If you are using a baked-in certificate, this "
"is expected. Otherwise, something is wrong.");
return;
}
Provision();
}

View File

@@ -9,8 +9,8 @@ namespace {
const std::string kWidevineKeySystem = "com.widevine.alpha";
// Content Protection license server (UAT) data
// For staging server replace url with http://wv-staging-proxy.appspot.com/proxy
const std::string kCpLicenseServer = "http://widevine-proxy.appspot.com/proxy";
const std::string kCpUatLicenseServer =
"http://widevine-proxy.appspot.com/proxy";
const std::string kCpClientAuth = "";
const std::string kCpKeyId =
"00000042" // blob size
@@ -31,6 +31,52 @@ const std::string kCpOfflineKeyId =
// pssh data:
"08011a0d7769646576696e655f746573"
"74220d6f66666c696e655f636c697032";
const std::string kCpUatServiceCertificate =
"0ABF020803121028703454C008F63618ADE7443DB6C4C8188BE7F99005228E023082010A02"
"82010100B52112B8D05D023FCC5D95E2C251C1C649B4177CD8D2BEEF355BB06743DE661E3D"
"2ABC3182B79946D55FDC08DFE95407815E9A6274B322A2C7F5E067BB5F0AC07A89D45AEA94"
"B2516F075B66EF811D0D26E1B9A6B894F2B9857962AA171C4F66630D3E4C602718897F5E1E"
"F9B6AAF5AD4DBA2A7E14176DF134A1D3185B5A218AC05A4C41F081EFFF80A3A040C50B09BB"
"C740EEDCD8F14D675A91980F92CA7DDC646A06ADAD5101F74A0E498CC01F00532BAC217850"
"BD905E90923656B7DFEFEF42486767F33EF6283D4F4254AB72589390BEE55808F1D668080D"
"45D893C2BCA2F74D60A0C0D0A0993CEF01604703334C3638139486BC9DAF24FD67A07F9AD9"
"4302030100013A1273746167696E672E676F6F676C652E636F6D128003983E30352675F40B"
"A715FC249BDAE5D4AC7249A2666521E43655739529721FF880E0AAEFC5E27BC980DAEADABF"
"3FC386D084A02C82537848CC753FF497B011A7DA97788A00E2AA6B84CD7D71C07A48EBF616"
"02CCA5A3F32030A7295C30DA915B91DC18B9BC9593B8DE8BB50F0DEDC12938B8E9E039CDDE"
"18FA82E81BB032630FE955D85A566CE154300BF6D4C1BD126966356B287D657B18CE63D0EF"
"D45FC5269E97EAB11CB563E55643B26FF49F109C2101AFCAF35B832F288F0D9D45960E259E"
"85FB5D24DBD2CF82764C5DD9BF727EFBE9C861F869321F6ADE18905F4D92F9A6DA6536DB84"
"75871D168E870BB2303CF70C6E9784C93D2DE845AD8262BE7E0D4E2E4A0759CEF82D109D25"
"92C72429F8C01742BAE2B3DECADBC33C3E5F4BAF5E16ECB74EADBAFCB7C6705F7A9E3B6F39"
"40383F9C5116D202A20C9229EE969C2519718303B50D0130C3352E06B014D838540F8A0C22"
"7C0011E0F5B38E4E298ED2CB301EB4564965F55C5D79757A250A4EB9C84AB3E6539F6B6FDF"
"56899EA29914";
// Content Protection license server (staging) data
const std::string kCpStagingLicenseServer =
"http://wv-staging-proxy.appspot.com/proxy";
const std::string kCpStagingServiceCertificate =
"0AC102080312101705B917CC1204868B06333A2F772A8C1882B4829205228E023082010A02"
"8201010099ED5B3B327DAB5E24EFC3B62A95B598520AD5BCCB37503E0645B814D876B8DF40"
"510441AD8CE3ADB11BB88C4E725A5E4A9E0795291D58584023A7E1AF0E38A9127939300861"
"0B6F158C878C7E21BFFBFEEA77E1019E1E5781E8A45F46263D14E60E8058A8607ADCE04FAC"
"8457B137A8D67CCDEB33705D983A21FB4EECBD4A10CA47490CA47EAA5D438218DDBAF1CADE"
"3392F13D6FFB6442FD31E1BF40B0C604D1C4BA4C9520A4BF97EEBD60929AFCEEF55BBAF564"
"E2D0E76CD7C55C73A082B996120B8359EDCE24707082680D6F67C6D82C4AC5F3134490A74E"
"EC37AF4B2F010C59E82843E2582F0B6B9F5DB0FC5E6EDF64FBD308B4711BCF1250019C9F5A"
"0902030100013A146C6963656E73652E7769646576696E652E636F6D128003AE347314B5A8"
"35297F271388FB7BB8CB5277D249823CDDD1DA30B93339511EB3CCBDEA04B944B927C12134"
"6EFDBDEAC9D413917E6EC176A10438460A503BC1952B9BA4E4CE0FC4BFC20A9808AAAF4BFC"
"D19C1DCFCDF574CCAC28D1B410416CF9DE8804301CBDB334CAFCD0D40978423A642E54613D"
"F0AFCF96CA4A9249D855E42B3A703EF1767F6A9BD36D6BF82BE76BBF0CBA4FDE59D2ABCC76"
"FEB64247B85C431FBCA52266B619FC36979543FCA9CBBDBBFAFA0E1A55E755A3C7BCE655F9"
"646F582AB9CF70AA08B979F867F63A0B2B7FDB362C5BC4ECD555D85BCAA9C593C383C857D4"
"9DAAB77E40B7851DDFD24998808E35B258E75D78EAC0CA16F7047304C20D93EDE4E8FF1C6F"
"17E6243E3F3DA8FC1709870EC45FBA823A263F0CEFA1F7093B1909928326333705043A29BD"
"A6F9B4342CC8DF543CB1A1182F7C5FFF33F10490FACA5B25360B76015E9C5A06AB8EE02F00"
"D2E8D5986104AACC4DD475FD96EE9CE4E326F21B83C7058577B38732CDDABC6A6BED13FB0D"
"49D38A45EB87A5F4";
// Google Play license server data
const std::string kGpLicenseServer =
@@ -78,9 +124,11 @@ const std::string kProductionProvisioningServerUrl =
const ConfigTestEnv::LicenseServerConfiguration license_servers[] = {
{kGooglePlayServer, kGpLicenseServer, kGpClientAuth, kGpKeyId,
kGpOfflineKeyId},
{kContentProtectionServer, kCpLicenseServer, kCpClientAuth, kCpKeyId,
kCpOfflineKeyId},
kGpOfflineKeyId, ""},
{kContentProtectionUatServer, kCpUatLicenseServer, kCpClientAuth,
kCpKeyId, kCpOfflineKeyId, kCpUatServiceCertificate},
{kContentProtectionStagingServer, kCpStagingLicenseServer,
kCpClientAuth, kCpKeyId, kCpOfflineKeyId, kCpStagingServiceCertificate},
};
} // namespace
@@ -116,6 +164,7 @@ void ConfigTestEnv::Init(LicenseServerId server_id) {
key_system_ = kWidevineKeySystem;
license_server_ = license_servers[server_id].url;
provisioning_server_url_ = kProductionProvisioningServerUrl;
service_certificate_ = license_servers[server_id].service_certificate;
wrong_key_id_ = kWrongKeyId;
}

View File

@@ -9,7 +9,8 @@
namespace wvcdm {
typedef enum {
kGooglePlayServer,
kContentProtectionServer,
kContentProtectionUatServer,
kContentProtectionStagingServer,
} LicenseServerId;
// Configures default test environment.
@@ -21,13 +22,14 @@ class ConfigTestEnv {
std::string client_tag;
std::string key_id;
std::string offline_key_id;
std::string service_certificate;
} LicenseServerConfiguration;
explicit ConfigTestEnv(LicenseServerId server_id);
ConfigTestEnv(LicenseServerId server_id, bool streaming);
ConfigTestEnv(LicenseServerId server_id, bool streaming, bool renew,
bool release);
~ConfigTestEnv() {};
~ConfigTestEnv(){};
const std::string& client_auth() const { return client_auth_; }
const KeyId& key_id() const { return key_id_; }
@@ -36,6 +38,9 @@ class ConfigTestEnv {
const std::string& provisioning_server_url() const {
return provisioning_server_url_;
}
const std::string& service_certificate() const {
return service_certificate_;
}
const KeyId& wrong_key_id() const { return wrong_key_id_; }
void set_key_id(KeyId& key_id) { key_id_.assign(key_id); }
@@ -54,6 +59,7 @@ class ConfigTestEnv {
CdmKeySystem key_system_;
std::string license_server_;
std::string provisioning_server_url_;
std::string service_certificate_;
KeyId wrong_key_id_;
CORE_DISALLOW_COPY_AND_ASSIGN(ConfigTestEnv);

View File

@@ -105,7 +105,7 @@ bool SocketWait(int fd, bool for_read, int timeout_in_ms) {
// static
bool HttpSocket::ParseUrl(const std::string& url, std::string* scheme,
bool* secure_connect, std::string* domain_name,
int* port, std::string* path) {
std::string* port, std::string* path) {
size_t offset = 0;
if (!Tokenize(url, "://", offset, scheme, &offset)) {
@@ -117,10 +117,10 @@ bool HttpSocket::ParseUrl(const std::string& url, std::string* scheme,
// Otherwise, consider the scheme unsupported and fail.
if (*scheme == "http") {
*secure_connect = false;
*port = 80;
port->assign("80");
} else if (*scheme == "https") {
*secure_connect = true;
*port = 443;
port->assign("443");
} else {
LOGE("Invalid URL, scheme not supported: %s", url.c_str());
return false;
@@ -140,8 +140,9 @@ bool HttpSocket::ParseUrl(const std::string& url, std::string* scheme,
std::string domain_name_without_port;
size_t port_offset;
if (Tokenize(*domain_name, ":", 0, &domain_name_without_port, &port_offset)) {
*port = atoi(domain_name->c_str() + port_offset);
if (*port <= 0 || *port >= 65536) {
port->assign(domain_name->c_str() + port_offset);
int port_num = atoi(port->c_str());
if (port_num <= 0 || port_num >= 65536) {
LOGE("Invalid URL, port not valid: %s", url.c_str());
return false;
}
@@ -180,8 +181,24 @@ bool HttpSocket::Connect(int timeout_in_ms) {
return false;
}
// lookup the server IP
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG;
struct addrinfo* addr_info = NULL;
int ret = getaddrinfo(domain_name_.c_str(), port_.c_str(), &hints,
&addr_info);
if (ret != 0) {
LOGE("getaddrinfo failed, errno = %d", ret);
return false;
}
// get a socket
socket_fd_ = socket(AF_INET, SOCK_STREAM, 0);
socket_fd_ = socket(addr_info->ai_family, addr_info->ai_socktype,
addr_info->ai_protocol);
if (socket_fd_ < 0) {
LOGE("cannot open socket, errno = %d", errno);
return false;
@@ -200,24 +217,6 @@ bool HttpSocket::Connect(int timeout_in_ms) {
return false;
}
// lookup the server IP
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
struct addrinfo* addr_info = NULL;
int ret = getaddrinfo(domain_name_.c_str(), NULL, &hints, &addr_info);
if (ret != 0) {
LOGE("getaddrinfo failed, errno = %d", ret);
return false;
}
// set the port
struct sockaddr_in* addr_ipv4 =
reinterpret_cast<struct sockaddr_in*>(addr_info->ai_addr);
addr_ipv4->sin_port = htons(port_);
// connect to the server
ret = connect(socket_fd_, addr_info->ai_addr, addr_info->ai_addrlen);
freeaddrinfo(addr_info);

View File

@@ -3,6 +3,8 @@
#ifndef CDM_TEST_HTTP_SOCKET_H_
#define CDM_TEST_HTTP_SOCKET_H_
#include <stdlib.h>
#include <string>
#include <gtest/gtest_prod.h>
@@ -25,7 +27,7 @@ class HttpSocket {
const std::string& scheme() const { return scheme_; }
bool secure_connect() const { return secure_connect_; }
const std::string& domain_name() const { return domain_name_; }
int port() const { return port_; }
int port() const { return atoi(port_.c_str()); }
const std::string& resource_path() const { return resource_path_; }
int Read(char* data, int len, int timeout_in_ms);
@@ -34,13 +36,13 @@ class HttpSocket {
private:
static bool ParseUrl(const std::string& url, std::string* scheme,
bool* secure_connect, std::string* domain_name,
int* port, std::string* path);
std::string* port, std::string* path);
FRIEND_TEST(HttpSocketTest, ParseUrlTest);
std::string scheme_;
bool secure_connect_;
std::string domain_name_;
int port_;
std::string port_;
std::string resource_path_;
bool valid_url_;

View File

@@ -98,7 +98,7 @@ struct ParseUrlTests {
const char* scheme;
bool secure_connect;
const char* domain_name;
int port;
const char* port;
const char* path;
};
@@ -108,7 +108,7 @@ ParseUrlTests parse_url_tests[] = {
"https", // scheme
true, // secure_connect
"code.google.com", // domain_name
443, // port
"443", // port
"/p/googletest/wiki/Primer", // path
},
{
@@ -116,7 +116,7 @@ ParseUrlTests parse_url_tests[] = {
"http", // scheme
false, // secure_connect
"code.google.com", // domain_name
80, // port
"80", // port
"/p/googletest/wiki/Primer/", // path
},
{
@@ -124,7 +124,7 @@ ParseUrlTests parse_url_tests[] = {
"http", // scheme
false, // secure_connect
"code.google.com", // domain_name
80, // port
"80", // port
"/", // path
},
{
@@ -132,7 +132,7 @@ ParseUrlTests parse_url_tests[] = {
"http", // scheme
false, // secure_connect
"code.google.com", // domain_name
80, // port
"80", // port
"/", // path
},
{
@@ -140,7 +140,7 @@ ParseUrlTests parse_url_tests[] = {
"http", // scheme
false, // secure_connect
"10.11.12.13", // domain_name
8888, // port
"8888", // port
"/drm", // path
},
{
@@ -148,7 +148,7 @@ ParseUrlTests parse_url_tests[] = {
"http", // scheme
false, // secure_connect
"10.11.12.13", // domain_name
8888, // port
"8888", // port
"/", // path
},
{
@@ -156,7 +156,7 @@ ParseUrlTests parse_url_tests[] = {
"https", // scheme
true, // secure_connect
"10.11.12.13", // domain_name
8888, // port
"8888", // port
"/", // path
},
{NULL, NULL, false, NULL, 0, NULL} // list terminator
@@ -166,7 +166,7 @@ TEST_F(HttpSocketTest, ParseUrlTest) {
std::string scheme;
bool secure_connect;
std::string domain_name;
int port;
std::string port;
std::string path;
ParseUrlTests* test = NULL;

View File

@@ -100,7 +100,7 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
break;
case EMPTY_LICENSE_RESPONSE_2: *os << "EMPTY_LICENSE_RESPONSE_2";
break;
case EMPTY_PROVISIONING_CERTIFICATE: *os << "EMPTY_PROVISIONING_CERTIFICATE";
case EMPTY_PROVISIONING_CERTIFICATE_1: *os << "EMPTY_PROVISIONING_CERTIFICATE_1";
break;
case EMPTY_PROVISIONING_RESPONSE: *os << "EMPTY_PROVISIONING_RESPONSE";
break;
@@ -337,6 +337,7 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
break;
case EMPTY_LICENSE_REQUEST: *os << "EMPTY_LICENSE_REQUEST";
break;
case DUPLICATE_SESSION_ID_SPECIFIED: *os << "DUPLICATE_SESSION_ID_SPECIFIED";
default:
*os << "Unknown CdmResponseType";
break;

View File

@@ -60,6 +60,7 @@ const int kShortSleep = 1 * kSpeedMultiplier;
const int kLongSleep = 2 * kSpeedMultiplier;
const uint32_t kDuration = 2 * kSpeedMultiplier;
const uint32_t kLongDuration = 5 * kSpeedMultiplier;
const int32_t kAlmostRange = 3 * kSpeedMultiplier;
} // namespace
typedef struct {
@@ -739,9 +740,9 @@ static void dump_openssl_error() {
}
// We don't expect exact timing.
#define EXPECT_ALMOST(A, B) \
EXPECT_GE(A + kSpeedMultiplier, B); \
EXPECT_LE(A - kSpeedMultiplier, B);
#define EXPECT_ALMOST(A, B) \
EXPECT_GE(A + kAlmostRange, B); \
EXPECT_LE(A - kAlmostRange, B);
class Session {
public:
@@ -768,7 +769,7 @@ class Session {
}
void open() {
EXPECT_TRUE(!open_);
EXPECT_FALSE(open_);
session_status_ = OEMCrypto_OpenSession(&session_id_);
if (OEMCrypto_SUCCESS == session_status_) {
open_ = true;
@@ -1386,7 +1387,7 @@ class Session {
vector<uint8_t> mac_context;
vector<uint8_t> enc_context;
FillDefaultContext(&mac_context, &enc_context);
ASSERT_EQ(OEMCrypto_ERROR_INVALID_RSA_KEY,
ASSERT_NE(OEMCrypto_SUCCESS,
OEMCrypto_DeriveKeysFromSessionKey(
session_id(), &enc_session_key[0], enc_session_key.size(),
&mac_context[0], mac_context.size(), &enc_context[0],
@@ -1663,7 +1664,10 @@ TEST_F(OEMCryptoClientTest, MaxSessionsOpenCloseAPI10) {
// We expect OEMCrypto implementations support at least 8 sessions.
const size_t kMinimumSupportedMaxNumberOfSessions = 8u;
ASSERT_GE(max_sessions, kMinimumSupportedMaxNumberOfSessions);
// We allow GetMaxNumberOfSessions to return an estimate. This tests with a
// pad of 5%. Even if it's just an estimate, we still require 8 sessions.
size_t max_sessions_with_pad = max(max_sessions * 19/20,
kMinimumSupportedMaxNumberOfSessions);
vector<OEMCrypto_SESSION> sessions;
// Limit the number of sessions for testing.
const size_t kMaxNumberOfSessionsForTesting = 0x100u;
@@ -1677,7 +1681,7 @@ TEST_F(OEMCryptoClientTest, MaxSessionsOpenCloseAPI10) {
// OEMCrypto_ERROR_TOO_MANY_SESSIONS if too many sessions are open.
if (sts != OEMCrypto_SUCCESS) {
ASSERT_EQ(OEMCrypto_ERROR_TOO_MANY_SESSIONS, sts);
ASSERT_GE(i, max_sessions);
ASSERT_GE(i, max_sessions_with_pad);
break;
}
ASSERT_EQ(OEMCrypto_SUCCESS,
@@ -2536,8 +2540,8 @@ TEST_F(OEMCryptoSessionTests, DecryptZeroDuration) {
class OEMCryptoSessionTestsDecryptEdgeCases : public OEMCryptoSessionTests {
public:
// Increment counter for AES-CTR. The CENC spec specifies we increment only
// the low 64 bits of the IV counter, and leave the high 64 bits alone. This is
// different from the OpenSSL implementation, so we implement the CTR loop
// the low 64 bits of the IV counter, and leave the high 64 bits alone. This
// is different from the OpenSSL implementation, so we implement the CTR loop
// ourselves.
void ctr128_inc64(int64_t increaseBy, uint8_t* iv) {
uint64_t* counterBuffer = reinterpret_cast<uint64_t*>(&iv[8]);
@@ -2688,6 +2692,15 @@ TEST_F(OEMCryptoSessionTestsDecryptEdgeCases, OddOffset) {
subsample_size);
}
// This tests that the algorithm used to increment the counter for
// AES-CTR mode is correct. There are two possible implementations:
// 1) increment the counter as if it were a 128 bit number,
// 2) increment the low 64 bits as a 64 bit number and leave the high bits alone.
// For CENC, the algorithm we should use is the second one. OpenSSL defaults to
// the first. If this test is not passing, you should look at the way you
// increment the counter. Look at the example code in ctr128_inc64 above.
// If you start with an IV of 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE, after you
// increment twice, you should get 0xFFFFFFFFFFFFFFFF0000000000000000.
TEST_F(OEMCryptoSessionTestsDecryptEdgeCases, DecryptWithNearWrap) {
vector<size_t> subsample_size;
subsample_size.push_back(150);
@@ -3410,7 +3423,6 @@ class OEMCryptoCastReceiverTest : public OEMCryptoLoadsCertificateAlternates {
vector<uint8_t> field_e = encode(0x02, wvcdm::a2b_hex("010001"));
vector<uint8_t> field_d =
encode(0x02, wvcdm::a2b_hex(
"00"
"5bd910257830dce17520b03441a51a8c"
"ab94020ac6ecc252c808f3743c95b7c8"
"3b8c8af1a5014346ebc4242cdfb5d718"
@@ -3462,7 +3474,6 @@ class OEMCryptoCastReceiverTest : public OEMCryptoLoadsCertificateAlternates {
"0dcbbc9b528f64a01706e05b0b91106f"));
vector<uint8_t> field_exp2 =
encode(0x02, wvcdm::a2b_hex(
"00"
"6827924a85e88b55ba00f8219128bd37"
"24c6b7d1dfe5629ef197925fecaff5ed"
"b9cdf3a7befd8ea2e8dd3707138b3ff8"
@@ -3473,7 +3484,6 @@ class OEMCryptoCastReceiverTest : public OEMCryptoLoadsCertificateAlternates {
"eec82d7f5458ec19e71b90eeef7dff61"));
vector<uint8_t> field_invq =
encode(0x02, wvcdm::a2b_hex(
"00"
"57b73888d183a99a6307422277551a3d"
"9e18adf06a91e8b55ceffef9077c8496"
"948ecb3b16b78155cb2a3a57c119d379"
@@ -5424,6 +5434,11 @@ TEST_P(UsageTableTestWithMAC, ReloadOfflineLicense) {
Session s;
LoadOfflineLicense(s, pst);
// If there are errors in LoadOfflineLicense, that function will exit but this
// test will continue. The session will be left open and in an unknown state.
// Best just to abort in that case.
ASSERT_FALSE(s.isOpen()) << "LoadOfflineLicense() failed. Aborting.";
s.open(); // Offline license can be reused.
s.GenerateTestSessionKeys();
// We will reuse the encrypted and signed message, so we don't call
@@ -5452,6 +5467,11 @@ TEST_P(UsageTableTestWithMAC, BadReloadOfflineLicense) {
Session s;
LoadOfflineLicense(s, pst);
// If there are errors in LoadOfflineLicense, that function will exit but this
// test will continue. The session will be left open and in an unknown state.
// Best just to abort in that case.
ASSERT_FALSE(s.isOpen()) << "LoadOfflineLicense() failed. Aborting.";
// Offline license with new mac keys should fail.
Session s2;
s2.open();
@@ -5523,6 +5543,11 @@ TEST_P(UsageTableTestWithMAC, DeactivateOfflineLicense) {
Session s;
LoadOfflineLicense(s, pst);
// If there are errors in LoadOfflineLicense, that function will exit but this
// test will continue. The session will be left open and in an unknown state.
// Best just to abort in that case.
ASSERT_FALSE(s.isOpen()) << "LoadOfflineLicense() failed. Aborting.";
s.open();
s.GenerateTestSessionKeys();
s.LoadTestKeys(pst, new_mac_keys_); // Reload the license
@@ -5589,6 +5614,13 @@ TEST_F(UsageTableTest, TimingTest) {
LoadOfflineLicense(s3, pst3);
time_t loaded3 = time(NULL);
// If there are errors in LoadOfflineLicense, that function will exit but this
// test will continue. The sessions will be left open and in an unknown state.
// Best just to abort in that case.
ASSERT_FALSE(s1.isOpen()) << "LoadOfflineLicense() failed. Aborting.";
ASSERT_FALSE(s2.isOpen()) << "LoadOfflineLicense() failed. Aborting.";
ASSERT_FALSE(s3.isOpen()) << "LoadOfflineLicense() failed. Aborting.";
sleep(kLongSleep);
s1.open();
s1.GenerateTestSessionKeys();