Source release v3.0.1 + third_party
This commit is contained in:
BIN
README.pdf
BIN
README.pdf
Binary file not shown.
@@ -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',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
'test/test_host.cpp',
|
||||
'test/test_host.h',
|
||||
],
|
||||
'variables': {
|
||||
'cdm_dir': '..',
|
||||
},
|
||||
'includes': [
|
||||
'oemcrypto_unittests.gypi',
|
||||
'core_unittests.gypi',
|
||||
|
||||
@@ -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',
|
||||
],
|
||||
}
|
||||
|
||||
@@ -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() {}
|
||||
};
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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_; }
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
838
core/test/buffer_reader_test.cpp
Normal file
838
core/test/buffer_reader_test.cpp
Normal 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
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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_;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user