Merge "Clean comments, namespace, and variable names"
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
// Copyright 2012 Google Inc. All Rights Reserved.
|
||||
|
||||
#ifndef CDM_BASE_BUFFER_READER_H_
|
||||
#define CDM_BASE_BUFFER_READER_H_
|
||||
#ifndef WVCDM_CORE_BUFFER_READER_H_
|
||||
#define WVCDM_CORE_BUFFER_READER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
@@ -65,4 +65,4 @@ class BufferReader {
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // CDM_BASE_BUFFER_READER_H_
|
||||
#endif // WVCDM_CORE_BUFFER_READER_H_
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
#ifndef CDM_BASE_CDM_CLIENT_PROPERTY_SET_H_
|
||||
#define CDM_BASE_CDM_CLIENT_PROPERTY_SET_H_
|
||||
#ifndef WVCDM_CORE_CDM_CLIENT_PROPERTY_SET_H_
|
||||
#define WVCDM_CORE_CDM_CLIENT_PROPERTY_SET_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -23,4 +23,4 @@ class CdmClientPropertySet {
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // CDM_BASE_CDM_CLIENT_PROPERTY_SET_H_
|
||||
#endif // WVCDM_CORE_CDM_CLIENT_PROPERTY_SET_H_
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
#ifndef CDM_BASE_CDM_ENGINE_H_
|
||||
#define CDM_BASE_CDM_ENGINE_H_
|
||||
#ifndef WVCDM_CORE_CDM_ENGINE_H_
|
||||
#define WVCDM_CORE_CDM_ENGINE_H_
|
||||
|
||||
#include "certificate_provisioning.h"
|
||||
#include "initialization_data.h"
|
||||
@@ -132,4 +132,4 @@ class CdmEngine {
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // CDM_BASE_CDM_ENGINE_H_
|
||||
#endif // WVCDM_CORE_CDM_ENGINE_H_
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2012 Google Inc. All Rights Reserved.
|
||||
|
||||
#ifndef CDM_BASE_CDM_SESSION_H_
|
||||
#define CDM_BASE_CDM_SESSION_H_
|
||||
#ifndef WVCDM_CORE_CDM_SESSION_H_
|
||||
#define WVCDM_CORE_CDM_SESSION_H_
|
||||
|
||||
#include <set>
|
||||
|
||||
@@ -131,4 +131,4 @@ class CdmSession {
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // CDM_BASE_CDM_SESSION_H_
|
||||
#endif // WVCDM_CORE_CDM_SESSION_H_
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
#ifndef CDM_BASE_CERTIFICATE_PROVISIONING_H_
|
||||
#define CDM_BASE_CERTIFICATE_PROVISIONING_H_
|
||||
#ifndef WVCDM_CORE_CERTIFICATE_PROVISIONING_H_
|
||||
#define WVCDM_CORE_CERTIFICATE_PROVISIONING_H_
|
||||
|
||||
#include "crypto_session.h"
|
||||
#include "oemcrypto_adapter.h"
|
||||
@@ -40,4 +40,4 @@ class CertificateProvisioning {
|
||||
};
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // CDM_BASE_CERTIFICATE_PROVISIONING_H_
|
||||
#endif // WVCDM_CORE_CERTIFICATE_PROVISIONING_H_
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
//
|
||||
// Clock - Platform independent interface for a time library
|
||||
//
|
||||
#ifndef CDM_BASE_CLOCK_H_
|
||||
#define CDM_BASE_CLOCK_H_
|
||||
#ifndef WVCDM_CORE_CLOCK_H_
|
||||
#define WVCDM_CORE_CLOCK_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -22,4 +22,4 @@ class Clock {
|
||||
|
||||
}; // namespace wvcdm
|
||||
|
||||
#endif // CDM_BASE_CLOCK_H_
|
||||
#endif // WVCDM_CORE_CLOCK_H_
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
// Copyright 2012 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// OEMCrypto Client - wrapper class for C-style OEMCrypto interface
|
||||
//
|
||||
#ifndef CDM_BASE_CRYPTO_KEY_H_
|
||||
#define CDM_BASE_CRYPTO_KEY_H_
|
||||
|
||||
#ifndef WVCDM_CORE_CRYPTO_KEY_H_
|
||||
#define WVCDM_CORE_CRYPTO_KEY_H_
|
||||
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
@@ -39,4 +37,4 @@ private:
|
||||
|
||||
}; // namespace wvcdm
|
||||
|
||||
#endif // CDM_BASE_CRYPTO_KEY_H_
|
||||
#endif // WVCDM_CORE_CRYPTO_KEY_H_
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
// Copyright 2012 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// OEMCrypto Client - wrapper class for C-style OEMCrypto interface
|
||||
//
|
||||
#ifndef CDM_BASE_CRYPTO_SESSSION_H_
|
||||
#define CDM_BASE_CRYPTO_SESSSION_H_
|
||||
|
||||
#ifndef WVCDM_CORE_CRYPTO_SESSSION_H_
|
||||
#define WVCDM_CORE_CRYPTO_SESSSION_H_
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
@@ -103,4 +101,4 @@ class CryptoSession {
|
||||
|
||||
}; // namespace wvcdm
|
||||
|
||||
#endif // CDM_BASE_CRYPTO_SESSSION_H_
|
||||
#endif // WVCDM_CORE_CRYPTO_SESSSION_H_
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
#ifndef CDM_BASE_DEVICE_FILES_H_
|
||||
#define CDM_BASE_DEVICE_FILES_H_
|
||||
#ifndef WVCDM_CORE_DEVICE_FILES_H_
|
||||
#define WVCDM_CORE_DEVICE_FILES_H_
|
||||
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
@@ -73,4 +73,4 @@ class DeviceFiles {
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // CDM_BASE_DEVICE_FILES_H_
|
||||
#endif // WVCDM_CORE_DEVICE_FILES_H_
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
//
|
||||
// File - Platform independent interface for a File class
|
||||
//
|
||||
#ifndef CDM_BASE_FILE_STORE_H_
|
||||
#define CDM_BASE_FILE_STORE_H_
|
||||
#ifndef WVCDM_CORE_FILE_STORE_H_
|
||||
#define WVCDM_CORE_FILE_STORE_H_
|
||||
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
@@ -48,4 +48,4 @@ class File {
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // CDM_BASE_FILE_STORE_H_
|
||||
#endif // WVCDM_CORE_FILE_STORE_H_
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2012 Google Inc. All Rights Reserved.
|
||||
|
||||
#ifndef CDM_BASE_LICENSE_H_
|
||||
#define CDM_BASE_LICENSE_H_
|
||||
#ifndef WVCDM_CORE_LICENSE_H_
|
||||
#define WVCDM_CORE_LICENSE_H_
|
||||
|
||||
#include <set>
|
||||
|
||||
@@ -76,4 +76,4 @@ class CdmLicense {
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // CDM_BASE_LICENSE_H_
|
||||
#endif // WVCDM_CORE_LICENSE_H_
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
//
|
||||
// Lock - Platform independent interface for a Mutex class
|
||||
//
|
||||
#ifndef CDM_BASE_LOCK_H_
|
||||
#define CDM_BASE_LOCK_H_
|
||||
#ifndef WVCDM_CORE_LOCK_H_
|
||||
#define WVCDM_CORE_LOCK_H_
|
||||
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
@@ -58,4 +58,4 @@ class AutoLock {
|
||||
|
||||
}; // namespace wvcdm
|
||||
|
||||
#endif // CDM_BASE_LOCK_H_
|
||||
#endif // WVCDM_CORE_LOCK_H_
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
//
|
||||
// Log - Platform independent interface for a Logging class
|
||||
//
|
||||
#ifndef CDM_BASE_LOG_H_
|
||||
#define CDM_BASE_LOG_H_
|
||||
#ifndef WVCDM_CORE_LOG_H_
|
||||
#define WVCDM_CORE_LOG_H_
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
@@ -17,13 +17,10 @@ typedef enum {
|
||||
LOG_VERBOSE
|
||||
} LogPriority;
|
||||
|
||||
// Required to enable/disable verbose logging (LOGV) in Chromium. In Chromium,
|
||||
// verbose logging level is controlled using command line switches --v (global)
|
||||
// or --vmodule (per module). This function calls logging::InitLogging to
|
||||
// initialize logging, which should have already been included in most Chromium
|
||||
// based binaries. However, it is typically not included by default in
|
||||
// unittests, in particular, the unittests in CDM core need to call InitLogging
|
||||
// to be able to control verbose logging in command line.
|
||||
// Enable/disable verbose logging (LOGV).
|
||||
// This function is supplied for cases where the system layer does not
|
||||
// initialize logging. This is also needed to initialize logging in
|
||||
// unit tests.
|
||||
void InitLogging(int argc, const char* const* argv);
|
||||
|
||||
void Log(const char* file, int line, LogPriority level, const char* fmt, ...);
|
||||
@@ -37,4 +34,4 @@ void Log(const char* file, int line, LogPriority level, const char* fmt, ...);
|
||||
|
||||
}; // namespace wvcdm
|
||||
|
||||
#endif // CDM_BASE_LOG_H_
|
||||
#endif // WVCDM_CORE_LOG_H_
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
/*********************************************************************
|
||||
* oemcrypto_adapter.h
|
||||
*
|
||||
* (c) Copyright 2013 Google, Inc.
|
||||
*
|
||||
* This interface allows CDM to open a Level 3 session instead of
|
||||
* letting the wrapper function choose between level 1 or level 3.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef OEMCRYPTO_ADAPTER_H_
|
||||
#define OEMCRYPTO_ADAPTER_H_
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// oemcrypto_adapter.h
|
||||
// This interface allows CDM to open a Level 3 session instead of
|
||||
// letting the wrapper function choose between level 1 or level 3.
|
||||
//
|
||||
#ifndef WVCDM_CORE_OEMCRYPTO_ADAPTER_H_
|
||||
#define WVCDM_CORE_OEMCRYPTO_ADAPTER_H_
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
|
||||
@@ -37,4 +33,4 @@ const char* OEMCrypto_SecurityLevel(SecurityLevel level);
|
||||
bool OEMCrypto_SupportsUsageTable(SecurityLevel level);
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // OEMCRYPTO_ADAPTER_H_
|
||||
#endif // WVCDM_CORE_OEMCRYPTO_ADAPTER_H_
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
#ifndef CDM_BASE_POLICY_ENGINE_H_
|
||||
#define CDM_BASE_POLICY_ENGINE_H_
|
||||
#ifndef WVCDM_CORE_POLICY_ENGINE_H_
|
||||
#define WVCDM_CORE_POLICY_ENGINE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
@@ -25,7 +25,7 @@ class PolicyEngine {
|
||||
// UpdateLicense/OnTimerEvent/BeginDecryption and may be out of sync
|
||||
// depending on the amount of time elapsed. The current decryption
|
||||
// status is not calculated to avoid overhead in the decryption path.
|
||||
inline bool can_decrypt() { return can_decrypt_; }
|
||||
inline bool can_decrypt() { return can_decrypt_; }
|
||||
|
||||
// OnTimerEvent is called when a timer fires. It notifies the Policy Engine
|
||||
// that the timer has fired and that it should check whether any events have
|
||||
@@ -118,5 +118,4 @@ class PolicyEngine {
|
||||
|
||||
} // wvcdm
|
||||
|
||||
#endif // CDM_BASE_POLICY_ENGINE_H_
|
||||
|
||||
#endif // WVCDM_CORE_POLICY_ENGINE_H_
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// RsaPublicKey based on //depot/google3/video/widevine/common/rsa_key.h by
|
||||
// tinskip@google.com.
|
||||
//
|
||||
// Description:
|
||||
// Declaration of classes representing AES and RSA public keys used
|
||||
// for signature verification and encryption.
|
||||
@@ -21,9 +18,9 @@
|
||||
// Algorithm: RSA-OAEP
|
||||
// Mask generation function: mgf1SHA1
|
||||
// Label (encoding paramter): empty string
|
||||
|
||||
#ifndef CDM_BASE_PRIVACY_CRYPTO_H_
|
||||
#define CDM_BASE_PRIVACY_CRYPTO_H_
|
||||
//
|
||||
#ifndef WVCDM_CORE_PRIVACY_CRYPTO_H_
|
||||
#define WVCDM_CORE_PRIVACY_CRYPTO_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
@@ -74,4 +71,4 @@ class RsaPublicKey {
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // CDM_BASE_PRIVACY_CRYPTO_H_
|
||||
#endif // WVCDM_CORE_PRIVACY_CRYPTO_H_
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
#ifndef CDM_BASE_PROPERTIES_H_
|
||||
#define CDM_BASE_PROPERTIES_H_
|
||||
#ifndef WVCDM_CORE_PROPERTIES_H_
|
||||
#define WVCDM_CORE_PROPERTIES_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
@@ -121,4 +121,4 @@ class Properties {
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // CDM_BASE_PROPERTIES_H_
|
||||
#endif // WVCDM_CORE_PROPERTIES_H_
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
// A simple and partial implementation of scoped_ptr class.
|
||||
// The implementation is copied from gtest/include/gtest/internal/gtest-port.h.
|
||||
//
|
||||
#ifndef CDM_BASE_SCOPED_PTR_H_
|
||||
#define CDM_BASE_SCOPED_PTR_H_
|
||||
#ifndef WVCDM_CORE_SCOPED_PTR_H_
|
||||
#define WVCDM_CORE_SCOPED_PTR_H_
|
||||
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
@@ -61,4 +61,4 @@ class scoped_ptr {
|
||||
|
||||
}; // namespace wvcdm
|
||||
|
||||
#endif // CDM_BASE_SCOPED_PTR_H_
|
||||
#endif // WVCDM_CORE_SCOPED_PTR_H_
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
#ifndef CDM_BASE_STRING_CONVERSIONS_H_
|
||||
#define CDM_BASE_STRING_CONVERSIONS_H_
|
||||
#ifndef WVCDM_CORE_STRING_CONVERSIONS_H_
|
||||
#define WVCDM_CORE_STRING_CONVERSIONS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
@@ -25,4 +25,4 @@ int64_t htonll64(int64_t x);
|
||||
|
||||
}; // namespace wvcdm
|
||||
|
||||
#endif // CDM_BASE_STRING_CONVERSIONS_H_
|
||||
#endif // WVCDM_CORE_STRING_CONVERSIONS_H_
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
//
|
||||
// Timer - Platform independent interface for a Timer class
|
||||
//
|
||||
#ifndef CDM_BASE_TIMER_H_
|
||||
#define CDM_BASE_TIMER_H_
|
||||
#ifndef WVCDM_CORE_TIMER_H_
|
||||
#define WVCDM_CORE_TIMER_H_
|
||||
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
@@ -48,4 +48,4 @@ class Timer {
|
||||
|
||||
}; // namespace wvcdm
|
||||
|
||||
#endif // CDM_BASE_TIMER_H_
|
||||
#endif // WVCDM_CORE_TIMER_H_
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
// Copyright 2012 Google Inc. All Rights Reserved.
|
||||
|
||||
#ifndef CDM_BASE_WV_CDM_CONSTANTS_H_
|
||||
#define CDM_BASE_WV_CDM_CONSTANTS_H_
|
||||
#ifndef WVCDM_CORE_WV_CDM_CONSTANTS_H_
|
||||
#define WVCDM_CORE_WV_CDM_CONSTANTS_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace wvcdm {
|
||||
static const size_t KEY_CONTROL_SIZE = 16;
|
||||
// TODO(kqyang): Key ID size is not fixed in spec, but conventionally we
|
||||
// always use 16 bytes key id. We'll need to update oemcrypto to support
|
||||
// variable size key id.
|
||||
static const size_t KEY_ID_SIZE = 16;
|
||||
static const size_t KEY_IV_SIZE = 16;
|
||||
static const size_t KEY_PAD_SIZE = 16;
|
||||
@@ -64,4 +61,4 @@ static const std::string CENC_INIT_DATA_FORMAT = "cenc";
|
||||
static const std::string WEBM_INIT_DATA_FORMAT = "webm";
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // CDM_BASE_WV_CDM_CONSTANTS_H_
|
||||
#endif // WVCDM_CORE_WV_CDM_CONSTANTS_H_
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2012 Google Inc. All Rights Reserved.
|
||||
|
||||
#ifndef CDM_BASE_WV_CDM_EVENT_LISTENER_H_
|
||||
#define CDM_BASE_WV_CDM_EVENT_LISTENER_H_
|
||||
#ifndef WVCDM_CORE_WV_CDM_EVENT_LISTENER_H_
|
||||
#define WVCDM_CORE_WV_CDM_EVENT_LISTENER_H_
|
||||
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
@@ -25,4 +25,4 @@ class WvCdmEventListener {
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // CDM_BASE_WV_CDM_EVENT_LISTENER_H_
|
||||
#endif // WVCDM_CORE_WV_CDM_EVENT_LISTENER_H_
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
#ifndef CDM_BASE_WV_CDM_TYPES_H_
|
||||
#define CDM_BASE_WV_CDM_TYPES_H_
|
||||
#ifndef WVCDM_CORE_WV_CDM_TYPES_H_
|
||||
#define WVCDM_CORE_WV_CDM_TYPES_H_
|
||||
|
||||
#include <map>
|
||||
#include <stdint.h>
|
||||
@@ -125,4 +125,4 @@ class Key;
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // CDM_BASE_WV_CDM_TYPES_H_
|
||||
#endif // WVCDM_CORE_WV_CDM_TYPES_H_
|
||||
|
||||
@@ -19,7 +19,8 @@ bool BufferReader::Read1(uint8_t* v) {
|
||||
// Internal implementation of multi-byte reads
|
||||
template<typename T> bool BufferReader::Read(T* v) {
|
||||
if (!HasBytes(sizeof(T))) {
|
||||
LOGE("BufferReader::Read<T> : Failure while parsing: Not enough bytes (%u)", sizeof(T));
|
||||
LOGE("BufferReader::Read<T> : Failure during parse: Not enough bytes (%u)",
|
||||
sizeof(T));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -41,7 +42,8 @@ bool BufferReader::Read8s(int64_t* v) { return Read(v); }
|
||||
|
||||
bool BufferReader::ReadString(std::string* str, int count) {
|
||||
if (!HasBytes(count)) {
|
||||
LOGE("BufferReader::ReadString : Failure while parsing: Not enough bytes (%d)", count);
|
||||
LOGE("BufferReader::ReadString : Parse Failure: Not enough bytes (%d)",
|
||||
count);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -52,7 +54,7 @@ bool BufferReader::ReadString(std::string* str, int count) {
|
||||
|
||||
bool BufferReader::ReadVec(std::vector<uint8_t>* vec, int count) {
|
||||
if (!HasBytes(count)) {
|
||||
LOGE("BufferReader::ReadVec : Failure while parsing: Not enough bytes (%d)", count);
|
||||
LOGE("BufferReader::ReadVec : Parse Failure: Not enough bytes (%d)", count);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -64,7 +66,8 @@ bool BufferReader::ReadVec(std::vector<uint8_t>* vec, int count) {
|
||||
|
||||
bool BufferReader::SkipBytes(int bytes) {
|
||||
if (!HasBytes(bytes)) {
|
||||
LOGE("BufferReader::SkipBytes : Failure while parsing: Not enough bytes (%d)", bytes);
|
||||
LOGE("BufferReader::SkipBytes : Parse Failure: Not enough bytes (%d)",
|
||||
bytes);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,8 +57,9 @@ CdmResponseType CdmEngine::OpenSession(
|
||||
if (sts == NEED_PROVISIONING) {
|
||||
cert_provisioning_requested_security_level_ =
|
||||
new_session->GetRequestedSecurityLevel();
|
||||
} else {
|
||||
LOGE("CdmEngine::OpenSession: bad session init: %u", sts);
|
||||
}
|
||||
LOGE("CdmEngine::OpenSession: bad session init: %u", sts);
|
||||
return sts;
|
||||
}
|
||||
*session_id = new_session->session_id();
|
||||
@@ -278,7 +279,8 @@ CdmResponseType CdmEngine::CancelKeyRequest(const CdmSessionId& session_id) {
|
||||
|
||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||
if (iter == sessions_.end()) {
|
||||
LOGE("CdmEngine::CancelKeyRequest: session_id not found = %s", session_id.c_str());
|
||||
LOGE("CdmEngine::CancelKeyRequest: session_id not found = %s",
|
||||
session_id.c_str());
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
@@ -295,12 +297,13 @@ CdmResponseType CdmEngine::GenerateRenewalRequest(
|
||||
|
||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||
if (iter == sessions_.end()) {
|
||||
LOGE("CdmEngine::GenerateRenewalRequest: session_id not found = %s", session_id.c_str());
|
||||
LOGE("CdmEngine::GenerateRenewalRequest: session_id not found = %s",
|
||||
session_id.c_str());
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
if (!key_request) {
|
||||
LOGE("CdmEngine::GenerateRenewalRequest: no key request destination provided");
|
||||
LOGE("CdmEngine::GenerateRenewalRequest: no key request destination");
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
@@ -310,7 +313,7 @@ CdmResponseType CdmEngine::GenerateRenewalRequest(
|
||||
server_url);
|
||||
|
||||
if (KEY_MESSAGE != sts) {
|
||||
LOGE("CdmEngine::GenerateRenewalRequest: key request generation failed, sts=%d",
|
||||
LOGE("CdmEngine::GenerateRenewalRequest: key request gen. failed, sts=%d",
|
||||
(int)sts);
|
||||
return sts;
|
||||
}
|
||||
@@ -406,7 +409,8 @@ CdmResponseType CdmEngine::QueryKeyStatus(
|
||||
LOGI("CdmEngine::QueryKeyStatus");
|
||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||
if (iter == sessions_.end()) {
|
||||
LOGE("CdmEngine::QueryKeyStatus: session_id not found = %s", session_id.c_str());
|
||||
LOGE("CdmEngine::QueryKeyStatus: session_id not found = %s",
|
||||
session_id.c_str());
|
||||
return KEY_ERROR;
|
||||
}
|
||||
return iter->second->QueryKeyStatus(key_info);
|
||||
@@ -418,7 +422,8 @@ CdmResponseType CdmEngine::QueryKeyControlInfo(
|
||||
LOGI("CdmEngine::QueryKeyControlInfo");
|
||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||
if (iter == sessions_.end()) {
|
||||
LOGE("CdmEngine::QueryKeyControlInfo: session_id not found = %s", session_id.c_str());
|
||||
LOGE("CdmEngine::QueryKeyControlInfo: session_id not found = %s",
|
||||
session_id.c_str());
|
||||
return KEY_ERROR;
|
||||
}
|
||||
return iter->second->QueryKeyControlInfo(key_info);
|
||||
|
||||
@@ -9,7 +9,11 @@
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
namespace {
|
||||
const std::string kDefaultProvisioningServerUrl =
|
||||
|
||||
// URL for Google Provisioning Server.
|
||||
// This server supplies the certificate that is needed
|
||||
// to communicate with the License Server.
|
||||
const std::string kProvisioningServerUrl =
|
||||
"https://www.googleapis.com/"
|
||||
"certificateprovisioning/v1/devicecertificates/create"
|
||||
"?key=AIzaSyB-5OLKTx2iU5mko18DfdwK5611JIjbUhE";
|
||||
@@ -60,7 +64,12 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequest(
|
||||
const std::string& cert_authority,
|
||||
CdmProvisioningRequest* request,
|
||||
std::string* default_url) {
|
||||
default_url->assign(kDefaultProvisioningServerUrl);
|
||||
if (!default_url) {
|
||||
LOGE("GetProvisioningRequest: pointer for returning URL is NULL");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
default_url->assign(kProvisioningServerUrl);
|
||||
|
||||
CdmResponseType sts = crypto_session_.Open(requested_security_level);
|
||||
if (NO_ERROR != sts) {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include "crypto_session.h"
|
||||
|
||||
#include <arpa/inet.h> // TODO(fredgc): Add ntoh to wv_cdm_utilities.h
|
||||
#include <arpa/inet.h> // needed for ntoh()
|
||||
#include <iostream>
|
||||
|
||||
#include "crypto_key.h"
|
||||
|
||||
@@ -202,7 +202,6 @@ bool CdmLicense::PrepareKeyRequest(const InitializationData& init_data,
|
||||
return PrepareServiceCertificateRequest(signed_request, server_url);
|
||||
}
|
||||
|
||||
// TODO(gmorgan): Request ID owned by session?
|
||||
std::string request_id;
|
||||
session_->GenerateRequestId(request_id);
|
||||
|
||||
|
||||
@@ -4,20 +4,8 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Description:
|
||||
// Merges certificate_provisioning.proto and client_identification.proto
|
||||
// inline to avoid having to hardcode the import path. This is a temporary
|
||||
// workaround for not getting proto_path to work in Android build envionment.
|
||||
//
|
||||
// Origin:
|
||||
// This file is derived from the authoritative source file at
|
||||
// https://cs.corp.google.com/#google3/video/widevine/server/sdk/
|
||||
// license_protocol.proto
|
||||
//
|
||||
// Description:
|
||||
// Definitions of the protocol buffer messages used in the Widevine license
|
||||
// exchange protocol, which is described in the document
|
||||
// https://docs.google.com/a/google.com/document/d/
|
||||
// 1cng6cDnchbDQDymLEd5MxMc_laS3EDv6IsoW3IzpgwQ
|
||||
// exchange protocol.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
@@ -124,8 +112,6 @@ message License {
|
||||
}
|
||||
|
||||
message KeyControl {
|
||||
// |key_control| is documented here:
|
||||
// https://docs.google.com/a/google.com/document/d/17eDxzzGpPc2qSm7zW68_5ensuxbHErYCvD3IxSKETRo/edit#
|
||||
// If present, the key control must be communicated to the secure
|
||||
// environment prior to any usage. This message is automatically generated
|
||||
// by the Widevine License Server SDK.
|
||||
@@ -233,7 +219,6 @@ message LicenseRequest {
|
||||
optional EncryptedClientIdentification encrypted_client_id = 8;
|
||||
}
|
||||
|
||||
|
||||
message LicenseError {
|
||||
enum Error {
|
||||
// The device credentials are invalid. The device must re-provision.
|
||||
@@ -286,17 +271,14 @@ message SessionState {
|
||||
// certificate_provisioning.proto
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
// Author: tinskip@google.com (Thomas Inskip)
|
||||
//
|
||||
// Description:
|
||||
// Public protocol buffer definitions for Widevine Device Certificate
|
||||
// Provisioning protocol.
|
||||
|
||||
// PROPOSED message for customizing provisioning request.
|
||||
// This could support requesting specificy types of certificates.
|
||||
// E.g. Cast X.509 certs.
|
||||
// ProvisioningOptions specifies the type of certificate to specify and
|
||||
// in the case of X509 certificates, the certificate authority to use.
|
||||
message ProvisioningOptions {
|
||||
// PROPOSED enum identifying the certificate type.
|
||||
enum CertificateType {
|
||||
RSA_WIDEVINE = 0; // Default. The original certificate type.
|
||||
X509 = 1; // X.509 certificate.
|
||||
@@ -304,8 +286,8 @@ message ProvisioningOptions {
|
||||
|
||||
optional CertificateType certificate_type = 1;
|
||||
|
||||
// OPEN QUESTION: How does the client specify the cert root authority?
|
||||
// Should this be the cert authority's domain? E.g. foo.com?
|
||||
// It is recommended that the certificate_authority specify the X.509
|
||||
// Subject of the signing certificate.
|
||||
optional string certificate_authority = 2;
|
||||
}
|
||||
|
||||
@@ -320,10 +302,6 @@ message ProvisioningRequest {
|
||||
}
|
||||
|
||||
// Provisioning response sent by the provisioning server to client devices.
|
||||
//
|
||||
// PROPOSAL: The contents of this message vary depending upon the value of
|
||||
// CertificateType in options. TODO(blueeyes): Determine the right way to
|
||||
// transfer X.509 certs.
|
||||
message ProvisioningResponse {
|
||||
// AES-128 encrypted device private RSA key. PKCS#1 ASN.1 DER-encoded.
|
||||
// Required.
|
||||
@@ -349,12 +327,6 @@ message SignedProvisioningMessage {
|
||||
// client_identification.proto
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
// Author: tinskip@google.com (Thomas Inskip)
|
||||
//
|
||||
// Origin:
|
||||
// This file is derived from the authoritative source file at
|
||||
// https://cs.corp.google.com/#google3/video/widevine/server/sdk/
|
||||
// license_protocol.proto
|
||||
//
|
||||
// Description:
|
||||
// ClientIdentification messages used by provisioning and license protocols.
|
||||
@@ -388,8 +360,8 @@ message EncryptedClientIdentification {
|
||||
// Serial number for the service certificate for which ClientIdentification is
|
||||
// encrypted.
|
||||
optional string service_certificate_serial_number = 2;
|
||||
// Serialized ClientIdentification message, encrypted with the privacy key using
|
||||
// AES-128-CBC with PKCS#5 padding.
|
||||
// Serialized ClientIdentification message, encrypted with the privacy key
|
||||
// using AES-128-CBC with PKCS#5 padding.
|
||||
optional bytes encrypted_client_id = 3;
|
||||
// Initialization vector needed to decrypt encrypted_client_id.
|
||||
optional bytes encrypted_client_id_iv = 4;
|
||||
@@ -402,7 +374,6 @@ message EncryptedClientIdentification {
|
||||
// device_certificate.proto
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
// Author: tinskip@google.com (Thomas Inskip)
|
||||
//
|
||||
// Description:
|
||||
// Device certificate and certificate status list format definitions.
|
||||
@@ -452,8 +423,8 @@ message SignedDeviceCertificate {
|
||||
// Contains device model information for a provisioned device.
|
||||
message ProvisionedDeviceInfo {
|
||||
enum WvSecurityLevel {
|
||||
// Defined in Widevine Security Integration Guide for DASH on Android:
|
||||
// https://docs.google.com/a/google.com/document/d/1Zum-fcJeoIw6KG1kDP_KepIE5h9gAZg0PaMtemBvk9c/edit#heading=h.1t3h5sf
|
||||
// Defined in "WV Modular DRM Security Integration Guide for
|
||||
// Common Encryption (CENC)"
|
||||
LEVEL_UNSPECIFIED = 0;
|
||||
LEVEL_1 = 1;
|
||||
LEVEL_2 = 2;
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Wrapper of OEMCrypto APIs for platforms that support both Levels 1 and 3.
|
||||
* This should be used when liboemcrypto.so is dynamically loaded at run
|
||||
* time and not linked with the CDM code at compile time.
|
||||
* An implementation should compile either oemcrypto_adapter_dynamic.cpp or
|
||||
* oemcrypto_adapter_static.cpp, but not both.
|
||||
*
|
||||
******************************************************************************/
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Wrapper of OEMCrypto APIs for platforms that support both Levels 1 and 3.
|
||||
// This should be used when liboemcrypto.so is dynamically loaded at run
|
||||
// time and not linked with the CDM code at compile time.
|
||||
// An implementation should compile either oemcrypto_adapter_dynamic.cpp or
|
||||
// oemcrypto_adapter_static.cpp, but not both.
|
||||
//
|
||||
|
||||
#include "oemcrypto_adapter.h"
|
||||
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Wrapper of OEMCrypto APIs for platforms that support Level 1 only.
|
||||
* This should be used when liboemcrypto.so is linked with the CDM code at
|
||||
* compile time.
|
||||
* An implementation should compile either oemcrypto_adapter_dynamic.cpp or
|
||||
* oemcrypto_adapter_static.cpp, but not both.
|
||||
*
|
||||
******************************************************************************/
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Wrapper of OEMCrypto APIs for platforms that support Level 1 only.
|
||||
// This should be used when liboemcrypto.so is linked with the CDM code at
|
||||
// compile time.
|
||||
//
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "oemcrypto_adapter.h"
|
||||
|
||||
@@ -76,15 +76,15 @@ extern "C" OEMCryptoResult OEMCrypto_LoadKeys(
|
||||
const uint8_t* enc_mac_key_iv, const uint8_t* enc_mac_key, size_t num_keys,
|
||||
const OEMCrypto_KeyObject* key_array,
|
||||
const uint8_t* pst, size_t pst_length) {
|
||||
return LoadKeys_V8(pair.session, message, message_length, signature,
|
||||
signature_length, enc_mac_key_iv, enc_mac_key,
|
||||
num_keys, key_array);
|
||||
return OEMCrypto_LoadKeys_V8(session, message, message_length, signature,
|
||||
signature_length, enc_mac_key_iv, enc_mac_key,
|
||||
num_keys, key_array);
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_GenerateRSASignature(
|
||||
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
|
||||
uint8_t* signature, size_t* signature_length, RSA_Padding_Scheme padding_scheme) {
|
||||
return GenerateRSASignature_V8(pair.session, message, message_length,
|
||||
return OEMCrypto_GenerateRSASignature_V8(session, message, message_length,
|
||||
signature, signature_length);
|
||||
}
|
||||
|
||||
|
||||
@@ -127,10 +127,6 @@ void PolicyEngine::UpdateLicense(
|
||||
return;
|
||||
}
|
||||
else {
|
||||
// TODO(edwingwong, rfrias): Check back with Thomas and see if
|
||||
// we need to enforce that all duration windows are absent if
|
||||
// license_start_time is not present. This is a TBD.
|
||||
|
||||
// if renewal, discard license if version has not been updated
|
||||
if (license.id().version() > license_id_.version())
|
||||
license_id_.CopyFrom(license.id());
|
||||
@@ -140,9 +136,6 @@ void PolicyEngine::UpdateLicense(
|
||||
|
||||
// Update time information
|
||||
int64_t current_time = clock_->GetCurrentTime();
|
||||
// TODO(edwingwong, rfrias): Check back with Thomas and see if
|
||||
// we need to enforce that all duration windows are absent if
|
||||
// license_start_time is not present. This is a TBD.
|
||||
if (license.has_license_start_time())
|
||||
license_start_time_ = license.license_start_time();
|
||||
license_received_time_ = current_time;
|
||||
@@ -276,10 +269,9 @@ bool PolicyEngine::IsRenewalDelayExpired(int64_t current_time) {
|
||||
current_time;
|
||||
}
|
||||
|
||||
// TODO(jfore, edwinwong, rfrias): This field is in flux and currently
|
||||
// not implemented. Will address after possible updates from Thomas.
|
||||
bool PolicyEngine::IsRenewalRecoveryDurationExpired(
|
||||
int64_t current_time) {
|
||||
// NOTE: Renewal Recovery Duration is currently not used.
|
||||
return (policy_.renewal_recovery_duration_seconds() > 0) &&
|
||||
license_received_time_ + policy_.renewal_recovery_duration_seconds() <=
|
||||
current_time;
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Original code at //depot/google3/video/widevine/common/rsa_key.cc by
|
||||
// tinskip@google.com. Modified for core CDM usage.
|
||||
//
|
||||
// Description:
|
||||
// Definition of classes representing RSA public keys used
|
||||
// for signature verification and encryption and decryption.
|
||||
|
||||
@@ -75,10 +75,10 @@ std::string b2a_hex(const std::string& byte) {
|
||||
byte.length());
|
||||
}
|
||||
|
||||
// Filename-friendly base64 encoding (RFC4648), commonly referred as
|
||||
// Base64WebSafeEncode.
|
||||
// This is the encoding required by GooglePlay to interface with the
|
||||
// provisioning server's Apiary interface as well as for certain license server
|
||||
// Filename-friendly base64 encoding (RFC4648), commonly referred to
|
||||
// as Base64WebSafeEncode.
|
||||
// This is the encoding required to interface with the provisioning
|
||||
// server's Apiary interface as well as for certain license server
|
||||
// transactions. It is also used for logging certain strings.
|
||||
// The difference between web safe encoding vs regular encoding is that
|
||||
// the web safe version replaces '+' with '-' and '/' with '_'.
|
||||
|
||||
@@ -1,861 +0,0 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
|
||||
#include "base/at_exit.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/message_loop.h"
|
||||
#include "base/sys_byteorder.h"
|
||||
#include "crypto/encryptor.h"
|
||||
#include "crypto/hmac.h"
|
||||
#include "crypto/symmetric_key.h"
|
||||
#include "license_protocol.pb.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "eureka/widevine_cdm/oemcrypto/client/oemcrypto_client.h"
|
||||
#include "eureka/widevine_cdm/oemcrypto/mock/src/cmac.h"
|
||||
#include "eureka/widevine_cdm/oemcrypto/mock/src/oemcrypto_keybox_mock.h"
|
||||
#include "wv_cdm_types.h"
|
||||
#include "wv_content_decryption_module.h"
|
||||
|
||||
namespace {
|
||||
|
||||
namespace wv_license_protocol = video_widevine_server::sdk;
|
||||
|
||||
using wv_license_protocol::License;
|
||||
using wv_license_protocol::LicenseIdentification;
|
||||
using wv_license_protocol::LicenseRequest;
|
||||
using wv_license_protocol::SessionState;
|
||||
using wv_license_protocol::SignedMessage;
|
||||
|
||||
enum PolicyType {
|
||||
kDefault = 0,
|
||||
kNoPlay,
|
||||
kShortDuration
|
||||
};
|
||||
|
||||
struct PolicyItem {
|
||||
PolicyType type;
|
||||
bool can_play;
|
||||
bool can_renew;
|
||||
int duration_seconds;
|
||||
int renewal_delay_seconds;
|
||||
int renewal_retry_interval_seconds;
|
||||
};
|
||||
|
||||
struct PolicyItem PolicyItems[] = {
|
||||
{
|
||||
kDefault,
|
||||
true,
|
||||
true,
|
||||
1000,
|
||||
100,
|
||||
0
|
||||
},
|
||||
{
|
||||
kShortDuration,
|
||||
true,
|
||||
true,
|
||||
12,
|
||||
2,
|
||||
2
|
||||
},
|
||||
{
|
||||
kNoPlay,
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
}
|
||||
};
|
||||
|
||||
// TODO(jfore): Move this into the test class.
|
||||
/*const*/ char kTestSigningKey[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
|
||||
};
|
||||
const int kTestSigningKeySize = arraysize(kTestSigningKey);
|
||||
|
||||
const char* kEncryptionKeyLabel = "ENCRYPTION";
|
||||
const uint32_t kEncryptionKeySizeBits = 128;
|
||||
const char* kSigningKeyLabel = "AUTHENTICATION";
|
||||
const uint32_t kSigningKeySizeBits = 256;
|
||||
|
||||
// This is a container to hold the info for an encrypted frame.
|
||||
struct WvCdmEncryptedFrameInfo {
|
||||
char plain_text[32];
|
||||
int plain_text_size;
|
||||
uint8_t key_id[32];
|
||||
int key_id_size;
|
||||
uint8_t content_key[32];
|
||||
int content_key_size;
|
||||
uint8_t encrypted_data[64];
|
||||
int encrypted_data_size;
|
||||
PolicyType policy_type;
|
||||
};
|
||||
|
||||
const WvCdmEncryptedFrameInfo kWvCdmEncryptedFrames[] = {
|
||||
{
|
||||
"Original data.", 14,
|
||||
{ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35
|
||||
}, 16,
|
||||
{ 0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
|
||||
0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c
|
||||
}, 16,
|
||||
{ 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0x82, 0x54, 0xab, 0x89, 0xa2, 0x75, 0xcd,
|
||||
0x85, 0x83, 0x61, 0x3f, 0xfe, 0x13, 0x58
|
||||
}, 23,
|
||||
kShortDuration
|
||||
},
|
||||
{
|
||||
"Original data.", 14,
|
||||
{ 0x08, 0x01, 0x12, 0x10, 0x6f, 0x13, 0x33, 0xe7,
|
||||
0x6e, 0x59, 0x5e, 0xb5, 0x8c, 0x04, 0x30, 0x72,
|
||||
0xcb, 0xb2, 0x50, 0x68
|
||||
}, 20,
|
||||
{ 0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
|
||||
0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c
|
||||
}, 16,
|
||||
{ 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0x82, 0x54, 0xab, 0x89, 0xa2, 0x75, 0xcd,
|
||||
0x85, 0x83, 0x61, 0x3f, 0xfe, 0x13, 0x58
|
||||
}, 23,
|
||||
kShortDuration
|
||||
},
|
||||
{
|
||||
"Changed Original data.", 22,
|
||||
{ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
|
||||
0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02
|
||||
}, 16,
|
||||
{ 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
|
||||
0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23
|
||||
}, 16,
|
||||
{ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x57, 0x66, 0xf4, 0x12, 0x1a, 0xed, 0xb5,
|
||||
0x79, 0x1c, 0x8e, 0x25, 0xd7, 0x17, 0xe7, 0x5e,
|
||||
0x16, 0xe3, 0x40, 0x08, 0x27, 0x11, 0xe9
|
||||
}, 31,
|
||||
kShortDuration
|
||||
},
|
||||
{
|
||||
"Original data.", 14,
|
||||
{ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
||||
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
|
||||
}, 16,
|
||||
{ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
|
||||
0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40
|
||||
}, 16,
|
||||
{ 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x9c, 0x71, 0x26, 0x57, 0x3e, 0x25, 0x37,
|
||||
0xf7, 0x31, 0x81, 0x19, 0x64, 0xce, 0xbc
|
||||
}, 23,
|
||||
kShortDuration
|
||||
},
|
||||
// For license renewal test. This has kNoPlay.
|
||||
{
|
||||
// Differnent key and key id.
|
||||
"Original data.", 14,
|
||||
{ 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
|
||||
0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33
|
||||
}, 16,
|
||||
{ 0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
|
||||
0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c
|
||||
}, 16,
|
||||
{ 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0x82, 0x54, 0xab, 0x89, 0xa2, 0x75, 0xcd,
|
||||
0x85, 0x83, 0x61, 0x3f, 0xfe, 0x13, 0x58
|
||||
}, 23,
|
||||
kNoPlay
|
||||
}
|
||||
};
|
||||
|
||||
bool GetPolicy(PolicyType policy_type, License::Policy* policy) {
|
||||
DCHECK(policy);
|
||||
PolicyItem policy_item;
|
||||
switch (policy_type) {
|
||||
case kDefault:
|
||||
policy_item = PolicyItems[0];
|
||||
DCHECK_EQ(policy_item.type, kDefault);
|
||||
break;
|
||||
case kShortDuration:
|
||||
policy_item = PolicyItems[1];
|
||||
DCHECK_EQ(policy_item.type, kShortDuration);
|
||||
break;
|
||||
case kNoPlay:
|
||||
policy_item = PolicyItems[2];
|
||||
DCHECK_EQ(policy_item.type, kNoPlay);
|
||||
break;
|
||||
default:
|
||||
NOTREACHED();
|
||||
return false;
|
||||
}
|
||||
policy->set_can_play(policy_item.can_play);
|
||||
policy->set_can_renew(policy_item.can_renew);
|
||||
policy->set_license_duration_seconds(policy_item.duration_seconds);
|
||||
policy->set_renewal_delay_seconds(policy_item.renewal_delay_seconds);
|
||||
policy->set_renewal_retry_interval_seconds(
|
||||
policy_item.renewal_retry_interval_seconds);
|
||||
return true;
|
||||
}
|
||||
|
||||
SessionState GetTestSessionState() {
|
||||
static const std::string kTestSessionId = "SomeSessionId";
|
||||
SessionState session_cache;
|
||||
session_cache.mutable_license_id()->set_session_id(kTestSessionId);
|
||||
session_cache.mutable_license_id()->set_version(0);
|
||||
session_cache.set_signing_key(kTestSigningKey, kTestSigningKeySize);
|
||||
return session_cache;
|
||||
}
|
||||
|
||||
// Since "GetTime" is used in this test where some functions cannot reach
|
||||
// Host instance, this will be used as a universal clock for this test.
|
||||
double GetCurrentTestTime() {
|
||||
return base::Time::Now().ToDoubleT();
|
||||
}
|
||||
|
||||
// This encrypts the content key using the device key in cdm/base/device_key.h.
|
||||
std::string EncryptUsingKey(const std::string& input,
|
||||
const std::string& iv,
|
||||
const std::string& encryption_key) {
|
||||
//static const int kAesBlockSize = 16;
|
||||
crypto::Encryptor aes_ecryptor;
|
||||
scoped_ptr<crypto::SymmetricKey> device_key(
|
||||
crypto::SymmetricKey::Import(crypto::SymmetricKey::AES,
|
||||
encryption_key));
|
||||
if (!aes_ecryptor.Init(device_key.get(), crypto::Encryptor::CBC, iv))
|
||||
return "";
|
||||
|
||||
std::string encrypted_data;
|
||||
if (!aes_ecryptor.Encrypt(input, &encrypted_data))
|
||||
return "";
|
||||
|
||||
return encrypted_data;
|
||||
}
|
||||
|
||||
// Takes the license and the session state and generates a SignedMessage. The
|
||||
// return value is the serialized version of the SignedMessage object.
|
||||
std::string GenerateSignedLicenseResponse(const License& license,
|
||||
const std::string& signing_key) {
|
||||
SignedMessage signed_message;
|
||||
bool success = license.SerializeToString(
|
||||
signed_message.mutable_msg());
|
||||
DCHECK(success);
|
||||
|
||||
crypto::HMAC hmacer(crypto::HMAC::SHA256);
|
||||
if (!hmacer.Init(signing_key))
|
||||
return "";
|
||||
|
||||
static const int kDigestSize = 32;
|
||||
uint8_t digest[kDigestSize] = { 0 };
|
||||
if (!hmacer.Sign(signed_message.msg(), digest, kDigestSize))
|
||||
return "";
|
||||
|
||||
signed_message.set_signature(digest, kDigestSize);
|
||||
|
||||
std::string signed_message_bytes;
|
||||
success = signed_message.SerializeToString(&signed_message_bytes);
|
||||
DCHECK(success);
|
||||
|
||||
return signed_message_bytes;
|
||||
}
|
||||
|
||||
// Note: We only use one session. So there aren't any list of sessions stored
|
||||
// anywhere.
|
||||
std::string GenerateNewSignedLicense(
|
||||
const LicenseRequest& license_request,
|
||||
const License::Policy& policies,
|
||||
const License::KeyContainer& content_key,
|
||||
const std::string& encryption_key,
|
||||
const std::string& signing_key) {
|
||||
DCHECK(license_request.content_id().has_cenc_id());
|
||||
SessionState session_cache = GetTestSessionState();
|
||||
DCHECK(session_cache.has_signing_key());
|
||||
|
||||
session_cache.mutable_license_id()->set_request_id(
|
||||
license_request.content_id().webm_id().request_id());
|
||||
session_cache.mutable_license_id()->set_type(
|
||||
license_request.content_id().webm_id().license_type());
|
||||
|
||||
License license;
|
||||
license.mutable_id()->CopyFrom(session_cache.license_id());
|
||||
license.mutable_policy()->CopyFrom(policies);
|
||||
license.set_license_start_time(GetCurrentTestTime());
|
||||
|
||||
License::KeyContainer* renewal_signing_key = license.add_key();
|
||||
renewal_signing_key->set_key(session_cache.signing_key());
|
||||
renewal_signing_key->set_type(License::KeyContainer::SIGNING);
|
||||
|
||||
license.add_key()->CopyFrom(content_key);
|
||||
for (int i = 0; i < license.key_size(); ++i) {
|
||||
license.mutable_key(i)->set_iv("0123456789012345");
|
||||
license.mutable_key(i)->set_key(
|
||||
EncryptUsingKey(license.key(i).key(),
|
||||
license.key(i).iv(),
|
||||
encryption_key));
|
||||
if (license.key(i).key().empty())
|
||||
return "";
|
||||
}
|
||||
|
||||
return GenerateSignedLicenseResponse(license, signing_key);
|
||||
}
|
||||
|
||||
bool GetContentKeyFromKeyId(const std::string& key_id,
|
||||
std::string* content_key) {
|
||||
DCHECK(content_key);
|
||||
for (unsigned int i = 0; i < arraysize(kWvCdmEncryptedFrames); ++i) {
|
||||
const WvCdmEncryptedFrameInfo& frame = kWvCdmEncryptedFrames[i];
|
||||
if (frame.key_id_size != static_cast<int>(key_id.size()))
|
||||
continue;
|
||||
if (!memcmp(frame.key_id, key_id.data(), frame.key_id_size)) {
|
||||
content_key->assign(frame.content_key,
|
||||
frame.content_key + frame.content_key_size);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string DeriveKey(const std::string& key,
|
||||
const std::string& purpose,
|
||||
const std::string& context,
|
||||
const uint32_t size_bits) {
|
||||
if (key.size() != 16)
|
||||
return "";
|
||||
|
||||
// We only handle even multiples of 16 bytes (128 bits) right now.
|
||||
if ((size_bits % 128) || (size_bits > (128 * 255))) {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string result;
|
||||
|
||||
const EVP_CIPHER *cipher = EVP_aes_128_cbc();
|
||||
CMAC_CTX* cmac_ctx = CMAC_CTX_new();
|
||||
|
||||
size_t reslen;
|
||||
unsigned char res[128];
|
||||
unsigned char counter;
|
||||
for (counter = 1; counter <= (size_bits / 128); counter++) {
|
||||
if (!CMAC_Init(cmac_ctx, key.data(), key.size(), cipher, 0))
|
||||
break;
|
||||
|
||||
std::string message;
|
||||
message.append(1, counter);
|
||||
message.append(purpose);
|
||||
message.append(1, '\0');
|
||||
message.append(context);
|
||||
uint32_t size_l = htonl(size_bits);
|
||||
message.append(reinterpret_cast<char*>(&size_l), sizeof(size_l));
|
||||
if (!CMAC_Update(cmac_ctx, message.data(), message.size()))
|
||||
break;
|
||||
|
||||
if (!CMAC_Final(cmac_ctx, res, &reslen))
|
||||
break;
|
||||
|
||||
result.append((const char*)res, reslen);
|
||||
}
|
||||
|
||||
CMAC_CTX_free(cmac_ctx);
|
||||
|
||||
if (counter <= (size_bits / 128))
|
||||
return "";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool VerifyTestSignature(const std::string& message,
|
||||
const std::string& signature,
|
||||
const std::string& key) {
|
||||
crypto::HMAC hmacer(crypto::HMAC::SHA256);
|
||||
if (!hmacer.Init(key))
|
||||
return false;
|
||||
|
||||
if (!hmacer.Verify(message, signature))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string GenerateNewLicenseResponse(const LicenseRequest& license_request,
|
||||
const PolicyType& policy_type) {
|
||||
if (!license_request.content_id().has_cenc_id())
|
||||
return "";
|
||||
|
||||
std::string content_key_id = license_request.content_id().cenc_id().pssh(0);
|
||||
|
||||
std::string content_key;
|
||||
if (!GetContentKeyFromKeyId(content_key_id,
|
||||
&content_key)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (content_key_id.size() > 16)
|
||||
content_key_id.resize(16);
|
||||
|
||||
License::Policy policies;
|
||||
if (!GetPolicy(policy_type, &policies))
|
||||
return "";
|
||||
|
||||
std::string context;
|
||||
if (!license_request.SerializeToString(&context))
|
||||
return "";
|
||||
|
||||
wvoec_mock::WvKeybox keybox;
|
||||
|
||||
// TODO(): Fix this to use a constant for key length.
|
||||
std::string widevine_device_key(keybox.device_key().value());
|
||||
std::string encryption_key = DeriveKey(widevine_device_key,
|
||||
std::string(kEncryptionKeyLabel),
|
||||
context,
|
||||
kEncryptionKeySizeBits);
|
||||
std::string signing_key = DeriveKey(widevine_device_key,
|
||||
std::string(kSigningKeyLabel),
|
||||
context,
|
||||
kSigningKeySizeBits);
|
||||
|
||||
memcpy(kTestSigningKey, &signing_key[0], 32);
|
||||
|
||||
License::KeyContainer key_container;
|
||||
key_container.set_id(content_key_id);
|
||||
key_container.set_key(content_key);
|
||||
key_container.set_type(License::KeyContainer::CONTENT);
|
||||
return GenerateNewSignedLicense(license_request,
|
||||
policies,
|
||||
key_container,
|
||||
encryption_key,
|
||||
signing_key);
|
||||
}
|
||||
|
||||
std::string GenerateLicenseRenewalResponse(
|
||||
const SignedMessage& signed_message,
|
||||
const PolicyType& policy_type) {
|
||||
SessionState session_cache = GetTestSessionState();
|
||||
|
||||
LicenseRequest license_request;
|
||||
if (!license_request.ParseFromString(signed_message.msg()))
|
||||
return "";
|
||||
|
||||
std::string session_id = license_request.content_id().license().
|
||||
license_id().session_id();
|
||||
if (session_id.compare(session_cache.license_id().session_id()))
|
||||
return "";
|
||||
|
||||
if (!VerifyTestSignature(signed_message.msg(),
|
||||
signed_message.signature(),
|
||||
session_cache.signing_key())) {
|
||||
return "";
|
||||
}
|
||||
session_cache.mutable_license_id()->set_version(
|
||||
session_cache.license_id().version() + 1);
|
||||
|
||||
License license;
|
||||
license.mutable_id()->CopyFrom(session_cache.license_id());
|
||||
|
||||
// Always get Policy object with kDefault for renewal.
|
||||
License::Policy policy;
|
||||
GetPolicy(policy_type, &policy);
|
||||
license.mutable_policy()->Swap(&policy);
|
||||
license.set_license_start_time(GetCurrentTestTime());
|
||||
|
||||
return GenerateSignedLicenseResponse(license, session_cache.signing_key());
|
||||
}
|
||||
|
||||
std::string GenerateLicenseResponse(const std::string& signed_request,
|
||||
const PolicyType& policy) {
|
||||
SignedMessage signed_message;
|
||||
if (!signed_message.ParseFromString(signed_request))
|
||||
return "";
|
||||
|
||||
LicenseRequest license_request;
|
||||
if (!license_request.ParseFromString(signed_message.msg()))
|
||||
return "";
|
||||
|
||||
if (license_request.type() == LicenseRequest::NEW) {
|
||||
return GenerateNewLicenseResponse(license_request, policy);
|
||||
} else if (license_request.type() == LicenseRequest::RENEWAL) {
|
||||
return GenerateLicenseRenewalResponse(signed_message, policy);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
struct WvCdmEncryptedData {
|
||||
char plain_text[32];
|
||||
int plain_text_size;
|
||||
uint8_t key_id[32];
|
||||
int key_id_size;
|
||||
uint8_t content_key[32];
|
||||
int content_key_size;
|
||||
uint8_t encrypted_data[64];
|
||||
int encrypted_data_size;
|
||||
const char* license_response;
|
||||
int license_response_size;
|
||||
};
|
||||
|
||||
// Container used to pass data from GenerateLicenseRequest to Decrypt.
|
||||
// TODO(rkuroiwa): This class was made before KeyMessage existed; this
|
||||
// should be removed.
|
||||
class LicenseRequestParameter {
|
||||
public:
|
||||
explicit LicenseRequestParameter(const WvCdmEncryptedData& frame)
|
||||
: init_data(new uint8_t[frame.key_id_size]),
|
||||
init_data_size(frame.key_id_size),
|
||||
session_id(NULL),
|
||||
session_id_size(0),
|
||||
key_request(NULL),
|
||||
key_request_size(0),
|
||||
default_url(NULL),
|
||||
default_url_size(0) {
|
||||
memcpy(init_data.get(), frame.key_id, frame.key_id_size);
|
||||
}
|
||||
|
||||
~LicenseRequestParameter() {
|
||||
}
|
||||
|
||||
scoped_array<uint8_t> init_data;
|
||||
int init_data_size;
|
||||
scoped_array<char> session_id;
|
||||
int session_id_size;
|
||||
scoped_array<uint8_t> key_request;
|
||||
int key_request_size;
|
||||
scoped_array<char> default_url;
|
||||
int default_url_size;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(LicenseRequestParameter);
|
||||
};
|
||||
|
||||
// |encrypted_data| is encrypted from |plain_text| using |key|. |key_id| is
|
||||
// used to distinguish |key|.
|
||||
struct WebmEncryptedData {
|
||||
uint8 plain_text[32];
|
||||
int plain_text_size;
|
||||
uint8 key_id[32];
|
||||
int key_id_size;
|
||||
uint8 key[32];
|
||||
int key_size;
|
||||
uint8 encrypted_data[64];
|
||||
int encrypted_data_size;
|
||||
};
|
||||
|
||||
// Frames 0 & 1 are encrypted with the same key. Frame 2 is encrypted with a
|
||||
// different key. Frame 3 is unencrypted.
|
||||
const WebmEncryptedData kWebmEncryptedFrames[] = {
|
||||
{
|
||||
// plaintext
|
||||
"Original data.", 14,
|
||||
// key_id
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13
|
||||
}, 20,
|
||||
// key
|
||||
{ 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
|
||||
0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23
|
||||
}, 16,
|
||||
// encrypted_data
|
||||
{ 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xf0, 0xd1, 0x12, 0xd5, 0x24, 0x81, 0x96,
|
||||
0x55, 0x1b, 0x68, 0x9f, 0x38, 0x91, 0x85
|
||||
}, 23
|
||||
},
|
||||
{
|
||||
// plaintext
|
||||
"Changed Original data.", 22,
|
||||
// key_id
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13
|
||||
}, 20,
|
||||
// key
|
||||
{ 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
|
||||
0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23
|
||||
}, 16,
|
||||
// encrypted_data
|
||||
{ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x57, 0x66, 0xf4, 0x12, 0x1a, 0xed, 0xb5,
|
||||
0x79, 0x1c, 0x8e, 0x25, 0xd7, 0x17, 0xe7, 0x5e,
|
||||
0x16, 0xe3, 0x40, 0x08, 0x27, 0x11, 0xe9
|
||||
}, 31
|
||||
},
|
||||
{
|
||||
// plaintext
|
||||
"Original data.", 14,
|
||||
// key_id
|
||||
{ 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
|
||||
0x2c, 0x2d, 0x2e, 0x2f, 0x30
|
||||
}, 13,
|
||||
// key
|
||||
{ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
|
||||
0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40
|
||||
}, 16,
|
||||
// encrypted_data
|
||||
{ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x9c, 0x71, 0x26, 0x57, 0x3e, 0x25, 0x37,
|
||||
0xf7, 0x31, 0x81, 0x19, 0x64, 0xce, 0xbc
|
||||
}, 23
|
||||
},
|
||||
{
|
||||
// plaintext
|
||||
"Changed Original data.", 22,
|
||||
// key_id
|
||||
{ 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
|
||||
0x2c, 0x2d, 0x2e, 0x2f, 0x30
|
||||
}, 13,
|
||||
// key
|
||||
{ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
|
||||
0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40
|
||||
}, 16,
|
||||
// encrypted_data
|
||||
{ 0x00, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64,
|
||||
0x20, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61,
|
||||
0x6c, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2e
|
||||
}, 23
|
||||
}
|
||||
};
|
||||
|
||||
static const uint8 kWebmWrongSizedKey[] = { 0x20, 0x20 };
|
||||
|
||||
static const char kClearKeySystem[] = "org.w3.clearkey";
|
||||
static const char *kWidevineKeySystem = "com.widevine.alpha";
|
||||
static const char kKeyType[] = "any";
|
||||
|
||||
// All three ContentIdentification are supported but cenc_id only supports
|
||||
// one key for now.
|
||||
// Using key_id kCencTestRequest will return the content_key kCencTestRequest
|
||||
//
|
||||
static const char kCencTestRequest[] = "0123456789ABCDEF";
|
||||
static const char kCencTestContentKey[] = {
|
||||
0x16, 0x23, 0xa3, 0x16, 0x67, 0x6d, 0xb7, 0x70,
|
||||
0xfe, 0x78, 0xf6, 0x58, 0x42, 0xb8, 0x16, 0x3c
|
||||
};
|
||||
|
||||
// System Id of the Widevine DRM system for identification in pssh
|
||||
static const uint8 kWidevineSystemId[] = {
|
||||
0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE,
|
||||
0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED,
|
||||
};
|
||||
|
||||
static std::string EncodeInt32(int i) {
|
||||
std::string s;
|
||||
s.resize(sizeof(int));
|
||||
memcpy(&*s.begin(), &i, sizeof(int));
|
||||
return s;
|
||||
}
|
||||
|
||||
// Generate PSSH blob from init data
|
||||
static std::string GeneratePSSHBlob(const uint8* init_data,
|
||||
int init_data_length) {
|
||||
std::string output;
|
||||
|
||||
// 4 byte size of the PSSH atom, inclusive
|
||||
int size = 4 + 4 + 4 + sizeof(kWidevineSystemId) + 4 + init_data_length;
|
||||
output.append(EncodeInt32(base::HostToNet32(size)));
|
||||
|
||||
// "pssh"
|
||||
output.append("pssh");
|
||||
|
||||
// 4 byte flags, value 0
|
||||
int flag = 0;
|
||||
output.append(EncodeInt32(base::HostToNet32(flag)));
|
||||
|
||||
// 16 byte system id
|
||||
output.append(reinterpret_cast<const char*>(kWidevineSystemId),
|
||||
sizeof(kWidevineSystemId));
|
||||
|
||||
// 4 byte size of PSSH data, exclusive
|
||||
output.append(EncodeInt32(base::HostToNet32(init_data_length)));
|
||||
|
||||
// pssh data
|
||||
output.append(reinterpret_cast<const char*>(init_data),
|
||||
init_data_length);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
}; // anonymous
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
class WvCdmDecryptorTest : public testing::Test {
|
||||
|
||||
public:
|
||||
WvCdmDecryptorTest() {}
|
||||
|
||||
~WvCdmDecryptorTest() {}
|
||||
|
||||
protected:
|
||||
void GenerateKeyRequest(const uint8* key_id, int key_id_size,
|
||||
std::string& message_buffer) {
|
||||
std::string init_data = GeneratePSSHBlob(key_id, key_id_size);
|
||||
wvcdm::CdmResponseType res = decryptor_.GenerateKeyRequest(
|
||||
kWidevineKeySystem, init_data, &message_buffer, &session_id_string_);
|
||||
EXPECT_TRUE(res == wvcdm::KEY_MESSAGE);
|
||||
}
|
||||
|
||||
void PrepareForRenewalRequest(int i) {
|
||||
}
|
||||
|
||||
void GetRenewalMessage(std::string& message_buffer) {
|
||||
}
|
||||
|
||||
void GetFailedRenewalMessage(std::string& message_buffer) {
|
||||
}
|
||||
|
||||
public:
|
||||
void AddKeyAndExpectToSucceed(const uint8* key_id, int key_id_size,
|
||||
const uint8* key, int key_size) {
|
||||
std::string cma_key((const char*)key, key_size);
|
||||
std::string init_data = GeneratePSSHBlob(key_id, key_id_size);
|
||||
wvcdm::CdmResponseType res = decryptor_.AddKey(
|
||||
kWidevineKeySystem, init_data, cma_key, session_id_string_);
|
||||
EXPECT_TRUE(res == wvcdm::KEY_ADDED);
|
||||
}
|
||||
|
||||
void AddKeyAndExpectToFail(const uint8* key_id, int key_id_size,
|
||||
const uint8* key, int key_size) {
|
||||
std::string cma_key((const char*)key, key_size);
|
||||
std::string init_data = GeneratePSSHBlob(key_id, key_id_size);
|
||||
wvcdm::CdmResponseType res = decryptor_.AddKey(
|
||||
kWidevineKeySystem, init_data, cma_key, session_id_string_);
|
||||
EXPECT_TRUE(res == wvcdm::KEY_ADDED);
|
||||
}
|
||||
protected:
|
||||
|
||||
wvcdm::WvContentDecryptionModule decryptor_;
|
||||
std::string session_id_string_;
|
||||
};
|
||||
|
||||
TEST_F(WvCdmDecryptorTest, RenewalTest) {
|
||||
std::string response;
|
||||
std::string message;
|
||||
const WvCdmEncryptedFrameInfo& frame = kWvCdmEncryptedFrames[3];
|
||||
License::Policy policies;
|
||||
DCHECK(GetPolicy(frame.policy_type, &policies));
|
||||
|
||||
GenerateKeyRequest(frame.key_id, frame.key_id_size, message);
|
||||
response = GenerateLicenseResponse(message, kShortDuration);
|
||||
AddKeyAndExpectToSucceed(frame.key_id, frame.key_id_size,
|
||||
reinterpret_cast<const uint8*>(response.data()),
|
||||
response.size());
|
||||
MessageLoop::current()->RunUntilIdle();
|
||||
PrepareForRenewalRequest(1);
|
||||
sleep(policies.renewal_delay_seconds());
|
||||
MessageLoop::current()->RunUntilIdle();
|
||||
GetRenewalMessage(message);
|
||||
response = GenerateLicenseResponse(message, frame.policy_type);
|
||||
AddKeyAndExpectToSucceed(frame.key_id, frame.key_id_size,
|
||||
reinterpret_cast<const uint8*>(response.data()),
|
||||
response.size());
|
||||
}
|
||||
|
||||
TEST_F(WvCdmDecryptorTest, MultiRenewalTest) {
|
||||
std::string response;
|
||||
std::string message;
|
||||
const WvCdmEncryptedFrameInfo& frame = kWvCdmEncryptedFrames[3];
|
||||
License::Policy policies;
|
||||
DCHECK(GetPolicy(frame.policy_type, &policies));
|
||||
|
||||
GenerateKeyRequest(frame.key_id, frame.key_id_size, message);
|
||||
response = GenerateLicenseResponse(message, kShortDuration);
|
||||
AddKeyAndExpectToSucceed(frame.key_id, frame.key_id_size,
|
||||
reinterpret_cast<const uint8*>(response.data()),
|
||||
response.size());
|
||||
MessageLoop::current()->RunUntilIdle();
|
||||
PrepareForRenewalRequest(1);
|
||||
sleep(policies.renewal_delay_seconds());
|
||||
MessageLoop::current()->RunUntilIdle();
|
||||
GetRenewalMessage(message);
|
||||
response = GenerateLicenseResponse(message, frame.policy_type);
|
||||
AddKeyAndExpectToSucceed(frame.key_id, frame.key_id_size,
|
||||
reinterpret_cast<const uint8*>(response.data()),
|
||||
response.size());
|
||||
|
||||
PrepareForRenewalRequest(2);
|
||||
sleep(policies.renewal_delay_seconds());
|
||||
MessageLoop::current()->RunUntilIdle();
|
||||
GetRenewalMessage(message);
|
||||
}
|
||||
|
||||
TEST_F(WvCdmDecryptorTest, RenewalRetryTest_ExpectSuccess) {
|
||||
std::string response;
|
||||
std::string message;
|
||||
const WvCdmEncryptedFrameInfo& frame = kWvCdmEncryptedFrames[3];
|
||||
License::Policy policies;
|
||||
DCHECK(GetPolicy(frame.policy_type, &policies));
|
||||
|
||||
GenerateKeyRequest(frame.key_id, frame.key_id_size, message);
|
||||
response = GenerateLicenseResponse(message, kShortDuration);
|
||||
AddKeyAndExpectToSucceed(frame.key_id, frame.key_id_size,
|
||||
reinterpret_cast<const uint8*>(response.data()),
|
||||
response.size());
|
||||
MessageLoop::current()->RunUntilIdle();
|
||||
|
||||
int loop_seconds =
|
||||
policies.license_duration_seconds() - policies.renewal_delay_seconds();
|
||||
int loop_count = loop_seconds / policies.renewal_retry_interval_seconds();
|
||||
if (loop_seconds % policies.renewal_retry_interval_seconds())
|
||||
++loop_count;
|
||||
for (int i = 1; i <= loop_count; ++i) {
|
||||
PrepareForRenewalRequest(i);
|
||||
sleep(policies.renewal_delay_seconds());
|
||||
MessageLoop::current()->RunUntilIdle();
|
||||
GetRenewalMessage(message);
|
||||
}
|
||||
|
||||
response = GenerateLicenseResponse(message, frame.policy_type);
|
||||
AddKeyAndExpectToSucceed(frame.key_id, frame.key_id_size,
|
||||
reinterpret_cast<const uint8*>(response.data()),
|
||||
response.size());
|
||||
}
|
||||
|
||||
TEST_F(WvCdmDecryptorTest, RenewalRetryTest_ExpectLicenseExpiration) {
|
||||
std::string response;
|
||||
std::string message;
|
||||
const WvCdmEncryptedFrameInfo& frame = kWvCdmEncryptedFrames[3];
|
||||
License::Policy policies;
|
||||
DCHECK(GetPolicy(frame.policy_type, &policies));
|
||||
|
||||
GenerateKeyRequest(frame.key_id, frame.key_id_size, message);
|
||||
response = GenerateLicenseResponse(message, kShortDuration);
|
||||
AddKeyAndExpectToSucceed(frame.key_id, frame.key_id_size,
|
||||
reinterpret_cast<const uint8*>(response.data()),
|
||||
response.size());
|
||||
MessageLoop::current()->RunUntilIdle();
|
||||
|
||||
int loop_seconds =
|
||||
policies.license_duration_seconds() - policies.renewal_delay_seconds();
|
||||
int loop_count = loop_seconds / policies.renewal_retry_interval_seconds() + 1;
|
||||
if (loop_seconds % policies.renewal_retry_interval_seconds())
|
||||
++loop_count;
|
||||
|
||||
for (int i = 1; i <= loop_count; ++i) {
|
||||
PrepareForRenewalRequest(i);
|
||||
sleep(i > 1 ?
|
||||
policies.renewal_retry_interval_seconds() :
|
||||
policies.renewal_delay_seconds());
|
||||
MessageLoop::current()->RunUntilIdle();
|
||||
if (i < loop_count)
|
||||
GetRenewalMessage(message);
|
||||
}
|
||||
GetFailedRenewalMessage(message);
|
||||
}
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
// TODO(rkuroiwa): Find where to put this main function just for Widevine CDM
|
||||
// unit tests.
|
||||
int main(int argc, char **argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
base::AtExitManager exit;
|
||||
MessageLoop ttr(MessageLoop::TYPE_IO);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -547,11 +547,9 @@ bool SessionContext::RefreshKey(const KeyId& key_id,
|
||||
// Decrypt encrypted key control block
|
||||
std::vector<uint8_t> control;
|
||||
if (key_control_iv.empty()) {
|
||||
// TODO(fredg): get confirmation from server team this is valid.
|
||||
LOGD("Key control block is NOT encrypted.");
|
||||
control = key_control;
|
||||
} else {
|
||||
// TODO(fredg): get confirmation from server team this is valid, too.
|
||||
LOGD("Key control block is encrypted.");
|
||||
if (!DecryptMessage(content_key_value, key_control_iv, key_control,
|
||||
&control)) {
|
||||
@@ -1024,9 +1022,13 @@ OEMCryptoResult SessionContext::DecryptCTR(
|
||||
size_t cipher_data_length, bool is_encrypted, uint8_t* clear_data,
|
||||
BufferType buffer_type) {
|
||||
// If the data is clear, we do not need a current key selected.
|
||||
if (!is_encrypted && buffer_type != kBufferTypeDirect) {
|
||||
memcpy(reinterpret_cast<uint8_t*>(clear_data),
|
||||
cipher_data, cipher_data_length);
|
||||
if (!is_encrypted) {
|
||||
if (buffer_type != kBufferTypeDirect) {
|
||||
memcpy(reinterpret_cast<uint8_t*>(clear_data), cipher_data,
|
||||
cipher_data_length);
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
// For reference implementation, we quietly drop the clear direct video.
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1083,7 +1085,7 @@ OEMCryptoResult SessionContext::DecryptCTR(
|
||||
}
|
||||
|
||||
if (buffer_type == kBufferTypeDirect) {
|
||||
// For reference implementation, we quietly drop direct video.
|
||||
// For reference implementation, we quietly drop the decrypted direct video.
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@ static void dump_hex(std::string name, const uint8_t* vector, size_t length) {
|
||||
printf("NULL;\n");
|
||||
return;
|
||||
}
|
||||
// TODO(fredgc): replace with HEXEncode.
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
if (i == 0) {
|
||||
printf("\n wvcdm::a2b_hex(\"");
|
||||
|
||||
Reference in New Issue
Block a user