Decouple key fetcher; Update ECMG API
This commit is contained in:
22
common/certificate_type.h
Normal file
22
common/certificate_type.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright 2017 Google LLC.
|
||||||
|
//
|
||||||
|
// This software is licensed under the terms defined in the Widevine Master
|
||||||
|
// License Agreement. For a copy of this agreement, please contact
|
||||||
|
// widevine-licensing@google.com.
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef COMMON_CERTIFICATE_TYPE_H_
|
||||||
|
#define COMMON_CERTIFICATE_TYPE_H_
|
||||||
|
|
||||||
|
namespace widevine {
|
||||||
|
|
||||||
|
enum CertificateType {
|
||||||
|
kCertificateTypeTesting,
|
||||||
|
kCertificateTypeDevelopment,
|
||||||
|
kCertificateTypeProduction,
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace widevine
|
||||||
|
|
||||||
|
#endif // COMMON_CERTIFICATE_TYPE_H_
|
||||||
116
common/status.h
Normal file
116
common/status.h
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright 2017 Google LLC.
|
||||||
|
//
|
||||||
|
// This software is licensed under the terms defined in the Widevine Master
|
||||||
|
// License Agreement. For a copy of this agreement, please contact
|
||||||
|
// widevine-licensing@google.com.
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef COMMON_STATUS_H_
|
||||||
|
#define COMMON_STATUS_H_
|
||||||
|
|
||||||
|
#include <iosfwd>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "util/error_space.h"
|
||||||
|
|
||||||
|
namespace widevine {
|
||||||
|
namespace error {
|
||||||
|
|
||||||
|
enum StatusCode {
|
||||||
|
// Success.
|
||||||
|
OK = 0,
|
||||||
|
|
||||||
|
// Client specified an invalid argument.
|
||||||
|
INVALID_ARGUMENT = 3,
|
||||||
|
|
||||||
|
// Some requested entity (e.g., file or directory) was not found.
|
||||||
|
NOT_FOUND = 5,
|
||||||
|
|
||||||
|
// Some entity that we attempted to create (e.g., file or directory)
|
||||||
|
// already exists.
|
||||||
|
ALREADY_EXISTS = 6,
|
||||||
|
|
||||||
|
// The caller does not have permission to execute the specified
|
||||||
|
// operation. PERMISSION_DENIED must not be used for rejections
|
||||||
|
// caused by exhausting some resource (use RESOURCE_EXHAUSTED
|
||||||
|
// instead for those errors).
|
||||||
|
PERMISSION_DENIED = 7,
|
||||||
|
|
||||||
|
// The operation was rejected because the system is not in a state
|
||||||
|
// required for the operation's execution. For example, the directory
|
||||||
|
// to be deleted is non-empty, an rmdir operation is applied to
|
||||||
|
// a non-directory, etc.
|
||||||
|
FAILED_PRECONDITION = 9,
|
||||||
|
|
||||||
|
// Operation is not implemented or not supported/enabled in this service.
|
||||||
|
UNIMPLEMENTED = 12,
|
||||||
|
|
||||||
|
// Internal errors. Means some invariants expected by underlying
|
||||||
|
// system has been broken. If you see one of these errors,
|
||||||
|
// something is very broken.
|
||||||
|
INTERNAL = 13,
|
||||||
|
|
||||||
|
// Operation is not implemented or not supported/enabled in this service.
|
||||||
|
UNAVAILABLE = 14,
|
||||||
|
|
||||||
|
// Number of generic (non license related) errors.
|
||||||
|
NUM_ERRORS,
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace error
|
||||||
|
|
||||||
|
class Status {
|
||||||
|
public:
|
||||||
|
|
||||||
|
Status() = default;
|
||||||
|
|
||||||
|
~Status() = default;
|
||||||
|
|
||||||
|
explicit Status(error::StatusCode c) : status_code_(c) {}
|
||||||
|
|
||||||
|
Status(error::StatusCode c, const std::string& error_message)
|
||||||
|
: status_code_(c), error_message_(error_message) {}
|
||||||
|
|
||||||
|
Status(const util::ErrorSpace* e, error::StatusCode c,
|
||||||
|
const std::string& error_message)
|
||||||
|
: error_space_(e), status_code_(c), error_message_(error_message) {}
|
||||||
|
|
||||||
|
Status(const util::ErrorSpace* e, int error,
|
||||||
|
const std::string& error_message)
|
||||||
|
: error_space_(e), status_code_(error), error_message_(error_message) {}
|
||||||
|
|
||||||
|
bool ok() const { return status_code_ == error::OK; }
|
||||||
|
const util::ErrorSpace* error_space() const { return error_space_; }
|
||||||
|
static const util::ErrorSpace* canonical_space();
|
||||||
|
std::string ToString() const;
|
||||||
|
std::string error_message() const { return error_message_; }
|
||||||
|
int error_code() const { return status_code_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const util::ErrorSpace* error_space_ = canonical_space();
|
||||||
|
int status_code_ = error::OK;
|
||||||
|
std::string error_message_;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline Status OkStatus() { return Status(); }
|
||||||
|
|
||||||
|
inline bool operator==(const Status& s1, const Status& s2) {
|
||||||
|
return s1.error_space() == s2.error_space() &&
|
||||||
|
s1.error_code() == s2.error_code() &&
|
||||||
|
s1.error_message() == s2.error_message();
|
||||||
|
}
|
||||||
|
inline bool operator!=(const Status& s1, const Status& s2) {
|
||||||
|
return !(s1 == s2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Prints a human-readable representation of 'x' to 'os'.
|
||||||
|
std::ostream& operator<<(std::ostream& os, const Status& x);
|
||||||
|
|
||||||
|
#define CHECK_OK(expression) CHECK(expression.ok()) << expression.ToString()
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace widevine
|
||||||
|
|
||||||
|
#endif // COMMON_STATUS_H_
|
||||||
@@ -29,7 +29,7 @@ constexpr char kTestEcmgChannelSetup[] = {
|
|||||||
constexpr char kTestEcmgChannelSetupWithPrivateParameters[] = {
|
constexpr char kTestEcmgChannelSetupWithPrivateParameters[] = {
|
||||||
'\x03', // protocol_version
|
'\x03', // protocol_version
|
||||||
'\x00', '\x01', // message_type - Channel_setup
|
'\x00', '\x01', // message_type - Channel_setup
|
||||||
'\x00', '\x70', // message_length
|
'\x00', '\x8c', // message_length
|
||||||
'\x00', '\x0e', // parameter_type - ECM_channel_id
|
'\x00', '\x0e', // parameter_type - ECM_channel_id
|
||||||
'\x00', '\x02', // parameter_length
|
'\x00', '\x02', // parameter_length
|
||||||
'\x00', '\x01', // parameter_value
|
'\x00', '\x01', // parameter_value
|
||||||
@@ -45,25 +45,26 @@ constexpr char kTestEcmgChannelSetupWithPrivateParameters[] = {
|
|||||||
'\x80', '\x04', // parameter_type - TRACK_TYPES
|
'\x80', '\x04', // parameter_type - TRACK_TYPES
|
||||||
'\x00', '\x02', // parameter_length
|
'\x00', '\x02', // parameter_length
|
||||||
'S', 'D', // parameter_value
|
'S', 'D', // parameter_value
|
||||||
'\x80', '\x04', // parameter_type - TRACK_TYPES
|
'\x80', '\x07', // parameter_type - ENTITLEMENT_ID_KEY_COMBINATION
|
||||||
'\x00', '\x02', // parameter_length
|
'\x00', '\x30', // parameter_length
|
||||||
'H', 'D', // parameter_value
|
// parameter_value - ENTITLEMENT_ID (16 bytes)
|
||||||
'\x80', '\x02', // parameter_type - CONTENT_ID
|
'\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37', //
|
||||||
'\x00', '\x09', // parameter_length
|
'\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37', //
|
||||||
'C', 'a', 's', 'T', 's', 'F', 'a', 'k',
|
// parameter_value (continued) - ENTITLEMENT_KEY (32 bytes)
|
||||||
'e', // parameter_value - CasTsFake
|
'\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37', //
|
||||||
'\x80', '\x03', // parameter_type - CONTENT_PROVIDER
|
'\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37', //
|
||||||
'\x00', '\x0d', // parameter_length
|
'\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37', //
|
||||||
'w', 'i', 'd', 'e', 'v', 'i', 'n', 'e',
|
'\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37', //
|
||||||
'_', 't', 'e', 's', 't', // parameter_value - widevine_test
|
'\x80', '\x07', // parameter_type - ENTITLEMENT_ID_KEY_COMBINATION
|
||||||
'\x80', '\x06', // parameter_type - CONTENT_IV
|
'\x00', '\x30', // parameter_length
|
||||||
'\x00', '\x10', // parameter_length
|
// parameter_value - ENTITLEMENT_ID (16 bytes)
|
||||||
'\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
|
'\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', '\x68', //
|
||||||
'\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
|
'\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', '\x68', //
|
||||||
'\x80', '\x06', // parameter_type - CONTENT_IV
|
// parameter_value (continued) - ENTITLEMENT_KEY (32 bytes)
|
||||||
'\x00', '\x10', // parameter_length
|
'\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', '\x68', //
|
||||||
'\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
|
'\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', '\x68', //
|
||||||
'\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f'};
|
'\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', '\x68', //
|
||||||
|
'\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', '\x68'};
|
||||||
|
|
||||||
constexpr char kTestEcmgChannelTest[] = {
|
constexpr char kTestEcmgChannelTest[] = {
|
||||||
'\x03', // protocol_version
|
'\x03', // protocol_version
|
||||||
@@ -74,6 +75,18 @@ constexpr char kTestEcmgChannelTest[] = {
|
|||||||
'\x00', '\x01', // parameter_value
|
'\x00', '\x01', // parameter_value
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr char kTestEcmgChannelError[] = {
|
||||||
|
'\x03', // protocol_version
|
||||||
|
'\x00', '\x05', // message_type - Stream_error
|
||||||
|
'\x00', '\x0c', // message_length
|
||||||
|
'\x00', '\x0e', // parameter_type - ECM_channel_id
|
||||||
|
'\x00', '\x02', // parameter_length
|
||||||
|
'\x00', '\x01', // parameter_value
|
||||||
|
'\x70', '\x00', // parameter_type - Error_status
|
||||||
|
'\x00', '\x02', // parameter_length
|
||||||
|
'\x70', '\x00', // parameter_value (UNKNOWN_ERROR)
|
||||||
|
};
|
||||||
|
|
||||||
constexpr char kTestEcmgChannelStatus[] = {
|
constexpr char kTestEcmgChannelStatus[] = {
|
||||||
'\x03', // protocol_version
|
'\x03', // protocol_version
|
||||||
'\x00', '\x03', // message_type - Channel_status
|
'\x00', '\x03', // message_type - Channel_status
|
||||||
@@ -113,7 +126,7 @@ constexpr char kTestEcmgChannelStatus[] = {
|
|||||||
constexpr char kTestEcmgStreamSetupWithPrivateParameters[] = {
|
constexpr char kTestEcmgStreamSetupWithPrivateParameters[] = {
|
||||||
'\x03', // protocol_version
|
'\x03', // protocol_version
|
||||||
'\x01', '\x01', // message_type - Stream_setup
|
'\x01', '\x01', // message_type - Stream_setup
|
||||||
'\x00', '\x1e', // message_length
|
'\x00', '\x46', // message_length
|
||||||
'\x00', '\x0e', // parameter_type - ECM_channel_id
|
'\x00', '\x0e', // parameter_type - ECM_channel_id
|
||||||
'\x00', '\x02', // parameter_length
|
'\x00', '\x02', // parameter_length
|
||||||
'\x00', '\x01', // parameter_value
|
'\x00', '\x01', // parameter_value
|
||||||
@@ -129,7 +142,14 @@ constexpr char kTestEcmgStreamSetupWithPrivateParameters[] = {
|
|||||||
'\x80', '\x05', // parameter_type - STREAM_TRACK_TYPE
|
'\x80', '\x05', // parameter_type - STREAM_TRACK_TYPE
|
||||||
'\x00', '\x02', // parameter_length
|
'\x00', '\x02', // parameter_length
|
||||||
'S', 'D', // parameter_value
|
'S', 'D', // parameter_value
|
||||||
};
|
'\x80', '\x06', // parameter_type - CONTENT_IV
|
||||||
|
'\x00', '\x10', // parameter_length
|
||||||
|
'\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
|
||||||
|
'\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
|
||||||
|
'\x80', '\x06', // parameter_type - CONTENT_IV
|
||||||
|
'\x00', '\x10', // parameter_length
|
||||||
|
'\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
|
||||||
|
'\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f'};
|
||||||
|
|
||||||
constexpr char kTestEcmgStreamSetup[] = {
|
constexpr char kTestEcmgStreamSetup[] = {
|
||||||
'\x03', // protocol_version
|
'\x03', // protocol_version
|
||||||
@@ -179,6 +199,24 @@ constexpr char kTestEcmgStreamStatus[] = {
|
|||||||
'\x01' // parameter_value
|
'\x01' // parameter_value
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr char kTestEcmgStreamError[] = {
|
||||||
|
'\x03', // protocol_version
|
||||||
|
'\x01', '\x06', // message_type - Stream_error
|
||||||
|
'\x00', '\x1a', // message_length
|
||||||
|
'\x00', '\x0e', // parameter_type - ECM_channel_id
|
||||||
|
'\x00', '\x02', // parameter_length
|
||||||
|
'\x00', '\x01', // parameter_value
|
||||||
|
'\x00', '\x0f', // parameter_type - ECM_stream_id
|
||||||
|
'\x00', '\x02', // parameter_length
|
||||||
|
'\x00', '\x01', // parameter_value
|
||||||
|
'\x70', '\x00', // parameter_type - Error_status
|
||||||
|
'\x00', '\x02', // parameter_length
|
||||||
|
'\x70', '\x00', // parameter_value (UNKNOWN_ERROR)
|
||||||
|
'\x70', '\x01', // parameter_type - Error_information
|
||||||
|
'\x00', '\x04', // parameter_length
|
||||||
|
'i', 'n', 'f', 'o' // parameter_value
|
||||||
|
};
|
||||||
|
|
||||||
constexpr char kTestEcmgCwProvision[] = {
|
constexpr char kTestEcmgCwProvision[] = {
|
||||||
'\x03', // protocol_version
|
'\x03', // protocol_version
|
||||||
'\x02', '\x01', // message_type - CW_provision
|
'\x02', '\x01', // message_type - CW_provision
|
||||||
@@ -209,7 +247,7 @@ constexpr char kTestEcmgCwProvision[] = {
|
|||||||
constexpr char kTestEcmgCwProvisionWithAccessCriteria[] = {
|
constexpr char kTestEcmgCwProvisionWithAccessCriteria[] = {
|
||||||
'\x03', // protocol_version
|
'\x03', // protocol_version
|
||||||
'\x02', '\x01', // message_type - CW_provision
|
'\x02', '\x01', // message_type - CW_provision
|
||||||
'\x00', '\xaa', // message_length
|
'\x00', '\xf4', // message_length
|
||||||
'\x00', '\x0e', // parameter_type - ECM_channel_id
|
'\x00', '\x0e', // parameter_type - ECM_channel_id
|
||||||
'\x00', '\x02', // parameter_length
|
'\x00', '\x02', // parameter_length
|
||||||
'\x00', '\x01', // parameter_value
|
'\x00', '\x01', // parameter_value
|
||||||
@@ -225,15 +263,15 @@ constexpr char kTestEcmgCwProvisionWithAccessCriteria[] = {
|
|||||||
'\x00', '\x14', // parameter_type - CP_CW_Combination
|
'\x00', '\x14', // parameter_type - CP_CW_Combination
|
||||||
'\x00', '\x12', // parameter_length
|
'\x00', '\x12', // parameter_length
|
||||||
'\x00', '\x00', // parameter_value - CP (2 bytes) then CW next (16 bytes)
|
'\x00', '\x00', // parameter_value - CP (2 bytes) then CW next (16 bytes)
|
||||||
'\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
|
'\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', //
|
||||||
'\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
|
'\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f', //
|
||||||
'\x00', '\x14', // parameter_type - CP_CW_Combination
|
'\x00', '\x14', // parameter_type - CP_CW_Combination
|
||||||
'\x00', '\x12', // parameter_length
|
'\x00', '\x12', // parameter_length
|
||||||
'\x00', '\x01', // parameter_value - CP (2 bytes) then CW next (16 bytes)
|
'\x00', '\x01', // parameter_value - CP (2 bytes) then CW next (16 bytes)
|
||||||
'\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
|
'\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', //
|
||||||
'\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
|
'\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', //
|
||||||
'\x00', '\x0d', // parameter_type - access_criteria
|
'\x00', '\x0d', // parameter_type - access_criteria
|
||||||
'\x00', '\x62', // parameter_length
|
'\x00', '\xac', // parameter_length
|
||||||
'\x80', '\x00', // access_criteria parameter_type - AGE_RESTRICTION
|
'\x80', '\x00', // access_criteria parameter_type - AGE_RESTRICTION
|
||||||
'\x00', '\x01', // parameter_length
|
'\x00', '\x01', // parameter_length
|
||||||
'\x00', // parameter_value
|
'\x00', // parameter_value
|
||||||
@@ -246,22 +284,34 @@ constexpr char kTestEcmgCwProvisionWithAccessCriteria[] = {
|
|||||||
'\x80', '\x05', // access_criteria parameter_type - STREAM_TRACK_TYPE
|
'\x80', '\x05', // access_criteria parameter_type - STREAM_TRACK_TYPE
|
||||||
'\x00', '\x02', // parameter_length
|
'\x00', '\x02', // parameter_length
|
||||||
'S', 'D', // parameter_value
|
'S', 'D', // parameter_value
|
||||||
'\x80', '\x02', // access_criteria parameter_type - CONTENT_ID
|
|
||||||
'\x00', '\x09', // parameter_length
|
|
||||||
'C', 'a', 's', 'T', 's', 'F', 'a', 'k',
|
|
||||||
'e', // parameter_value - CasTsFake
|
|
||||||
'\x80', '\x03', // access_criteria parameter_type - CONTENT_PROVIDER
|
|
||||||
'\x00', '\x0d', // parameter_length
|
|
||||||
'w', 'i', 'd', 'e', 'v', 'i', 'n', 'e',
|
|
||||||
'_', 't', 'e', 's', 't', // parameter_value - widevine_test
|
|
||||||
'\x80', '\x06', // access_criteria parameter_type - CONTENT_IV
|
'\x80', '\x06', // access_criteria parameter_type - CONTENT_IV
|
||||||
'\x00', '\x10', // parameter_length
|
'\x00', '\x10', // parameter_length
|
||||||
'\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
|
'\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', //
|
||||||
'\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
|
'\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f', //
|
||||||
'\x80', '\x06', // access_criteria parameter_type - CONTENT_IV
|
'\x80', '\x06', // access_criteria parameter_type - CONTENT_IV
|
||||||
'\x00', '\x10', // parameter_length
|
'\x00', '\x10', // parameter_length
|
||||||
'\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
|
'\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', //
|
||||||
'\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f'};
|
'\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', //
|
||||||
|
'\x80', '\x07', // parameter_type - ENTITLEMENT_ID_KEY_COMBINATION
|
||||||
|
'\x00', '\x30', // parameter_length
|
||||||
|
// parameter_value - ENTITLEMENT_ID (16 bytes)
|
||||||
|
'\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37', //
|
||||||
|
'\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37', //
|
||||||
|
// parameter_value (continued) - ENTITLEMENT_KEY (32 bytes)
|
||||||
|
'\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37', //
|
||||||
|
'\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37', //
|
||||||
|
'\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37', //
|
||||||
|
'\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37', //
|
||||||
|
'\x80', '\x07', // parameter_type - ENTITLEMENT_ID_KEY_COMBINATION
|
||||||
|
'\x00', '\x30', // parameter_length
|
||||||
|
// parameter_value - ENTITLEMENT_ID (16 bytes)
|
||||||
|
'\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', '\x68', //
|
||||||
|
'\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', '\x68', //
|
||||||
|
// parameter_value (continued) - ENTITLEMENT_KEY (32 bytes)
|
||||||
|
'\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', '\x68', //
|
||||||
|
'\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', '\x68', //
|
||||||
|
'\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', '\x68', //
|
||||||
|
'\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', '\x68'};
|
||||||
|
|
||||||
constexpr char kTestEcmgCwProvisionSingleKey[] = {
|
constexpr char kTestEcmgCwProvisionSingleKey[] = {
|
||||||
'\x03', // protocol_version
|
'\x03', // protocol_version
|
||||||
@@ -303,25 +353,25 @@ constexpr char kTestEcmgEcmResponse[] = {
|
|||||||
'\x00', '\xbc', // parameter_length
|
'\x00', '\xbc', // parameter_length
|
||||||
// parameter_value - ECM_datagram
|
// parameter_value - ECM_datagram
|
||||||
'\x47', '\x40', '\x00', '\x10', '\x00', '\x80', '\x70', '\xa5', '\x4a',
|
'\x47', '\x40', '\x00', '\x10', '\x00', '\x80', '\x70', '\xa5', '\x4a',
|
||||||
'\xd4', '\x02', '\x0b', '\xc0', '\x66', '\x61', '\x6b', '\x65', '\x5f',
|
'\xd4', '\x02', '\x0b', '\xc0', '\x30', '\x31', '\x32', '\x33', '\x34',
|
||||||
'\x6b', '\x65', '\x79', '\x5f', '\x69', '\x64', '\x31', '\x2e', '\x2e',
|
'\x35', '\x36', '\x37', '\x30', '\x31', '\x32', '\x33', '\x34', '\x35',
|
||||||
'\x2e', '\x2e', '\xef', '\x40', '\x57', '\x48', '\xa7', '\xad', '\xdd',
|
'\x36', '\x37', '\xef', '\x40', '\x57', '\x48', '\xa7', '\xad', '\xdd',
|
||||||
'\x34', '\x73', '\xfe', '\x5d', '\x1c', '\x65', '\xa0', '\xbf', '\x93',
|
'\x34', '\x73', '\xfe', '\x5d', '\x1c', '\x65', '\xa0', '\xbf', '\x93',
|
||||||
'\xfe', '\x01', '\x4b', '\x1d', '\xcd', '\x9e', '\x1d', '\x3a', '\x36',
|
'\x90', '\x04', '\x1a', '\xab', '\x1a', '\x46', '\x00', '\xdb', '\xdb',
|
||||||
'\x99', '\x8f', '\x47', '\xa1', '\x3b', '\x46', '\xf1', '\xde', '\x9e',
|
'\x2f', '\xcb', '\xa5', '\x10', '\x2a', '\x3b', '\x73', '\xf1', '\xfe',
|
||||||
'\xc2', '\x88', '\xf8', '\x27', '\x2f', '\xea', '\xa1', '\x63', '\x9b',
|
'\x9d', '\x28', '\x2a', '\x3c', '\x0a', '\x5c', '\x58', '\xbc', '\x97',
|
||||||
'\x1b', '\x6a', '\x56', '\x2d', '\x26', '\x31', '\x32', '\x33', '\x34',
|
'\x1d', '\x81', '\x5b', '\x5b', '\xf7', '\x00', '\x01', '\x02', '\x03',
|
||||||
'\x35', '\x36', '\x37', '\x38', '\x66', '\x61', '\x6b', '\x65', '\x5f',
|
'\x04', '\x05', '\x06', '\x07', '\x08', '\x09', '\x0a', '\x0b', '\x0c',
|
||||||
'\x6b', '\x65', '\x79', '\x5f', '\x69', '\x64', '\x32', '\x2e', '\x2e',
|
'\x0d', '\x0e', '\x0f', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66',
|
||||||
'\x2e', '\x2e', '\xf4', '\x71', '\x2a', '\x4b', '\x6d', '\x6d', '\x14',
|
'\x67', '\x68', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67',
|
||||||
'\x4d', '\x2e', '\x53', '\xe7', '\x4b', '\x9f', '\x4b', '\x0a', '\x34',
|
'\x68', '\xf4', '\x71', '\x2a', '\x4b', '\x6d', '\x6d', '\x14', '\x4d',
|
||||||
'\xb4', '\xfd', '\xbe', '\x86', '\x21', '\x35', '\x1e', '\xda', '\x81',
|
'\x2e', '\x53', '\xe7', '\x4b', '\x9f', '\x4b', '\x0a', '\x34', '\x84',
|
||||||
'\x89', '\x6f', '\x70', '\xd3', '\xd2', '\xb2', '\x79', '\xf2', '\xcd',
|
'\xe7', '\xe8', '\xf5', '\x02', '\x39', '\x1f', '\x62', '\x43', '\xb5',
|
||||||
'\xeb', '\xc5', '\xaf', '\x89', '\xab', '\xeb', '\xf0', '\x1b', '\xd0',
|
'\xca', '\xb0', '\xee', '\x77', '\xaf', '\xe9', '\x84', '\x41', '\x0a',
|
||||||
'\xd3', '\xe9', '\x7d', '\x81', '\x8a', '\x31', '\x32', '\x33', '\x34',
|
'\x16', '\x45', '\x23', '\x6c', '\x1d', '\xe7', '\xdb', '\xfd', '\x91',
|
||||||
'\x35', '\x36', '\x37', '\x38', '\xff', '\xff', '\xff', '\xff', '\xff',
|
'\x91', '\xac', '\x47', '\xbc', '\x10', '\x11', '\x12', '\x13', '\x14',
|
||||||
'\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff',
|
'\x15', '\x16', '\x17', '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d',
|
||||||
'\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff',
|
'\x1e', '\x1f', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff',
|
||||||
'\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff'};
|
'\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff'};
|
||||||
|
|
||||||
constexpr char kTestEcmgStreamClose[] = {
|
constexpr char kTestEcmgStreamClose[] = {
|
||||||
|
|||||||
Binary file not shown.
@@ -17,63 +17,125 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include "common/status.h"
|
||||||
#include "media_cas_packager_sdk/public/wv_cas_ecm.h"
|
#include "media_cas_packager_sdk/public/wv_cas_ecm.h"
|
||||||
#include "media_cas_packager_sdk/public/wv_cas_types.h"
|
#include "media_cas_packager_sdk/public/wv_cas_types.h"
|
||||||
|
|
||||||
const size_t kContentIvSize = 8;
|
const size_t kContentIvSize = 16; // 8 or 16
|
||||||
const bool kKeyRotation = false; // whether key rotation is enabled
|
const bool kKeyRotation = true; // whether key rotation is enabled
|
||||||
const char kCryptoMode[] = "CTR"; // CBC, CTR, or CSA2
|
const char kCryptoMode[] =
|
||||||
|
"AesScte"; // "AesCbc", "AesCtr", "DvbCsa2", "DvbCsa3", "AesOfb", "AesScte"
|
||||||
const int kEcmPid = 149; // PID for the ECM packet
|
const int kEcmPid = 149; // PID for the ECM packet
|
||||||
|
const int kAgeRestriction = 0; // Age restriction for the ECM
|
||||||
const char kOutputFile[] =
|
const char kOutputFile[] =
|
||||||
"/tmp/ecm.ts"; // ECM TS packet will be output to here
|
"/tmp/ecm.ts"; // ECM TS packet will be output to here
|
||||||
|
const uint8_t kTableId = 0x80; // 0x80 or 0x81
|
||||||
|
const char kDefaultTrackTypeSd[] = "SD";
|
||||||
|
|
||||||
const char kCsaEvenKey[] = "even_key"; // 8 bytes
|
const char kEvenKey[] = "even_key........"; // 16 bytes
|
||||||
|
const char kEvenKeyId[] = "even_key_id....."; // 16 bytes
|
||||||
const char kEvenContentIv8Bytes[] = "even_iv."; // 8 bytes
|
const char kEvenContentIv8Bytes[] = "even_iv."; // 8 bytes
|
||||||
|
const char kEvenContentIv16Bytes[] = "even_iv.even_iv."; // 16 bytes
|
||||||
const char kEvenEntitlementKeyId[] = "fake_key_id1...."; // 16 bytes
|
const char kEvenEntitlementKeyId[] = "fake_key_id1...."; // 16 bytes
|
||||||
const char kEvenEntitlementKey[] =
|
const char kEvenEntitlementKey[] =
|
||||||
"fakefakefakefakefakefakefake1..."; // 32 bytes
|
"fakefakefakefakefakefakefake1..."; // 32 bytes
|
||||||
const char kCsaOddKey[] = "odd_key."; // 8 bytes
|
const char kEvenWrapIv[] = "even_warp_iv...."; // 16 bytes
|
||||||
|
|
||||||
|
const char kOddKey[] = "odd_key........."; // 16 bytes
|
||||||
|
const char kOddKeyId[] = "odd_key_id......"; // 16 bytes
|
||||||
const char kOddContentIv8Bytes[] = "odd_iv.."; // 8 bytes
|
const char kOddContentIv8Bytes[] = "odd_iv.."; // 8 bytes
|
||||||
|
const char kOddContentIv16Bytes[] = "odd_iv..odd_iv.."; // 16 bytes
|
||||||
const char kOddEntitlementKeyId[] = "fake_key_id2...."; // 16 bytes
|
const char kOddEntitlementKeyId[] = "fake_key_id2...."; // 16 bytes
|
||||||
const char kOddEntitlementKey[] =
|
const char kOddEntitlementKey[] =
|
||||||
"fakefakefakefakefakefakefake2..."; // 32 bytes
|
"fakefakefakefakefakefakefake2..."; // 32 bytes
|
||||||
const uint8_t kTableId = 0x80;
|
const char kOddWrapIv[] = "odd_warp_iv....."; // 16 bytes
|
||||||
|
|
||||||
const size_t kTsPacketSize = 188;
|
const size_t kTsPacketSize = 188;
|
||||||
|
|
||||||
widevine::cas::CryptoMode GetCryptoMode(const std::string& crypto_mode) {
|
using widevine::cas::EntitlementKeyInfo;
|
||||||
if (crypto_mode.compare("CBC") == 0) {
|
using widevine::cas::WvCasContentKeyInfo;
|
||||||
return widevine::cas::CryptoMode::kAesCbc;
|
using widevine::cas::WvCasEcmParameters;
|
||||||
|
|
||||||
|
WvCasEcmParameters CreateWvCasEcmParameters(bool key_rotation,
|
||||||
|
int content_iv_size) {
|
||||||
|
WvCasEcmParameters params;
|
||||||
|
params.content_iv_size = content_iv_size == 8
|
||||||
|
? widevine::cas::kIvSize8
|
||||||
|
: widevine::cas::kIvSize16;
|
||||||
|
params.key_rotation_enabled = key_rotation;
|
||||||
|
if (!widevine::cas::StringToCryptoMode(kCryptoMode,
|
||||||
|
¶ms.crypto_mode)) {
|
||||||
|
std::cerr << "Unsupported crypto mode " << kCryptoMode << std::endl;
|
||||||
}
|
}
|
||||||
if (crypto_mode.compare("CTR") == 0) {
|
params.age_restriction = kAgeRestriction;
|
||||||
return widevine::cas::CryptoMode::kAesCtr;
|
return params;
|
||||||
}
|
}
|
||||||
return widevine::cas::CryptoMode::kDvbCsa2;
|
|
||||||
|
std::vector<EntitlementKeyInfo> CreateInjectedEntitlements(bool key_rotation) {
|
||||||
|
std::vector<EntitlementKeyInfo> injected_entitlements;
|
||||||
|
injected_entitlements.reserve(key_rotation ? 2 : 1);
|
||||||
|
injected_entitlements.emplace_back();
|
||||||
|
EntitlementKeyInfo* entitlement = &injected_entitlements.back();
|
||||||
|
entitlement->key_id = kEvenEntitlementKeyId;
|
||||||
|
entitlement->key_value = kEvenEntitlementKey;
|
||||||
|
entitlement->is_even_key = true;
|
||||||
|
entitlement->track_type = kDefaultTrackTypeSd;
|
||||||
|
if (key_rotation) {
|
||||||
|
injected_entitlements.emplace_back();
|
||||||
|
EntitlementKeyInfo* entitlement = &injected_entitlements.back();
|
||||||
|
entitlement->key_id = kOddEntitlementKeyId;
|
||||||
|
entitlement->key_value = kOddEntitlementKey;
|
||||||
|
entitlement->is_even_key = false;
|
||||||
|
entitlement->track_type = kDefaultTrackTypeSd;
|
||||||
|
}
|
||||||
|
return injected_entitlements;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<WvCasContentKeyInfo> CreateContentKeyInfo(bool key_rotation,
|
||||||
|
int content_iv_size) {
|
||||||
|
std::vector<WvCasContentKeyInfo> content_keys;
|
||||||
|
content_keys.reserve(key_rotation ? 2 : 1);
|
||||||
|
content_keys.emplace_back();
|
||||||
|
WvCasContentKeyInfo* content_key = &content_keys.back();
|
||||||
|
content_key->key = kEvenKey;
|
||||||
|
content_key->key_id = kEvenKeyId;
|
||||||
|
content_key->content_iv =
|
||||||
|
content_iv_size == 8 ? kEvenContentIv8Bytes : kEvenContentIv16Bytes;
|
||||||
|
content_key->wrapped_key_iv = kEvenWrapIv;
|
||||||
|
if (key_rotation) {
|
||||||
|
content_keys.emplace_back();
|
||||||
|
WvCasContentKeyInfo* content_key = &content_keys.back();
|
||||||
|
content_key->key = kOddKey;
|
||||||
|
content_key->key_id = kOddKeyId;
|
||||||
|
content_key->content_iv =
|
||||||
|
content_iv_size == 8 ? kOddContentIv8Bytes : kOddContentIv16Bytes;
|
||||||
|
content_key->wrapped_key_iv = kOddWrapIv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return content_keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
// Generate ECM.
|
WvCasEcmParameters params =
|
||||||
widevine::cas::WvCasEcm wv_cas_ecm;
|
CreateWvCasEcmParameters(kKeyRotation, kContentIvSize);
|
||||||
widevine::cas::WvCasStatus status = wv_cas_ecm.Initialize(
|
std::vector<EntitlementKeyInfo> entitlements =
|
||||||
kContentIvSize, kKeyRotation, GetCryptoMode(kCryptoMode));
|
CreateInjectedEntitlements(kKeyRotation);
|
||||||
if (status != widevine::cas::OK) {
|
widevine::cas::WvCasEcm wv_cas_ecm(params, entitlements);
|
||||||
std::cerr << "Failed to initialize WV CAS ECM, error: "
|
|
||||||
<< widevine::cas::GetWvCasStatusMessage(status)
|
std::vector<WvCasContentKeyInfo> content_keys =
|
||||||
<< std::endl;
|
CreateContentKeyInfo(kKeyRotation, kContentIvSize);
|
||||||
}
|
|
||||||
std::string ecm;
|
std::string ecm;
|
||||||
|
widevine::Status status;
|
||||||
if (kKeyRotation) {
|
if (kKeyRotation) {
|
||||||
status = wv_cas_ecm.GenerateEcm(
|
status = wv_cas_ecm.GenerateEcm(content_keys[0], content_keys[1],
|
||||||
kCsaEvenKey, kEvenContentIv8Bytes, kEvenEntitlementKeyId,
|
kDefaultTrackTypeSd, &ecm);
|
||||||
kEvenEntitlementKey, kCsaOddKey, kOddContentIv8Bytes,
|
|
||||||
kOddEntitlementKeyId, kOddEntitlementKey, &ecm);
|
|
||||||
} else {
|
} else {
|
||||||
status = wv_cas_ecm.GenerateSingleKeyEcm(kCsaEvenKey, kEvenContentIv8Bytes,
|
status = wv_cas_ecm.GenerateSingleKeyEcm(content_keys[0],
|
||||||
kEvenEntitlementKeyId,
|
kDefaultTrackTypeSd, &ecm);
|
||||||
kEvenEntitlementKey, &ecm);
|
|
||||||
}
|
}
|
||||||
if (status != widevine::cas::OK) {
|
|
||||||
std::cerr << "Failed to generate WV CAS ECM, error: "
|
if (!status.ok()) {
|
||||||
<< widevine::cas::GetWvCasStatusMessage(status)
|
std::cerr << "Failed to generate WV CAS ECM, error: " << status
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
@@ -89,8 +151,8 @@ int main(int argc, char** argv) {
|
|||||||
uint8_t continuity_counter; // not used.
|
uint8_t continuity_counter; // not used.
|
||||||
status = wv_cas_ecm.GenerateTsPacket(ecm, kEcmPid, kTableId,
|
status = wv_cas_ecm.GenerateTsPacket(ecm, kEcmPid, kTableId,
|
||||||
&continuity_counter, packet);
|
&continuity_counter, packet);
|
||||||
if (status != widevine::cas::OK) {
|
if (!status.ok()) {
|
||||||
std::cerr << "Failed to create ECM TS packet" << std::endl;
|
std::cerr << "Failed to create ECM TS packet: " << status << std::endl;
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
std::cout << "TS packet bytes: ";
|
std::cout << "TS packet bytes: ";
|
||||||
|
|||||||
Binary file not shown.
@@ -7,65 +7,86 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "glog/logging.h"
|
|
||||||
#include "absl/flags/flag.h"
|
|
||||||
#include "absl/flags/parse.h"
|
|
||||||
#include "common/status.h"
|
#include "common/status.h"
|
||||||
#include "media_cas_packager_sdk/public/wv_cas_key_fetcher.h"
|
#include "media_cas_packager_sdk/public/wv_cas_key_fetcher.h"
|
||||||
#include "protos/public/media_cas_encryption.pb.h"
|
|
||||||
|
|
||||||
ABSL_FLAG(std::string, content_id, "21140844", "Content ID");
|
const char kContentId[] = "21140844";
|
||||||
ABSL_FLAG(bool, key_rotation, true, "Whether key rotation is enabled");
|
const char kContentProvider[] = "widevine";
|
||||||
ABSL_FLAG(std::string, track_type, "SD", "Provider name");
|
const char kTrackType[] = "SD";
|
||||||
|
const bool kKeyRotation = false;
|
||||||
|
const char kSigningProvider[] = "widevine_test";
|
||||||
|
const char kSingingKey[] =
|
||||||
|
"1ae8ccd0e7985cc0b6203a55855a1034afc252980e970ca90e5202689f947ab9";
|
||||||
|
const char kSingingIv[] = "d58ce954203b7c9a9a9d467f59839249";
|
||||||
|
const char kHttpResponse[] =
|
||||||
|
"{\"response\":"
|
||||||
|
"\"eyJzdGF0dXMiOiJPSyIsImNvbnRlbnRfaWQiOiJNakV4TkRBNE5EUT0iLCJlbnRpdGxlbWVu"
|
||||||
|
"dF9rZXlzIjpbeyJrZXlfaWQiOiJNUGFndXhNb1hNNkUxUzhEOUF3RkNBPT0iLCJrZXkiOiJoZ1"
|
||||||
|
"JycmdqeUg4NjQycjY3VHd0OHJ1cU5MUGNMRmtKcWRVSUROdm5GZDBNPSIsInRyYWNrX3R5cGUi"
|
||||||
|
"OiJTRCIsImtleV9zbG90IjoiU0lOR0xFIn1dfQ==\"}";
|
||||||
|
|
||||||
|
using widevine::Status;
|
||||||
|
using widevine::cas::EntitlementKeyInfo;
|
||||||
|
using widevine::cas::EntitlementRequestParams;
|
||||||
|
using widevine::cas::WvCasKeyFetcher;
|
||||||
|
|
||||||
|
class ExampleKeyFetcher : public WvCasKeyFetcher {
|
||||||
|
public:
|
||||||
|
ExampleKeyFetcher(const std::string& signing_provider,
|
||||||
|
const std::string& signing_key,
|
||||||
|
const std::string& signing_iv)
|
||||||
|
: WvCasKeyFetcher(signing_provider, signing_key, signing_iv) {}
|
||||||
|
|
||||||
|
// An example that always returns the same response.
|
||||||
|
Status MakeHttpRequest(const std::string& signed_request_json,
|
||||||
|
std::string* http_response_json) const override {
|
||||||
|
*http_response_json = kHttpResponse;
|
||||||
|
return widevine::OkStatus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
absl::ParseCommandLine(argc, argv);
|
// Initialize key fetcher.
|
||||||
CHECK(!absl::GetFlag(FLAGS_content_id).empty() &&
|
ExampleKeyFetcher key_fetcher(kSigningProvider, kSingingKey, kSingingIv);
|
||||||
!absl::GetFlag(FLAGS_track_type).empty())
|
|
||||||
<< "Flags 'content_id' and 'track_type' are required";
|
|
||||||
// Required flags in key fetcher.
|
|
||||||
CHECK(!absl::GetFlag(FLAGS_license_server).empty() &&
|
|
||||||
!absl::GetFlag(FLAGS_signing_provider).empty() &&
|
|
||||||
!absl::GetFlag(FLAGS_signing_key).empty() &&
|
|
||||||
!absl::GetFlag(FLAGS_signing_iv).empty())
|
|
||||||
<< "Flags 'license_server', 'signing_provider', 'signing_key' "
|
|
||||||
"and 'signing_iv' are required";
|
|
||||||
|
|
||||||
|
// Create request string.
|
||||||
std::string request_str;
|
std::string request_str;
|
||||||
widevine::CasEncryptionRequest request;
|
EntitlementRequestParams request_params;
|
||||||
request.set_provider(absl::GetFlag(FLAGS_signing_provider));
|
request_params.content_id = kContentId;
|
||||||
request.set_content_id(absl::GetFlag(FLAGS_content_id));
|
request_params.content_provider = kContentProvider;
|
||||||
request.set_key_rotation(absl::GetFlag(FLAGS_key_rotation));
|
request_params.track_types = {kTrackType};
|
||||||
// Only 1 track in this example.
|
request_params.key_rotation = kKeyRotation;
|
||||||
request.add_track_types(absl::GetFlag(FLAGS_track_type));
|
Status status =
|
||||||
LOG(INFO) << "Request: " << request.ShortDebugString();
|
key_fetcher.CreateEntitlementRequest(request_params, &request_str);
|
||||||
if (!request.SerializeToString(&request_str)) {
|
|
||||||
LOG(ERROR) << "Failed to serialize request";
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string signed_response_str;
|
|
||||||
widevine::cas::WvCasKeyFetcher key_fetcher;
|
|
||||||
widevine::Status status =
|
|
||||||
key_fetcher.RequestEntitlementKey(request_str, &signed_response_str);
|
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
LOG(ERROR) << "Failed to request entitlement key";
|
std::cerr << "Failed to create entitlement request, error: " << status
|
||||||
return -1;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
widevine::SignedCasEncryptionResponse signed_response;
|
std::cout << "Request: " << request_str << std::endl;
|
||||||
if (!signed_response.ParseFromString(signed_response_str)) {
|
|
||||||
LOG(ERROR) << "Failed to deserialize signed response";
|
// Request entitlement keys.
|
||||||
return -1;
|
std::string signed_response_str;
|
||||||
|
status = key_fetcher.MakeHttpRequest(request_str, &signed_response_str);
|
||||||
|
if (!status.ok()) {
|
||||||
|
std::cerr << "Failed to request entitlement key, error: " << status
|
||||||
|
<< std::endl;
|
||||||
}
|
}
|
||||||
LOG(INFO) << "Signed response: " << signed_response.ShortDebugString();
|
std::cout << "Response: " << signed_response_str << std::endl;
|
||||||
widevine::CasEncryptionResponse response;
|
|
||||||
if (!response.ParseFromString(signed_response.response())) {
|
// Parse entitlement key response.
|
||||||
LOG(ERROR) << "Failed to deserialize response";
|
std::vector<widevine::cas::EntitlementKeyInfo> entitlements;
|
||||||
return -1;
|
status =
|
||||||
|
key_fetcher.ParseEntitlementResponse(signed_response_str, &entitlements);
|
||||||
|
if (!status.ok()) {
|
||||||
|
std::cerr << "Failed to parse entitlement response, error: " << status
|
||||||
|
<< std::endl;
|
||||||
}
|
}
|
||||||
LOG(INFO) << "Response: " << response.ShortDebugString();
|
std::cout << "Parsed: " << entitlements.size() << " entitlement keys."
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -14,7 +14,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include "media_cas_packager_sdk/public/wv_cas_types.h"
|
#include "common/status.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
namespace cas {
|
namespace cas {
|
||||||
@@ -55,8 +55,9 @@ class WvCasCaDescriptor {
|
|||||||
// section (for an EMM stream) or into a TS Program Map Table section (for an
|
// section (for an EMM stream) or into a TS Program Map Table section (for an
|
||||||
// ECM stream). The descriptor will be 6 bytes plus any bytes added as
|
// ECM stream). The descriptor will be 6 bytes plus any bytes added as
|
||||||
// (user-defined) private data.
|
// (user-defined) private data.
|
||||||
virtual WvCasStatus GenerateCaDescriptor(
|
virtual Status GenerateCaDescriptor(uint16_t ca_pid,
|
||||||
uint16_t ca_pid, const std::string& provider, const std::string& content_id,
|
const std::string& provider,
|
||||||
|
const std::string& content_id,
|
||||||
std::string* serialized_ca_desc) const;
|
std::string* serialized_ca_desc) const;
|
||||||
|
|
||||||
// Return the base size (before private data is added) of the CA
|
// Return the base size (before private data is added) of the CA
|
||||||
|
|||||||
61
media_cas_packager_sdk/public/wv_cas_curl_key_fetcher.cc
Normal file
61
media_cas_packager_sdk/public/wv_cas_curl_key_fetcher.cc
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright 2020 Google LLC.
|
||||||
|
//
|
||||||
|
// This software is licensed under the terms defined in the Widevine Master
|
||||||
|
// License Agreement. For a copy of this agreement, please contact
|
||||||
|
// widevine-licensing@google.com.
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "media_cas_packager_sdk/public/wv_cas_curl_key_fetcher.h"
|
||||||
|
|
||||||
|
#include "absl/strings/str_cat.h"
|
||||||
|
#include "absl/strings/string_view.h"
|
||||||
|
#include "curl/curl.h"
|
||||||
|
#include "curl/easy.h"
|
||||||
|
|
||||||
|
namespace widevine {
|
||||||
|
namespace cas {
|
||||||
|
|
||||||
|
size_t AppendToString(void* ptr, size_t size, size_t count,
|
||||||
|
std::string* output) {
|
||||||
|
const absl::string_view data(static_cast<char*>(ptr), size * count);
|
||||||
|
absl::StrAppend(output, data);
|
||||||
|
return data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
Status WvCasCurlKeyFetcher::MakeHttpRequest(
|
||||||
|
const std::string& signed_request_json,
|
||||||
|
std::string* http_response_json) const {
|
||||||
|
if (license_server_.empty()) {
|
||||||
|
return Status(error::NOT_FOUND, "license_server is empty");
|
||||||
|
}
|
||||||
|
if (http_response_json == nullptr) {
|
||||||
|
return Status(error::INVALID_ARGUMENT, "http_response_json is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
CURL* curl;
|
||||||
|
CURLcode curl_code;
|
||||||
|
curl = curl_easy_init();
|
||||||
|
if (curl) {
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, license_server_.c_str());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, signed_request_json.c_str());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, http_response_json);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &AppendToString);
|
||||||
|
// If we don't provide POSTFIELDSIZE, libcurl will strlen() by itself.
|
||||||
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE,
|
||||||
|
(int64_t)strlen(signed_request_json.c_str()));
|
||||||
|
curl_code = curl_easy_perform(curl);
|
||||||
|
if (curl_code != CURLE_OK) {
|
||||||
|
return Status(error::INTERNAL,
|
||||||
|
"curl_easy_perform() failed: " +
|
||||||
|
std::string(curl_easy_strerror(curl_code)));
|
||||||
|
}
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
} else {
|
||||||
|
return Status(error::INTERNAL, "curl_easy_init() failed");
|
||||||
|
}
|
||||||
|
return OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace cas
|
||||||
|
} // namespace widevine
|
||||||
39
media_cas_packager_sdk/public/wv_cas_curl_key_fetcher.h
Normal file
39
media_cas_packager_sdk/public/wv_cas_curl_key_fetcher.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright 2020 Google LLC.
|
||||||
|
//
|
||||||
|
// This software is licensed under the terms defined in the Widevine Master
|
||||||
|
// License Agreement. For a copy of this agreement, please contact
|
||||||
|
// widevine-licensing@google.com.
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_CURL_KEY_FETCHER_H_
|
||||||
|
#define MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_CURL_KEY_FETCHER_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "common/status.h"
|
||||||
|
#include "media_cas_packager_sdk/public/wv_cas_key_fetcher.h"
|
||||||
|
|
||||||
|
namespace widevine {
|
||||||
|
namespace cas {
|
||||||
|
|
||||||
|
class WvCasCurlKeyFetcher : public WvCasKeyFetcher {
|
||||||
|
public:
|
||||||
|
WvCasCurlKeyFetcher(const std::string& license_server,
|
||||||
|
const std::string& signing_provider,
|
||||||
|
const std::string& signing_key,
|
||||||
|
const std::string& signing_iv)
|
||||||
|
: WvCasKeyFetcher(signing_provider, signing_key, signing_iv),
|
||||||
|
license_server_(license_server) {}
|
||||||
|
|
||||||
|
Status MakeHttpRequest(const std::string& signed_request_json,
|
||||||
|
std::string* http_response_json) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string license_server_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace cas
|
||||||
|
} // namespace widevine
|
||||||
|
|
||||||
|
#endif // MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_CURL_KEY_FETCHER_H_
|
||||||
@@ -10,102 +10,91 @@
|
|||||||
#define MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_ECM_H_
|
#define MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_ECM_H_
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include "common/status.h"
|
||||||
#include "media_cas_packager_sdk/public/wv_cas_types.h"
|
#include "media_cas_packager_sdk/public/wv_cas_types.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
namespace cas {
|
namespace cas {
|
||||||
|
|
||||||
|
// Information needed to generate content key portion of ECM.
|
||||||
|
// Fields:
|
||||||
|
// |key_id| key ID for the content key, must be 16 bytes.
|
||||||
|
// |key| content key value (aka control word), must be 16 bytes. It will be
|
||||||
|
// wrapped (encrypted) by corresponding entitlement key (decided by track
|
||||||
|
// type), together with |wrapped_key_iv| as the initial vector.
|
||||||
|
// |content_iv| content initial vector, must be 8 or 16 bytes. It is used for
|
||||||
|
// decrypting the content stream.
|
||||||
|
// |wrapped_key_iv| must be 16 bytes. It is used to encrypt |key|.
|
||||||
|
struct WvCasContentKeyInfo {
|
||||||
|
std::string key_id;
|
||||||
|
std::string key;
|
||||||
|
std::string content_iv;
|
||||||
|
std::string wrapped_key_iv;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Information needed to start a new ECM stream.
|
||||||
|
// Fields:
|
||||||
|
// |content_iv_size| size of all content key IVs in the ECM stream.
|
||||||
|
// A constant of type EcmIvSize specifying 8 or 16.
|
||||||
|
// |key_rotation_enabled| the encryption uses multiple keys in rotation.
|
||||||
|
// |crypto_mode| the encryption mode used for the content stream.
|
||||||
|
// A constant of type CryptoMode.
|
||||||
|
// |age_restriction| minimum age required; the value represents actual age.
|
||||||
|
struct WvCasEcmParameters {
|
||||||
|
EcmIvSize content_iv_size = kIvSize8;
|
||||||
|
bool key_rotation_enabled = true;
|
||||||
|
CryptoMode crypto_mode = CryptoMode::kAesCtr;
|
||||||
|
uint8_t age_restriction = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// Class for generating Widevine CAS ECMs.
|
// Class for generating Widevine CAS ECMs.
|
||||||
// See wv_cas_ecm_test.cc for example usage.
|
// See wv_cas_ecm_test.cc for example usage.
|
||||||
// This class is NOT thread-safe.
|
// This class is NOT thread-safe.
|
||||||
class WvCasEcm {
|
class WvCasEcm {
|
||||||
public:
|
public:
|
||||||
WvCasEcm() = default;
|
// Construct of class WvCasEcm.
|
||||||
|
// Args:
|
||||||
|
// |ecm_init_parameters| encryption-related parameters for configuring
|
||||||
|
// the ECM stream.
|
||||||
|
// |injected_entitlement| entitlement key info. May be fetched from the server
|
||||||
|
// with WvCasKeyFetcher.
|
||||||
|
WvCasEcm(const WvCasEcmParameters& ecm_parameters,
|
||||||
|
const std::vector<EntitlementKeyInfo>& injected_entitlements);
|
||||||
WvCasEcm(const WvCasEcm&) = delete;
|
WvCasEcm(const WvCasEcm&) = delete;
|
||||||
WvCasEcm& operator=(const WvCasEcm&) = delete;
|
WvCasEcm& operator=(const WvCasEcm&) = delete;
|
||||||
virtual ~WvCasEcm() = default;
|
virtual ~WvCasEcm() = default;
|
||||||
|
|
||||||
// Initialize an instance of this class.
|
// Accept keys and IVs and construct an ECM that will fit into a Transport
|
||||||
//
|
// Stream packet payload (184 bytes).
|
||||||
// Args:
|
// Args:
|
||||||
// - |content_iv_size| iv size in bytes for encrypting the content,
|
// |even_key| information for even key to be encoded into ECM.
|
||||||
// only support 8 bytes or 16 bytes
|
// |odd_key| information for odd key to be encoded into ECM.
|
||||||
// When using 8 bytes content_iv, we assume additional 8 bytes of '\x00' are
|
// |track_type| the track that the keys are being used to encrypt.
|
||||||
// appended to the iv to form a 16 bytes AES IV when content is encrypted.
|
// |serialized_ecm| caller-supplied std::string pointer to receive the ECM.
|
||||||
// - |key_rotation_enabled| whether key rotation is enabled,
|
// The |even_key| and |odd_key| contents (specifically IV sizes) must be
|
||||||
// if this is 'true' only subsequent call to GenerateEcm will be allowed,
|
// consistent with the initialized settings.
|
||||||
// if this is 'false' only subsequent call to GenerateSingleKeyEcm will
|
// The even_key and odd_key will be wrapped using the appropriate
|
||||||
// be allowed
|
// entitlement key. Wrapping modifies the original structure.
|
||||||
// - |crypto_mode| crypto mode for encrypting content
|
virtual Status GenerateEcm(const WvCasContentKeyInfo& even_key,
|
||||||
//
|
const WvCasContentKeyInfo& odd_key,
|
||||||
// Returns:
|
const std::string& track_type,
|
||||||
// - A status indicating whether there was any error during initialization
|
std::string* serialized_ecm) const;
|
||||||
//
|
|
||||||
// Note:
|
|
||||||
// - 'even'/'odd' key in the ECM will be be encrypted using AEC_CBC
|
|
||||||
virtual WvCasStatus Initialize(int content_iv_size, bool key_rotation_enabled,
|
|
||||||
CryptoMode crypto_mode);
|
|
||||||
|
|
||||||
// Generate an ECM containing two keys (even and odd). Can be called when
|
// Accept a key and IV and construct an ECM that will fit into a Transport
|
||||||
// |key_rotation_enabled| is initialized to 'true'.
|
// Stream packet payload (184 bytes). This call is specifically for the case
|
||||||
//
|
// where key rotation is disabled.
|
||||||
// Args (all pointer parameters must be not nullptr):
|
// Args:
|
||||||
// - |even_key| clear even content key, must be 8 bytes for kDvbCsa2,
|
// |key| information for key to be encoded into ECM.
|
||||||
// 16 bytes for kAesCtr or kAesCbc
|
// |track_type| the track that the key is being used to encrypt.
|
||||||
// - |even_content_iv| iv used along with |even_key| for encrypting content,
|
// |serialized_ecm| caller-supplied std::string pointer to receive the ECM.
|
||||||
// length must match |content_iv_size| set during initialization
|
// The |key| contents (specifically IV sizes) must be consistent
|
||||||
// - |even_entitlement_key_id| key id for |even_entitlement_key|,
|
// with the initialized settings.
|
||||||
// must be 16 bytes length
|
virtual Status GenerateSingleKeyEcm(const WvCasContentKeyInfo& key,
|
||||||
// - |even_entitlement_key| entitlement key used to encrypt even key,
|
const std::string& track_type,
|
||||||
// must be 32 bytes length
|
std::string* serialized_ecm) const;
|
||||||
// - |odd_key| clear odd content key, must be 8 bytes for kDvbCsa2,
|
|
||||||
// 16 bytes for kAesCtr or kAesCbc
|
|
||||||
// - |odd_content_iv| iv used along with |odd_key| for encrypting content,
|
|
||||||
// length must match |content_iv_size| set during initialization
|
|
||||||
// - |odd_entitlement_key_id| key id for |odd_entitlement_key|,
|
|
||||||
// must be 16 bytes length
|
|
||||||
// - |odd_entitlement_key| entitlement key used to encrypt odd key,
|
|
||||||
// must be 32 bytes length
|
|
||||||
// - |ecm| for returning the generated ECM,
|
|
||||||
// size of the generated ecm is 149 bytes when content iv is 8 bytes
|
|
||||||
// 165 bytes when content iv is 16 bytes
|
|
||||||
//
|
|
||||||
// Returns:
|
|
||||||
// - A status indicating whether there was any error during processing
|
|
||||||
virtual WvCasStatus GenerateEcm(const char* const even_key,
|
|
||||||
const char* const even_content_iv,
|
|
||||||
const char* const even_entitlement_key_id,
|
|
||||||
const char* const even_entitlement_key,
|
|
||||||
const char* const odd_key,
|
|
||||||
const char* const odd_content_iv,
|
|
||||||
const char* const odd_entitlement_key_id,
|
|
||||||
const char* const odd_entitlement_key,
|
|
||||||
std::string* ecm) const;
|
|
||||||
|
|
||||||
// Generate an ECM containing only a singe even key. Can be called when
|
|
||||||
// |key_rotation_enabled| is initialized to 'false'.
|
|
||||||
//
|
|
||||||
// Args (all pointer parameters must be not nullptr):
|
|
||||||
// - |even_key| clear even content key, must be 8 bytes for kDvbCsa2,
|
|
||||||
// 16 bytes for kAesCtr or kAesCbc
|
|
||||||
// - |even_content_iv| iv used along with |even_key| for encrypting content,
|
|
||||||
// length must match |content_iv_size| set during initialization
|
|
||||||
// - |even_entitlement_key_id| key id for |even_entitlement_key|,
|
|
||||||
// must be 16 bytes length
|
|
||||||
// - |even_entitlement_key| entitlement key used to encrypt even key,
|
|
||||||
// must be 32 bytes length
|
|
||||||
// - |ecm| for returning the generated ECM,
|
|
||||||
// size of the generated ecm is 77 bytes when content iv is 8 bytes
|
|
||||||
// 85 bytes when content iv is 16 bytes
|
|
||||||
//
|
|
||||||
// Returns:
|
|
||||||
// - A status indicating whether there was any error during processing
|
|
||||||
virtual WvCasStatus GenerateSingleKeyEcm(
|
|
||||||
const char* const even_key, const char* const even_content_iv,
|
|
||||||
const char* const even_entitlement_key_id,
|
|
||||||
const char* const even_entitlement_key, std::string* ecm) const;
|
|
||||||
|
|
||||||
// Generate a TS packet with the given |ecm| as payload.
|
// Generate a TS packet with the given |ecm| as payload.
|
||||||
//
|
//
|
||||||
@@ -125,16 +114,13 @@ class WvCasEcm {
|
|||||||
//
|
//
|
||||||
// Returns:
|
// Returns:
|
||||||
// - A status indicating whether there was any error during processing
|
// - A status indicating whether there was any error during processing
|
||||||
virtual WvCasStatus GenerateTsPacket(const std::string& ecm, uint16_t pid,
|
static Status GenerateTsPacket(const std::string& ecm, uint16_t pid,
|
||||||
uint8_t table_id,
|
uint8_t table_id, uint8_t* continuity_counter,
|
||||||
uint8_t* continuity_counter,
|
uint8_t* packet);
|
||||||
uint8_t* packet) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool initialized_ = false;
|
WvCasEcmParameters ecm_param_;
|
||||||
int content_iv_size_;
|
std::vector<EntitlementKeyInfo> injected_entitlements_;
|
||||||
bool key_rotation_enabled_;
|
|
||||||
CryptoMode crypto_mode_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace cas
|
} // namespace cas
|
||||||
|
|||||||
@@ -1,160 +0,0 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Copyright 2018 Google LLC.
|
|
||||||
//
|
|
||||||
// This software is licensed under the terms defined in the Widevine Master
|
|
||||||
// License Agreement. For a copy of this agreement, please contact
|
|
||||||
// widevine-licensing@google.com.
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#include "media_cas_packager_sdk/public/wv_cas_key_fetcher.h"
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include "glog/logging.h"
|
|
||||||
#include "google/protobuf/util/json_util.h"
|
|
||||||
#include "absl/flags/flag.h"
|
|
||||||
#include "absl/strings/escaping.h"
|
|
||||||
#include "absl/strings/str_cat.h"
|
|
||||||
#include "absl/strings/string_view.h"
|
|
||||||
#include "curl/curl.h"
|
|
||||||
#include "curl/easy.h"
|
|
||||||
#include "common/signature_util.h"
|
|
||||||
#include "common/status.h"
|
|
||||||
#include "protos/public/media_cas_encryption.pb.h"
|
|
||||||
|
|
||||||
using google::protobuf::util::JsonPrintOptions;
|
|
||||||
using google::protobuf::util::JsonStringToMessage;
|
|
||||||
using google::protobuf::util::MessageToJsonString;
|
|
||||||
|
|
||||||
ABSL_FLAG(std::string, license_server, "",
|
|
||||||
"HTTP URL to the license server for making CAS encryption request.");
|
|
||||||
ABSL_FLAG(std::string, signing_provider, "",
|
|
||||||
"Name of the provider signing the CAS encryption request.");
|
|
||||||
ABSL_FLAG(std::string, signing_key, "",
|
|
||||||
"AES key (in hex) for signing the CAS encryption request.");
|
|
||||||
ABSL_FLAG(std::string, signing_iv, "",
|
|
||||||
"AES iv (in hex) for signing the CAS encryption request.");
|
|
||||||
|
|
||||||
namespace widevine {
|
|
||||||
namespace cas {
|
|
||||||
|
|
||||||
Status WvCasKeyFetcher::RequestEntitlementKey(
|
|
||||||
const std::string& request_string,
|
|
||||||
std::string* signed_response_string) const {
|
|
||||||
if (absl::GetFlag(FLAGS_signing_provider).empty() ||
|
|
||||||
absl::GetFlag(FLAGS_signing_key).empty() ||
|
|
||||||
absl::GetFlag(FLAGS_signing_iv).empty()) {
|
|
||||||
return Status(
|
|
||||||
error::INVALID_ARGUMENT,
|
|
||||||
"Flag 'signing_provider', 'signing_key' or 'signing_iv' is empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Processes request.
|
|
||||||
CasEncryptionRequest request;
|
|
||||||
request.ParseFromString(request_string);
|
|
||||||
std::string request_json;
|
|
||||||
JsonPrintOptions print_options;
|
|
||||||
// Set this option so that the json output is
|
|
||||||
// {"content_id":"MjExNDA4NDQ=", ...
|
|
||||||
// instead of
|
|
||||||
// {"contentId":"MjExNDA4NDQ=", ...
|
|
||||||
print_options.preserve_proto_field_names = true;
|
|
||||||
// NOTE: MessageToJsonString will automatically converts 'bytes' type fields
|
|
||||||
// to base64. For example content ID '21140844' becomes 'MjExNDA4NDQ='.
|
|
||||||
if (!MessageToJsonString(request, &request_json, print_options).ok()) {
|
|
||||||
return Status(error::INTERNAL,
|
|
||||||
"Failed to convert request message to json.");
|
|
||||||
}
|
|
||||||
LOG(INFO) << "Json CasEncryptionRequest: " << request_json;
|
|
||||||
|
|
||||||
// Creates signed request.
|
|
||||||
SignedCasEncryptionRequest signed_request;
|
|
||||||
signed_request.set_request(request_json);
|
|
||||||
std::string signature;
|
|
||||||
if (!signature_util::GenerateAesSignature(
|
|
||||||
request_json,
|
|
||||||
absl::HexStringToBytes(absl::GetFlag(FLAGS_signing_key)),
|
|
||||||
absl::HexStringToBytes(absl::GetFlag(FLAGS_signing_iv)), &signature)
|
|
||||||
.ok()) {
|
|
||||||
return Status(error::INTERNAL, "Failed to sign the request.");
|
|
||||||
}
|
|
||||||
signed_request.set_signature(signature);
|
|
||||||
signed_request.set_signer(absl::GetFlag(FLAGS_signing_provider));
|
|
||||||
std::string signed_request_json;
|
|
||||||
// NOTE: MessageToJsonString will automatically converts the 'request' and
|
|
||||||
// 'signature' fields in SignedCasEncryptionRequest to base64, because they
|
|
||||||
// are of type 'bytes'.
|
|
||||||
if (!MessageToJsonString(signed_request, &signed_request_json).ok()) {
|
|
||||||
return Status(error::INTERNAL,
|
|
||||||
"Failed to convert signed request message to json.");
|
|
||||||
}
|
|
||||||
LOG(INFO) << "Json SignedCasEncryptionRequest: " << signed_request_json;
|
|
||||||
|
|
||||||
// Makes HTTP request against License Server.
|
|
||||||
std::string http_response_json;
|
|
||||||
Status status = MakeHttpRequest(signed_request_json, &http_response_json);
|
|
||||||
if (!status.ok()) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
LOG(INFO) << "Json HTTP response: " << http_response_json;
|
|
||||||
HttpResponse http_response;
|
|
||||||
if (!JsonStringToMessage(http_response_json, &http_response).ok()) {
|
|
||||||
return Status(error::INTERNAL,
|
|
||||||
"Failed to convert http response json to message.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Processes signed response.
|
|
||||||
LOG(INFO) << "Json CasEncryptionResponse: " << http_response.response();
|
|
||||||
CasEncryptionResponse response;
|
|
||||||
if (!JsonStringToMessage(http_response.response(), &response).ok()) {
|
|
||||||
return Status(error::INTERNAL,
|
|
||||||
"Failed to convert response json to message.");
|
|
||||||
}
|
|
||||||
SignedCasEncryptionResponse signed_response;
|
|
||||||
signed_response.set_response(response.SerializeAsString());
|
|
||||||
signed_response.SerializeToString(signed_response_string);
|
|
||||||
return OkStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t AppendToString(void* ptr, size_t size, size_t count,
|
|
||||||
std::string* output) {
|
|
||||||
const absl::string_view data(static_cast<char*>(ptr), size * count);
|
|
||||||
absl::StrAppend(output, data);
|
|
||||||
return data.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
Status WvCasKeyFetcher::MakeHttpRequest(const std::string& signed_request_json,
|
|
||||||
std::string* http_response_json) const {
|
|
||||||
CHECK(http_response_json);
|
|
||||||
if (absl::GetFlag(FLAGS_license_server).empty()) {
|
|
||||||
return Status(error::INVALID_ARGUMENT, "Flag 'license_server' is empty");
|
|
||||||
}
|
|
||||||
CURL* curl;
|
|
||||||
CURLcode curl_code;
|
|
||||||
curl = curl_easy_init();
|
|
||||||
if (curl) {
|
|
||||||
curl_easy_setopt(curl, CURLOPT_URL,
|
|
||||||
absl::GetFlag(FLAGS_license_server).c_str());
|
|
||||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, signed_request_json.c_str());
|
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, http_response_json);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &AppendToString);
|
|
||||||
// If we don't provide POSTFIELDSIZE, libcurl will strlen() by itself.
|
|
||||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE,
|
|
||||||
(int64_t)strlen(signed_request_json.c_str()));
|
|
||||||
curl_code = curl_easy_perform(curl);
|
|
||||||
if (curl_code != CURLE_OK) {
|
|
||||||
return Status(error::INTERNAL,
|
|
||||||
"curl_easy_perform() failed: " +
|
|
||||||
std::string(curl_easy_strerror(curl_code)));
|
|
||||||
}
|
|
||||||
curl_easy_cleanup(curl);
|
|
||||||
} else {
|
|
||||||
return Status(error::INTERNAL, "curl_easy_init() failed");
|
|
||||||
}
|
|
||||||
return OkStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace cas
|
|
||||||
} // namespace widevine
|
|
||||||
@@ -11,50 +11,86 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "absl/flags/declare.h"
|
|
||||||
#include "common/status.h"
|
#include "common/status.h"
|
||||||
#include "media_cas_packager_sdk/internal/key_fetcher.h"
|
#include "media_cas_packager_sdk/public/wv_cas_types.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
namespace cas {
|
namespace cas {
|
||||||
|
|
||||||
|
// Paramerters that are needed to construct an entitlement key rquest message.
|
||||||
|
// Fields:
|
||||||
|
// |content_id| uniquely identifies the content (with |content_provider|)
|
||||||
|
// |content_provider| unique std::string for provider of the content stream.
|
||||||
|
// |track_types| a vector of track ID (std::string) that specify the set of track
|
||||||
|
// types of interest; controls the entitlement keys returned by the
|
||||||
|
// server.
|
||||||
|
// |key_rotation| the encryption uses two keys if set. Two entitlement keys
|
||||||
|
// are requested for each track type.
|
||||||
|
struct EntitlementRequestParams {
|
||||||
|
std::string content_id;
|
||||||
|
std::string content_provider;
|
||||||
|
std::vector<std::string> track_types;
|
||||||
|
bool key_rotation;
|
||||||
|
};
|
||||||
|
|
||||||
// WV CAS KeyFetcher. Performs the communication with the Widevine License
|
// WV CAS KeyFetcher. Performs the communication with the Widevine License
|
||||||
// Server to get entitlement keys on behalf of a WvCasEcm object.
|
// Server to get entitlement keys on behalf of a WvCasEcm object.
|
||||||
class WvCasKeyFetcher : public KeyFetcher {
|
class WvCasKeyFetcher {
|
||||||
public:
|
public:
|
||||||
WvCasKeyFetcher() = default;
|
// Initialize an WvCasKeyFetcher object with required infomartion.
|
||||||
|
// Args:
|
||||||
|
// |signing_provider| name of the provider signing the CAS encryption
|
||||||
|
// request.
|
||||||
|
// |signing_key| AES key (in hex) for signing the CAS encryption request.
|
||||||
|
// |signing_iv| AES iv (in hex) for signing the CAS encryption request.
|
||||||
|
WvCasKeyFetcher(const std::string& signing_provider,
|
||||||
|
const std::string& signing_key,
|
||||||
|
const std::string& signing_iv);
|
||||||
WvCasKeyFetcher(const WvCasKeyFetcher&) = delete;
|
WvCasKeyFetcher(const WvCasKeyFetcher&) = delete;
|
||||||
WvCasKeyFetcher& operator=(const WvCasKeyFetcher&) = delete;
|
WvCasKeyFetcher& operator=(const WvCasKeyFetcher&) = delete;
|
||||||
~WvCasKeyFetcher() override = default;
|
virtual ~WvCasKeyFetcher() = default;
|
||||||
|
|
||||||
// Get entitlement keys from the license server. Send a
|
// Create a SignedCasEncryptionRequest message that can be used to request
|
||||||
// SignedCasEncryptionRequest message to the license server, receive a
|
// entitlement keys from a server.
|
||||||
// SignedCasEncryptionResponse and return it to the caller.
|
|
||||||
// Args:
|
// Args:
|
||||||
// |request_string| a serialized CasEncryptionRequest message, produced
|
// |request_params| paramerters that are needed to request entitlement keys
|
||||||
// by WvCasEcm::Initialize().
|
// from the server.
|
||||||
// |signed_response_string| a serialized SignedCasEncryptionResponse
|
// |signed_request_json| the created serialized SignedCasEncryptionRequest
|
||||||
// message. It should be passed into
|
// message.
|
||||||
// widevine::cas::Ecm::ProcessCasEncryptionResponse().
|
virtual Status CreateEntitlementRequest(
|
||||||
Status RequestEntitlementKey(
|
const EntitlementRequestParams& request_params,
|
||||||
const std::string& request_string,
|
std::string* signed_request_json) const;
|
||||||
std::string* signed_response_string) const override;
|
|
||||||
|
// Parse a CasEncryptionResponse message holding the entitlement keys for
|
||||||
|
// generating the ECM stream. The entitlement keys are used to encrypt the
|
||||||
|
// keys conveyed in the ECM. The entitlement key IDs are also part of the ECM.
|
||||||
|
// Args:
|
||||||
|
// |response_string| a serialized CasEncryptionRequest message from the server
|
||||||
|
// holding entitlement key information (or error information).
|
||||||
|
// |entitlements| a pointer holding the resulting entitlement keys parsed from
|
||||||
|
// the response string.
|
||||||
|
static Status ParseEntitlementResponse(
|
||||||
|
const std::string& http_response_json,
|
||||||
|
std::vector<EntitlementKeyInfo>* entitlements);
|
||||||
|
|
||||||
protected:
|
|
||||||
// Makes a HTTP request to License Server for entitlement key(s).
|
// Makes a HTTP request to License Server for entitlement key(s).
|
||||||
// Returns the HTTP response in Json format in |http_response_json|.
|
// Returns the HTTP response in Json format in |http_response_json|.
|
||||||
// Protected visibility to support unit testing.
|
|
||||||
virtual Status MakeHttpRequest(const std::string& signed_request_json,
|
virtual Status MakeHttpRequest(const std::string& signed_request_json,
|
||||||
std::string* http_response_json) const;
|
std::string* http_response_json) const = 0;
|
||||||
|
|
||||||
|
// Conventient function that calls CreateEntitlementRequest,
|
||||||
|
// MakeHttpRequest, and ParseEntitlementResponse in sequence.
|
||||||
|
virtual Status FetchEntitlements(
|
||||||
|
const EntitlementRequestParams& request_params,
|
||||||
|
std::vector<EntitlementKeyInfo>* entitlements) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string signing_provider_;
|
||||||
|
std::string signing_key_;
|
||||||
|
std::string signing_iv_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace cas
|
} // namespace cas
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
|
|
||||||
// Exposed for testing and example.
|
|
||||||
ABSL_DECLARE_FLAG(std::string, license_server);
|
|
||||||
ABSL_DECLARE_FLAG(std::string, signing_provider);
|
|
||||||
ABSL_DECLARE_FLAG(std::string, signing_key);
|
|
||||||
ABSL_DECLARE_FLAG(std::string, signing_iv);
|
|
||||||
|
|
||||||
#endif // MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_KEY_FETCHER_H_
|
#endif // MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_KEY_FETCHER_H_
|
||||||
|
|||||||
@@ -20,30 +20,6 @@ using google::protobuf::util::MessageToJsonString;
|
|||||||
namespace widevine {
|
namespace widevine {
|
||||||
namespace cas {
|
namespace cas {
|
||||||
|
|
||||||
static const char* kWvCasStatusMessage[] = {
|
|
||||||
"OK", // OK = 0,
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
"Invalid argument", // INVALID_ARGUMENT = 3,
|
|
||||||
"",
|
|
||||||
"Not found", // NOT_FOUND = 5,
|
|
||||||
"Already exists", // ALREADY_EXISTS = 6,
|
|
||||||
"Permission denied", // PERMISSION_DENIED = 7,
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
"Unimplemented", // UNIMPLEMENTED = 12,
|
|
||||||
"Internal", // INTERNAL = 13,
|
|
||||||
"Unavailable", // UNAVAILABLE = 14,
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string GetWvCasStatusMessage(WvCasStatus status) {
|
|
||||||
static_assert(arraysize(kWvCasStatusMessage) == NUM_WV_CAS_STATUS,
|
|
||||||
"mismatching status message and status.");
|
|
||||||
return kWvCasStatusMessage[status];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Numeric value of crypto mode is the index into strings array.
|
// Numeric value of crypto mode is the index into strings array.
|
||||||
static const char* kCrypoModeStrings[] = {
|
static const char* kCrypoModeStrings[] = {
|
||||||
"AesCbc", "AesCtr", "DvbCsa2", "DvbCsa3", "AesOfb", "AesScte",
|
"AesCbc", "AesCtr", "DvbCsa2", "DvbCsa3", "AesOfb", "AesScte",
|
||||||
@@ -109,8 +85,8 @@ bool StringToScramblingLevel(const std::string& str, ScramblingLevel* mode) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
WvCasStatus CreateWvCasEncryptionRequestJson(
|
Status CreateWvCasEncryptionRequestJson(const WvCasEncryptionRequest& request,
|
||||||
const WvCasEncryptionRequest& request, std::string* request_json) {
|
std::string* request_json) {
|
||||||
CHECK(request_json);
|
CHECK(request_json);
|
||||||
|
|
||||||
CasEncryptionRequest request_proto;
|
CasEncryptionRequest request_proto;
|
||||||
@@ -131,14 +107,14 @@ WvCasStatus CreateWvCasEncryptionRequestJson(
|
|||||||
// to base64. For example content ID '21140844' becomes 'MjExNDA4NDQ='.
|
// to base64. For example content ID '21140844' becomes 'MjExNDA4NDQ='.
|
||||||
if (!MessageToJsonString(request_proto, request_json, print_options).ok()) {
|
if (!MessageToJsonString(request_proto, request_json, print_options).ok()) {
|
||||||
LOG(ERROR) << "Failed to convert request message to json.";
|
LOG(ERROR) << "Failed to convert request message to json.";
|
||||||
return INTERNAL;
|
return Status(error::INTERNAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
return OK;
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
WvCasStatus ParseWvCasEncryptionResponseJson(
|
Status ParseWvCasEncryptionResponseJson(const std::string& response_json,
|
||||||
const std::string& response_json, WvCasEncryptionResponse* response) {
|
WvCasEncryptionResponse* response) {
|
||||||
CHECK(response);
|
CHECK(response);
|
||||||
|
|
||||||
CasEncryptionResponse response_proto;
|
CasEncryptionResponse response_proto;
|
||||||
@@ -146,7 +122,7 @@ WvCasStatus ParseWvCasEncryptionResponseJson(
|
|||||||
// 'bytes' type fields.
|
// 'bytes' type fields.
|
||||||
if (!JsonStringToMessage(response_json, &response_proto).ok()) {
|
if (!JsonStringToMessage(response_json, &response_proto).ok()) {
|
||||||
LOG(ERROR) << "Failed to convert response json to message.";
|
LOG(ERROR) << "Failed to convert response json to message.";
|
||||||
return INTERNAL;
|
return Status(error::INTERNAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
response->status =
|
response->status =
|
||||||
@@ -163,7 +139,7 @@ WvCasStatus ParseWvCasEncryptionResponseJson(
|
|||||||
response->entitlement_keys.push_back(key_info);
|
response->entitlement_keys.push_back(key_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
return OK;
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace cas
|
} // namespace cas
|
||||||
|
|||||||
@@ -12,45 +12,11 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/status.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
namespace cas {
|
namespace cas {
|
||||||
|
|
||||||
enum WvCasStatus {
|
|
||||||
// Success.
|
|
||||||
OK = 0,
|
|
||||||
|
|
||||||
// Client specified an invalid argument.
|
|
||||||
INVALID_ARGUMENT = 3,
|
|
||||||
|
|
||||||
// Some requested entity (e.g., file or directory) was not found.
|
|
||||||
NOT_FOUND = 5,
|
|
||||||
|
|
||||||
// Some entity that we attempted to create (e.g., file or directory)
|
|
||||||
// already exists.
|
|
||||||
ALREADY_EXISTS = 6,
|
|
||||||
|
|
||||||
// The caller does not have permission to execute the specified
|
|
||||||
// operation.
|
|
||||||
PERMISSION_DENIED = 7,
|
|
||||||
|
|
||||||
// Operation is not implemented or not supported/enabled in this service.
|
|
||||||
UNIMPLEMENTED = 12,
|
|
||||||
|
|
||||||
// Internal errors. Means some invariants expected by underlying
|
|
||||||
// system has been broken. If you see one of these errors,
|
|
||||||
// something is very broken.
|
|
||||||
INTERNAL = 13,
|
|
||||||
|
|
||||||
// Operation is not implemented or not supported/enabled in this service.
|
|
||||||
UNAVAILABLE = 14,
|
|
||||||
|
|
||||||
// Number of errors.
|
|
||||||
NUM_WV_CAS_STATUS,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Returns the message std::string for the given WvCasStatus.
|
|
||||||
std::string GetWvCasStatusMessage(WvCasStatus status);
|
|
||||||
|
|
||||||
// Crypto mode for encryption / decryption. ENUM value should be consistent with
|
// Crypto mode for encryption / decryption. ENUM value should be consistent with
|
||||||
// ECM V2 definition. Largest supported value for this CryptoMode ENUM is 15.
|
// ECM V2 definition. Largest supported value for this CryptoMode ENUM is 15.
|
||||||
enum class CryptoMode : int {
|
enum class CryptoMode : int {
|
||||||
@@ -77,6 +43,28 @@ bool ScramblingLevelToString(ScramblingLevel mode, std::string* str);
|
|||||||
// Returns false if str is not a valid ScramblingLevel.
|
// Returns false if str is not a valid ScramblingLevel.
|
||||||
bool StringToScramblingLevel(const std::string& str, ScramblingLevel* mode);
|
bool StringToScramblingLevel(const std::string& str, ScramblingLevel* mode);
|
||||||
|
|
||||||
|
// Declare Content IV size in an ECM stream.
|
||||||
|
// Content IVs may be encoded as 8 or 16 random bytes. The receiver is
|
||||||
|
// responsible for appending 8 zeros to an 8-byte IV. All content IVs, once the
|
||||||
|
// size is declared, must be the same size. Wrapped key IVs are always 16 bytes.
|
||||||
|
enum EcmIvSize { kIvSize8 = 0, kIvSize16 = 1 };
|
||||||
|
|
||||||
|
// Information needed for the injected entitlement keys. Used for Ecm
|
||||||
|
// initialization.
|
||||||
|
// Fields:
|
||||||
|
// |track_type| the track that the key is being used to encrypt.
|
||||||
|
// |is_even_key| if true, this entitlement is an even key. For the single key
|
||||||
|
// case (no key rotation), is_even_key is always true.
|
||||||
|
// |key_id| key ID for this entitlement key, must be 16 bytes.
|
||||||
|
// |key_value| entitlement key value, must be 32 bytes. Used to decrypt
|
||||||
|
// content keys.
|
||||||
|
struct EntitlementKeyInfo {
|
||||||
|
std::string track_type;
|
||||||
|
bool is_even_key;
|
||||||
|
std::string key_id; // must be 16 bytes.
|
||||||
|
std::string key_value; // must be 32 bytes.
|
||||||
|
};
|
||||||
|
|
||||||
struct WvCasEncryptionRequest {
|
struct WvCasEncryptionRequest {
|
||||||
std::string content_id;
|
std::string content_id;
|
||||||
std::string provider;
|
std::string provider;
|
||||||
@@ -124,14 +112,14 @@ struct WvCasEncryptionResponse {
|
|||||||
// request JSON message.
|
// request JSON message.
|
||||||
// And that signed JSON message can be sent to Widevine license server for
|
// And that signed JSON message can be sent to Widevine license server for
|
||||||
// acquiring entitlement keys.
|
// acquiring entitlement keys.
|
||||||
WvCasStatus CreateWvCasEncryptionRequestJson(
|
Status CreateWvCasEncryptionRequestJson(const WvCasEncryptionRequest& request,
|
||||||
const WvCasEncryptionRequest& request, std::string* request_json);
|
std::string* request_json);
|
||||||
|
|
||||||
// Parses a WvCasEncryptionResponse in JSON format, returns a
|
// Parses a WvCasEncryptionResponse in JSON format, returns a
|
||||||
// WvCasEncryptionResponse.
|
// WvCasEncryptionResponse.
|
||||||
// |response_json| is supposed to be the 'response' field in the signed
|
// |response_json| is supposed to be the 'response' field in the signed
|
||||||
// response from Widevine license server.
|
// response from Widevine license server.
|
||||||
WvCasStatus ParseWvCasEncryptionResponseJson(const std::string& response_json,
|
Status ParseWvCasEncryptionResponseJson(const std::string& response_json,
|
||||||
WvCasEncryptionResponse* response);
|
WvCasEncryptionResponse* response);
|
||||||
|
|
||||||
} // namespace cas
|
} // namespace cas
|
||||||
|
|||||||
Binary file not shown.
36
protos/public/BUILD
Normal file
36
protos/public/BUILD
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
################################################################################
|
||||||
|
# Copyright 2018 Google LLC.
|
||||||
|
#
|
||||||
|
# This software is licensed under the terms defined in the Widevine Master
|
||||||
|
# License Agreement. For a copy of this agreement, please contact
|
||||||
|
# widevine-licensing@google.com.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
# Protocol buffer definitions for Widevine media cas packager sdk.
|
||||||
|
|
||||||
|
package(default_visibility = ["//visibility:public"])
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "binary_release_files",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
)
|
||||||
|
|
||||||
|
proto_library(
|
||||||
|
name = "media_cas_encryption_proto",
|
||||||
|
srcs = ["media_cas_encryption.proto"],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc_proto_library(
|
||||||
|
name = "media_cas_encryption_cc_proto",
|
||||||
|
deps = [":media_cas_encryption_proto"],
|
||||||
|
)
|
||||||
|
|
||||||
|
proto_library(
|
||||||
|
name = "media_cas_proto",
|
||||||
|
srcs = ["media_cas.proto"],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc_proto_library(
|
||||||
|
name = "media_cas_cc_proto",
|
||||||
|
deps = [":media_cas_proto"],
|
||||||
|
)
|
||||||
21
protos/public/media_cas.proto
Normal file
21
protos/public/media_cas.proto
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright 2018 Google LLC.
|
||||||
|
//
|
||||||
|
// This software is licensed under the terms defined in the Widevine Master
|
||||||
|
// License Agreement. For a copy of this agreement, please contact
|
||||||
|
// widevine-licensing@google.com.
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
package widevine.cas;
|
||||||
|
|
||||||
|
// Widevine private data in the CA descriptor.
|
||||||
|
message CaDescriptorPrivateData {
|
||||||
|
// Provider name.
|
||||||
|
optional string provider = 1;
|
||||||
|
|
||||||
|
// Content ID.
|
||||||
|
optional bytes content_id = 2;
|
||||||
|
}
|
||||||
74
protos/public/media_cas_encryption.proto
Normal file
74
protos/public/media_cas_encryption.proto
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright 2018 Google LLC.
|
||||||
|
//
|
||||||
|
// This software is licensed under the terms defined in the Widevine Master
|
||||||
|
// License Agreement. For a copy of this agreement, please contact
|
||||||
|
// widevine-licensing@google.com.
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Protocol buffer definitions for Widevine CAS.
|
||||||
|
|
||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
package widevine;
|
||||||
|
|
||||||
|
option java_package = "com.google.video.widevine.mediacasencryption";
|
||||||
|
|
||||||
|
message CasEncryptionRequest {
|
||||||
|
optional bytes content_id = 1;
|
||||||
|
optional string provider = 2;
|
||||||
|
// Optional track types such as "AUDIO", SD" or "HD".
|
||||||
|
repeated string track_types = 3;
|
||||||
|
// Indicates if the client is using key rotation. If true, the server will
|
||||||
|
// return one key for EVEN and one key for ODD, otherwise only a single key is
|
||||||
|
// returned.
|
||||||
|
optional bool key_rotation = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CasEncryptionResponse {
|
||||||
|
enum Status {
|
||||||
|
STATUS_UNSPECIFIED = 0;
|
||||||
|
OK = 1;
|
||||||
|
SIGNATURE_FAILED = 2;
|
||||||
|
ACCESS_DENIED = 3;
|
||||||
|
INTERNAL_ERROR = 4;
|
||||||
|
INVALID_ARGUMENT = 5;
|
||||||
|
PROVIDER_ID_MISSING = 6;
|
||||||
|
CONTENT_ID_MISSING = 7;
|
||||||
|
TRACK_TYPE_MISSING = 8;
|
||||||
|
}
|
||||||
|
message KeyInfo {
|
||||||
|
enum KeySlot {
|
||||||
|
KEY_SLOT_UNSPECIFIED = 0;
|
||||||
|
SINGLE = 1;
|
||||||
|
EVEN = 2;
|
||||||
|
ODD = 3;
|
||||||
|
}
|
||||||
|
optional bytes key_id = 1;
|
||||||
|
optional bytes key = 2;
|
||||||
|
// Optional label used for the key.
|
||||||
|
optional string track_type = 3;
|
||||||
|
optional KeySlot key_slot = 4;
|
||||||
|
}
|
||||||
|
optional Status status = 1;
|
||||||
|
optional string status_message = 2;
|
||||||
|
optional bytes content_id = 3;
|
||||||
|
repeated KeyInfo entitlement_keys = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SignedCasEncryptionRequest {
|
||||||
|
optional bytes request = 1;
|
||||||
|
optional bytes signature = 2;
|
||||||
|
// Identifies the entity sending / signing the request.
|
||||||
|
optional string signer = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SignedCasEncryptionResponse {
|
||||||
|
// Serialized CasEncryptionResponse message.
|
||||||
|
optional bytes response = 1;
|
||||||
|
optional bytes signature = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message HttpResponse {
|
||||||
|
optional bytes response = 1;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user