Update to support OEMCrypto v16 with ODK

This commit is contained in:
Widevine Buildbot
2020-09-22 01:38:10 +00:00
parent 9e2d97ce2a
commit 863d114011
53 changed files with 2839 additions and 0 deletions

22
common/certificate_type.h Normal file
View 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_

View File

@@ -0,0 +1,11 @@
################################################################################
# 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.
################################################################################
from "common/certificate_type.h":
namespace `widevine`:
enum CertificateType

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
intermediate_passphrase

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
provider_passphrase

Binary file not shown.

View File

@@ -0,0 +1,4 @@
Twas bryllyg, and ye slythy toves
Did gyre and gymble in ye wabe:
All mimsy were ye borogoves;
And ye mome raths outgrabe.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
service_passphrase

Binary file not shown.

View File

@@ -0,0 +1,113 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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 <stddef.h>
#include <stdio.h>
#include <iostream>
#include <memory>
#include <string>
#include "common/certificate_type.h"
#include "provisioning_sdk/public/provisioning_engine.h"
#include "provisioning_sdk/public/provisioning_session.h"
#include "provisioning_sdk/public/provisioning_status.h"
using widevine::kCertificateTypeTesting;
using widevine::OK;
using widevine::ProvisioningEngine;
using widevine::ProvisioningSession;
std::string GetContents(const std::string& file_name) {
if (file_name.empty()) {
std::cout << "File name is empty." << std::endl;
return "";
}
FILE* file = fopen(file_name.c_str(), "r");
if (!file) {
std::cout << "Unable to open file " << file_name << std::endl;
return "";
}
std::string contents;
const size_t kReadSize = 0x1000;
char buffer[kReadSize];
while (true) {
size_t size_read = fread(buffer, sizeof(char), kReadSize, file);
if (size_read == 0) break;
contents.append(buffer, size_read);
}
if (!feof(file)) std::cout << "Failed to read all file contents.";
fclose(file);
return contents;
}
int main(int argc, char** argv) {
ProvisioningEngine engine;
// Call Initialize to setup the engine.
if (engine.Initialize(
kCertificateTypeTesting, GetContents("example_data/service.cert"),
GetContents("example_data/service.encrypted.private"),
GetContents("example_data/service.passphrase"),
GetContents("example_data/provisioner.cert"),
GetContents("example_data/provisioner.encrypted.private"),
GetContents("example_data/provisioner.passphrase"),
GetContents("example_data/provisioner.spoid_secret")) != OK) {
std::cout << "Failed to initialize." << std::endl;
return 1;
}
// Certificate status list should be updated periodically. In this example,
// we'll just set it once. Note that in practice, the expiration should not be
// 10 years long.
if (engine.SetCertificateStatusList(
GetContents("example_data/certificate_list"),
10 * 365 * 24 * 3600 /* 10 years */) != OK) {
std::cout << "Failed to set certificate status list." << std::endl;
return 1;
}
// Before being able to process provisioning request for a specific type of
// device, we need to generate the intermediate certificate and add it to the
// engine first. This only needs to be done once for every new type of device.
const int kSystemId = 2001;
std::string certificate;
if (engine.GenerateDrmIntermediateCertificate(
kSystemId, GetContents("example_data/intermediate.public"),
&certificate) != OK) {
std::cout << "Failed to generate intermediate certificate." << std::endl;
return 1;
}
if (engine.AddDrmIntermediateCertificate(
certificate,
GetContents("example_data/intermediate.encrypted.private"),
GetContents("example_data/intermediate.passphrase")) != OK) {
std::cout << "Failed to add intermediate certificate." << std::endl;
return 1;
}
// In order to process provisioning request, we need to create a session. The
// public/private key pairs should be unique - they cannot be reused if the
// message is processed successfully; if ProcessMessage fails, they can be
// reused on another session.
std::unique_ptr<ProvisioningSession> session;
if (engine.NewProvisioningSession(
GetContents("example_data/device.public"),
GetContents("example_data/device.private"), &session) != OK) {
std::cout << "Failed to create session." << std::endl;
return 1;
}
std::string response;
bool done;
if (session->ProcessMessage(GetContents("example_data/message"), &response,
&done) != OK) {
std::cout << "Failed to process message." << std::endl;
return 1;
}
std::cout << "Message processed successfully.";
return 0;
}

Binary file not shown.

BIN
libprovisioning_sdk.so Executable file

Binary file not shown.

View File

@@ -0,0 +1,188 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Public protocol buffer definitions for Widevine Device Certificate
// Provisioning protocol.
syntax = "proto2";
package widevine;
import "protos/public/client_identification.proto";
import "protos/public/hash_algorithm.proto";
import "protos/public/remote_attestation.proto";
option java_package = "com.google.video.widevine.protos";
// ProvisioningOptions specifies the type of certificate to specify and
// in the case of X509 certificates, the certificate authority to use.
message ProvisioningOptions {
enum CertificateType {
WIDEVINE_DRM = 0; // Default. The original certificate type.
X509 = 1; // X.509 certificate.
WIDEVINE_KEYBOX = 2;
}
optional CertificateType certificate_type = 1 [default = WIDEVINE_DRM];
// Contains the application-specific name used to identify the certificate
// authority for signing the generated certificate. This is required iff the
// certificate type is X509.
optional string certificate_authority = 2;
// System ID for OTA keybox provisioning. Requires device secure boot.
optional uint32 system_id = 3;
}
// Provisioning request sent by client devices to provisioning service.
message ProvisioningRequest {
message EncryptedSessionKeys {
message SessionKeys {
// 16 bytes encryption key generated by client, used by the server to:
// (1) AES-128-CBC decrypt encrypted_client_id in
// EncryptedClientIdentification which is in RemoteAttestation
// (2) AES-128-CBC encrypt device_key to be returned in
// ProvisioningResponse.
optional bytes encryption_key = 1;
// 32 bytes mac key generated by client, used by server to sign
// the ProvisioningResponse.
optional bytes mac_key = 2;
}
// Serial number of certificate which was used to encrypt the session keys.
// Required.
optional bytes certificate_serial_number = 1;
// Serialized, encrypted session keys. Required.
optional bytes encrypted_session_keys = 2;
}
oneof clear_or_encrypted_client_id {
// Device root of trust and other client identification. Required.
ClientIdentification client_id = 1;
EncryptedClientIdentification encrypted_client_id = 5;
}
// Nonce value used to prevent replay attacks. Required.
optional bytes nonce = 2;
// Options for type of certificate to generate. Optional.
optional ProvisioningOptions options = 3;
oneof spoid_param {
// Stable identifier, unique for each device + application (or origin).
// To be deprecated.
bytes stable_id = 4;
// Service provider ID from the service certificate's provider_id field.
// Preferred parameter.
bytes provider_id = 6;
// Client-generated stable per-origin identifier to be copied directly
// to the client certificate serial number.
bytes spoid = 7;
}
// SessionKeys encrypted using a service cert public key.
// Required for keybox provisioning.
optional EncryptedSessionKeys encrypted_session_keys = 8;
}
// Provisioning response sent by the provisioning server to client devices.
// This message is used for both regular Widevine DRM certificates and for
// application-specific X.509 certificates.
message ProvisioningResponse {
message OtaKeybox {
// Iv used along with SessionKeys.encryption_key for encrypting device key.
optional bytes device_key_encryption_iv = 1;
// Device key component of the keybox, encrypted using the
// SessionKeys.encryption_key in the request and |device_key_encryption_iv|
// above.
optional bytes encrypted_device_key = 2;
// Device CA token component of the keybox.
optional bytes device_ca_token = 3;
}
// AES-128 encrypted device private RSA key. PKCS#1 ASN.1 DER-encoded.
// Required. For X.509 certificates, the private RSA key may also include
// a prefix as specified by private_key_prefix in the X509CertificateMetadata
// proto message.
optional bytes device_rsa_key = 1;
// Initialization vector used to encrypt device_rsa_key. Required.
optional bytes device_rsa_key_iv = 2;
// For Widevine DRM certificates, this contains the serialized
// SignedDrmCertificate. For X.509 certificates, this contains the PEM
// encoded X.509 certificate. Required.
optional bytes device_certificate = 3;
// Nonce value matching nonce in ProvisioningRequest. Required.
optional bytes nonce = 4;
// Key used to wrap device_rsa_key when DRM provisioning an OEM factory
// provisioned device. Encrypted with the device OEM public key using
// RSA-OAEP.
optional bytes wrapping_key = 5;
// Only populated in OTA keybox provisioning response.
optional OtaKeybox ota_keybox = 6;
}
// Protocol-specific context data used to hold the state of the server in
// stateful provisioning protocols. For more information, please refer to
// mE_ZP4WmSX-JNldg
message ProvisioningContext {
// Serialized ProvisioningContextKeyData. Required.
optional bytes key_data = 1;
// Protocol-dependent context data, encrypted with key and IV in key_data.
// Required.
optional bytes context_data = 2;
}
message SignedProvisioningContext {
// ProvisioningContext in bytes.
optional bytes provisioning_context = 1;
// RSASSA-PSS signature of provisioning_context. Signed with service private
// key.
optional bytes signature = 2;
// Optional field that indicates the hash algorithm used in signature scheme.
optional HashAlgorithmProto hash_algorithm = 3;
}
// Cryptographic tokens to be used for ProvisioningContext.
message ProvisioningContextKeyData {
// Encryption key, usually 32 bytes used for AES-256-CBC. Required.
optional bytes encryption_key = 1;
// Encryption IV, 16 bytes. Required.
optional bytes encryption_iv = 2;
}
// Serialized ProvisioningRequest or ProvisioningResponse signed with
// The message authentication key.
message SignedProvisioningMessage {
enum ProtocolVersion {
SERVICE_CERTIFICATE_REQUEST = 1; // Service certificate request.
PROVISIONING_20 = 2; // Keybox factory-provisioned devices.
PROVISIONING_30 = 3; // OEM certificate factory-provisioned devices.
}
// Serialized protobuf message for the corresponding protocol and stage of
// the provisioning exchange. ProvisioningRequest or ProvisioningResponse
// in the case of Provisioning 2.0, 3.0 and ARCPP_PROVISIONING. Required.
optional bytes message = 1;
// HMAC-SHA256 (Keybox) or RSASSA-PSS (OEM) signature of message. Required
// for provisioning 2.0 and 3.0. For ARCPP_PROVISIONING, only used in
// response.
optional bytes signature = 2;
// Version number of provisioning protocol.
optional ProtocolVersion protocol_version = 3 [default = PROVISIONING_20];
// Protocol-specific context / state information for multiple-exchange,
// stateful provisioing protocols. Optional.
optional SignedProvisioningContext signed_provisioning_context = 4;
// Remote attestation data to authenticate that the ChromeOS client device
// is operating in verified mode. Remote attestation challenge data is
// |message| field above. Required for ARCPP_PROVISIONING request.
// It contains signature of |message|.
optional RemoteAttestation remote_attestation = 5;
// The core message is the simple serialization of fields used by OEMCrypto.
// This field was introduced in OEMCrypto API v16. The core message format is
// documented in the "Widevine Core Message Serialization", found internally
// at
// https://docs.google.com/document/d/1M5f0OA8zrIFufpZiny_M9WkvJkCUs9DpRpeDmk9QKKY/edit
optional bytes oemcrypto_core_message = 6;
// Optional field that indicates the hash algorithm used in signature scheme.
optional HashAlgorithmProto hash_algorithm = 7;
}

View File

@@ -0,0 +1,131 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// ClientIdentification messages used by provisioning and license protocols.
syntax = "proto2";
package widevine;
option java_package = "com.google.video.widevine.protos";
option java_outer_classname = "ClientIdentificationProtos";
// ClientIdentification message used to authenticate the client device.
message ClientIdentification {
enum TokenType {
KEYBOX = 0;
DRM_DEVICE_CERTIFICATE = 1;
REMOTE_ATTESTATION_CERTIFICATE = 2;
OEM_DEVICE_CERTIFICATE = 3;
}
message NameValue {
optional string name = 1;
optional string value = 2;
}
// Capabilities which not all clients may support. Used for the license
// exchange protocol only.
message ClientCapabilities {
enum HdcpVersion {
HDCP_NONE = 0;
HDCP_V1 = 1;
HDCP_V2 = 2;
HDCP_V2_1 = 3;
HDCP_V2_2 = 4;
HDCP_V2_3 = 5;
HDCP_NO_DIGITAL_OUTPUT = 0xff;
}
enum CertificateKeyType {
RSA_2048 = 0;
RSA_3072 = 1;
ECC_SECP256R1 = 2;
ECC_SECP384R1 = 3;
ECC_SECP521R1 = 4;
}
enum AnalogOutputCapabilities {
ANALOG_OUTPUT_UNKNOWN = 0;
ANALOG_OUTPUT_NONE = 1;
ANALOG_OUTPUT_SUPPORTED = 2;
ANALOG_OUTPUT_SUPPORTS_CGMS_A = 3;
}
optional bool client_token = 1 [default = false];
optional bool session_token = 2 [default = false];
optional bool video_resolution_constraints = 3 [default = false];
optional HdcpVersion max_hdcp_version = 4 [default = HDCP_NONE];
optional uint32 oem_crypto_api_version = 5;
// Client has hardware support for protecting the usage table, such as
// storing the generation number in secure memory. For Details, see:
// https://docs.google.com/document/d/1Mm8oB51SYAgry62mEuh_2OEkabikBiS61kN7HsDnh9Y/edit#heading=h.xgjl2srtytjt
optional bool anti_rollback_usage_table = 6 [default = false];
// The client shall report |srm_version| if available.
optional uint32 srm_version = 7;
// A device may have SRM data, and report a version, but may not be capable
// of updating SRM data.
optional bool can_update_srm = 8 [default = false];
repeated CertificateKeyType supported_certificate_key_type = 9;
optional AnalogOutputCapabilities analog_output_capabilities = 10
[default = ANALOG_OUTPUT_UNKNOWN];
optional bool can_disable_analog_output = 11 [default = false];
// Clients can indicate a performance level supported by OEMCrypto.
// This will allow applications and providers to choose an appropriate
// quality of content to serve. Currently defined tiers are
// 1 (low), 2 (medium) and 3 (high). Any other value indicate that
// the resource rating is unavailable or reporting erroneous values
// for that device. For details see,
// https://docs.google.com/document/d/1wodSYK-Unj3AgTSXqujWuBCAFC00qF85G1AhfLtqdko
optional uint32 resource_rating_tier = 12 [default = 0];
}
message ClientCredentials {
optional TokenType type = 1 [default = KEYBOX];
optional bytes token = 2;
}
// Type of factory-provisioned device root of trust. Optional.
optional TokenType type = 1 [default = KEYBOX];
// Factory-provisioned device root of trust. Required.
optional bytes token = 2;
// Optional client information name/value pairs.
repeated NameValue client_info = 3;
// Client token generated by the content provider. Optional.
optional bytes provider_client_token = 4;
// Number of licenses received by the client to which the token above belongs.
// Only present if client_token is specified.
optional uint32 license_counter = 5;
// List of non-baseline client capabilities.
optional ClientCapabilities client_capabilities = 6;
// Serialized VmpData message. Optional.
optional bytes vmp_data = 7;
// Optional field that may contain additional provisioning credentials.
optional ClientCredentials device_credentials = 8;
}
// EncryptedClientIdentification message used to hold ClientIdentification
// messages encrypted for privacy purposes.
message EncryptedClientIdentification {
// Provider ID for which the ClientIdentifcation is encrypted (owner of
// service certificate).
optional string provider_id = 1;
// Serial number for the service certificate for which ClientIdentification is
// encrypted.
optional bytes service_certificate_serial_number = 2;
// 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;
// AES-128 privacy key, encrypted with the service public key using RSA-OAEP.
optional bytes encrypted_privacy_key = 5;
}

View File

@@ -0,0 +1,172 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
//
// This file contains device-related definitions that are common to both the
// legacy device management service and the new devices service. Eventually,
// we may merge the contents of this file into other files.
syntax = "proto3";
package widevine;
option java_package = "com.google.video.widevine.protos";
// Allows additional make/models to be associated with a system_id.
message DeviceModel {
// ModelStatus is used to specify how confident we are that this
// make/model/year combination is allowed by the device manufacturer.
// VERIFIED indicates that the manufacturer confirmed that it is correct.
// UNVERIFIED means that we have sufficient data to believe it is correct,
// but the manufacturer has not confirmed.
// UNKNOWN indicates that we do not have sufficient information to indicate
// whether or not the device is allowed by the manufacturer.
// REJECTED indicates that the manufacturer explicitly disallowed the use
// of the make/model/year combination.
enum ModelStatus {
MODEL_STATUS_UNSPECIFIED = 0;
MODEL_STATUS_VERIFIED = 1;
MODEL_STATUS_UNVERIFIED = 2;
MODEL_STATUS_UNKNOWN = 4;
MODEL_STATUS_REJECTED = 3;
}
// Represents the device manufacturer. Typically, this will be Philips, LG,
// Sharp, etc.
string manufacturer = 1;
// Model of the device.
string model_name = 2;
// The expected release year of the make/model combination. Optional.
uint32 model_year = 3;
// The model status of this make and model.
ModelStatus status = 4;
}
// DeviceState defines the current state of the device. It is used in
// licensing to determine if a (classic or MDRM/CENC) license should be
// issued. The status affects if and how a device record is shown in
// keysmith's CertificateStatusList.
//
// States:
// DEVICE_STATE_UNKNOWN: This should not be used.
// It only indicates that a state has not been set.
// IN_TESTING: The first valid state of a device record. A newly created
// device should be in this state until the device is considered
// "released". In this state a device should only be supported on test
// services (e.g. UAT license service).
// PRE_RELEASE: The state of a device when it's ready to be used with
// production services. In this state a device can receive production
// classic and MDRM/CENC licenses. The device will also be listed in
// keysmith's certificate status list. The device data will be
// available for sharing with internal partners only.
// RELEASED: Indicates that the device is available on the store shelves.
// The device data will be available for sharing with external partners.
// DELETED: Indicates that the device was manually disabled and should
// not be used for any test or production services. The device should
// not appear in the device certificate status list. Customers will
// not be able to see or utilize this state when managing their devices.
// TEST_ONLY: Indicates that this device was never intended for production
// but can be used for test purposes. The device will be listed in the
// certificate status list as a test device.
// REVOKED: Indicates that the device was revoked. No test or production
// service should honor requests (classic nor MDRM/CENC) from one of
// these devices. The device serial number and its REVOKED status will
// appear in keysmith's certificate status list.
//
// Devices in the above states have the following behaviors in widevince
// services:
//
// Licensing | Certificate | Cert | Cert | Test |
// State Prod | UAT | Provisioning | Listed | status | device | redact
// -- -- -- -- -- -- -- --
// IN_TESTING No Yes Yes Yes VALID true yes
// TEST_ONLY No Yes Yes Yes VALID true no
// PRE_RELEASE Yes Yes Yes Yes VALID false yes
// RELEASED Yes Yes Yes Yes VALID false no
// REVOKED No No No Yes REVOKED false no
// DELETED No No No No n/a n/a n/a
enum DeviceState {
DEVICE_STATE_UNKNOWN = 0;
IN_TESTING = 1;
RELEASED = 2;
DELETED = 3;
TEST_ONLY = 4;
REVOKED = 5;
PRE_RELEASE = 6;
}
// Specifies the device type, or form factor of a device.
enum DeviceType {
DEVICE_TYPE_UNSPECIFIED = 0;
DEVICE_TYPE_PHONE = 1;
DEVICE_TYPE_TV = 2;
DEVICE_TYPE_TABLET = 3;
DEVICE_TYPE_GAMING_CONSOLE = 4;
DEVICE_TYPE_SET_TOP_BOX = 5;
DEVICE_TYPE_VIDEO_DONGLE = 6;
DEVICE_TYPE_PC = 7;
DEVICE_TYPE_AUTO = 8;
DEVICE_TYPE_WEARABLE = 9;
DEVICE_TYPE_CONNECTED_AUDIO_DEVICE = 10;
DEVICE_TYPE_SMART_DISPLAY = 11;
// Legacy identifier for records that were created for SoC integration.
DEVICE_TYPE_SOC = 12;
}
// Specifies the platform and OS of the device.
enum Platform {
PLATFORM_UNSPECIFIED = 0;
PLATFORM_CHROMECAST = 1;
PLATFORM_FUCHSIA = 2;
PLATFORM_IOS = 3;
PLATFORM_IPAD_OS = 4;
PLATFORM_TV_OS = 5;
PLATFORM_ANDROID = 6;
PLATFORM_WINDOWS = 7;
PLATFORM_CHROME_OS = 8;
PLATFORM_MAC_OS = 9;
PLATFORM_LINUX = 10;
PLATFORM_WEB_OS = 11;
PLATFORM_TIZEN = 12;
PLATFORM_FIRE_OS = 13;
PLATFORM_ROKU = 14;
PLATFORM_PLAYSTATION = 15;
PLATFORM_XBOX = 16;
PLATFORM_KAIOS = 17;
PLATFORM_RDK = 18;
PLATFORM_OTHER = 19;
}
// This is used for tri-state answers. Yes-TEE, Yes-REE, No.
// This has to be in device_common to avoid import conflicts between security
// profiles and device security profiles.
enum OsOptionalSupport {
OS_OPTIONAL_SUPPORT_UNSPECIFIED = 0;
YES_TEE = 1;
YES_REE = 2;
NO_SUPPORT = 3;
}
// Version of High-bandwidth Digital Content Protection (HDCP).
// This has to be in device_common to avoid import conflicts between security
// profiles and device security profiles.
enum HdcpVersion {
HDCP_VERSION_UNSPECIFIED = 0;
HDCP_V1 = 1;
HDCP_V2 = 2;
HDCP_V2_1 = 3;
HDCP_V2_2 = 4;
HDCP_V2_3 = 5;
}
// Widevine device security level.
enum DeviceSecurityLevel {
SECURITY_LEVEL_UNSPECIFIED = 0;
LEVEL_1 = 1;
LEVEL_2 = 2;
LEVEL_3 = 3;
}

View File

@@ -0,0 +1,81 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2019 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Definitions of the protocol buffer messages used in the Widevine license
// exchange protocol to support DRM systems native to a device other than
// Widevine.
syntax = "proto2";
package widevine;
import "protos/public/client_identification.proto";
import "protos/public/license_protocol.proto";
option java_package = "com.google.video.widevine.externallicense";
option java_multiple_files = true;
enum ExternalLicenseType {
EXTERNAL_LICENSE_TYPE_UNDEFINED = 0;
PLAYREADY_LICENSE_NEW = 1;
PLAYREADY_LICENSE_RENEWAL = 2;
PLAYREADY_LICENSE_RELEASE = 3;
}
message EncryptedLicenseRequest {
// Provider ID for which the license request is encrypted (owner of
// service certificate).
optional string provider_id = 1;
// Serial number for the service certificate for which license_request is
// encrypted.
optional bytes service_certificate_serial_number = 2;
// Serialized license request message, encrypted with the privacy key
// using AES-128-CBC with PKCS#5 padding.
optional bytes encrypted_license_request = 3;
// Initialization vector needed to decrypt encrypted_license_request.
optional bytes encrypted_license_request_iv = 4;
// AES-128 privacy key, encrypted with the service public key using RSA-OAEP.
optional bytes encrypted_privacy_key = 5;
}
message ExternalLicenseRequest {
optional ExternalLicenseType request_type = 1;
// The license request.
oneof clear_or_encrypted_request {
// License request from the client.
bytes request = 2;
// Encrypted request from the client.
EncryptedLicenseRequest encrypted_request = 7;
}
oneof clear_or_encrypted_client_id {
// Information about the device.
ClientIdentification client_id = 3;
// Encrypted ClientIdentification message, used for privacy purposes.
EncryptedClientIdentification encrypted_client_id = 4;
}
// Information about the content, including the PSSH data.
optional LicenseRequest.ContentIdentification content_id = 5;
// Time of the request in seconds (UTC) as set by the client.
optional int64 request_time = 6;
}
message ExternalLicense {
optional ExternalLicenseType license_type = 1;
// The license representing the license type.
optional bytes license = 2;
// Widevine specific policy for renewals and expiry.
optional License.Policy policy = 3;
// Time of the request in seconds (UTC) as set in
// LicenseRequest.request_time. If this time is not set in the request,
// the local time at the license service is used in this field.
optional int64 license_start_time = 4;
// List of key Identifiers associated with this license.
repeated bytes key_id = 5;
}

View File

@@ -0,0 +1,20 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
syntax = "proto3";
package widevine;
// LINT.IfChange
enum HashAlgorithmProto {
// Unspecified hash algorithm: SHA_256 shall be used for ECC based algorithms
// and SHA_1 shall be used otherwise.
HASH_ALGORITHM_UNSPECIFIED = 0;
HASH_ALGORITHM_SHA_1 = 1;
HASH_ALGORITHM_SHA_256 = 2;
}

View File

@@ -0,0 +1,522 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Definitions of the protocol buffer messages used in the Widevine license
// exchange protocol, described in Widevine license exchange protocol document
syntax = "proto2";
package widevine;
import "protos/public/client_identification.proto";
import "protos/public/hash_algorithm.proto";
import "protos/public/remote_attestation.proto";
option java_package = "com.google.video.widevine.protos";
// option optimize_for = LITE_RUNTIME;
enum LicenseType {
STREAMING = 1;
OFFLINE = 2;
// License type decision is left to provider.
AUTOMATIC = 3;
}
enum PlatformVerificationStatus {
// The platform is not verified.
PLATFORM_UNVERIFIED = 0;
// Tampering detected on the platform.
PLATFORM_TAMPERED = 1;
// The platform has been verified by means of software.
PLATFORM_SOFTWARE_VERIFIED = 2;
// The platform has been verified by means of hardware (e.g. secure boot).
PLATFORM_HARDWARE_VERIFIED = 3;
// Platform verification was not performed.
PLATFORM_NO_VERIFICATION = 4;
// Platform and secure storage capability have been verified by means of
// software.
PLATFORM_SECURE_STORAGE_SOFTWARE_VERIFIED = 5;
}
// LicenseIdentification is propagated from LicenseRequest to License,
// incrementing version with each iteration.
message LicenseIdentification {
optional bytes request_id = 1;
optional bytes session_id = 2;
optional bytes purchase_id = 3;
optional LicenseType type = 4;
optional int32 version = 5;
optional bytes provider_session_token = 6;
}
// This message is used to indicate the license cateogry spec for a license as
// a part of initial license issuance.
// LINT.IfChange
message LicenseCategorySpec {
// Possible license categories.
enum LicenseCategory {
// By default, License is used for single content.
SINGLE_CONTENT_LICENSE_DEFAULT = 0;
// License is used for multiple contents (could be a combination of
// single contents and groups of contents).
MULTI_CONTENT_LICENSE = 1;
// License is used for contents logically grouped.
GROUP_LICENSE = 2;
}
// Optional. License category indicates if license is used for single
// content, multiple contents (could be a combination of
// single contents and groups of contents) or a group of contents.
optional LicenseCategory license_category = 1;
// Optional. Content or group ID covered by the license.
oneof content_or_group_id {
// Content_id would be present if it is a license for single content.
bytes content_id = 2;
// Group_id would be present if the license is a multi_content_license or
// group_license. Group Id could be the name of a group of contents,
// defined by licensor.
bytes group_id = 3;
}
}
message License {
// LINT.IfChange
message Policy {
// Indicates that playback of the content is allowed.
optional bool can_play = 1 [default = false];
// Indicates that the license may be persisted to non-volatile
// storage for offline use.
optional bool can_persist = 2 [default = false];
// Indicates that renewal of this license is allowed.
optional bool can_renew = 3 [default = false];
// For the |*duration*| fields, playback must halt when
// license_start_time (seconds since the epoch (UTC)) +
// license_duration_seconds is exceeded. A value of 0
// indicates that there is no limit to the duration.
// Indicates the rental window.
optional int64 rental_duration_seconds = 4 [default = 0];
// Indicates the viewing window, once playback has begun.
optional int64 playback_duration_seconds = 5 [default = 0];
// Indicates the time window for this specific license.
optional int64 license_duration_seconds = 6 [default = 0];
// The |renewal*| fields only apply if |can_renew| is true.
// The window of time, in which playback is allowed to continue while
// renewal is attempted, yet unsuccessful due to backend problems with
// the license server.
optional int64 renewal_recovery_duration_seconds = 7 [default = 0];
// All renewal requests for this license shall be directed to the
// specified URL.
optional string renewal_server_url = 8;
// How many seconds after license_start_time, before renewal is first
// attempted.
optional int64 renewal_delay_seconds = 9 [default = 0];
// Specifies the delay in seconds between subsequent license
// renewal requests, in case of failure.
optional int64 renewal_retry_interval_seconds = 10 [default = 0];
// Indicates that the license shall be sent for renewal when usage is
// started.
optional bool renew_with_usage = 11 [default = false];
// Indicates to client that license renewal and release requests ought to
// include ClientIdentification (client_id).
optional bool always_include_client_id = 12 [default = false];
// Duration of grace period before playback_duration_seconds (short window)
// goes into effect. Optional.
optional int64 play_start_grace_period_seconds = 13 [default = 0];
// Enables "soft enforcement" of playback_duration_seconds, letting the user
// finish playback even if short window expires. Optional.
optional bool soft_enforce_playback_duration = 14 [default = false];
// Enables "soft enforcement" of rental_duration_seconds. Initial playback
// must always start before rental duration expires. In order to allow
// subsequent playbacks to start after the rental duration expires,
// soft_enforce_playback_duration must be true. Otherwise, subsequent
// playbacks will not be allowed once rental duration expires. Optional.
optional bool soft_enforce_rental_duration = 15 [default = true];
}
message KeyContainer {
enum KeyType {
SIGNING = 1; // No more than one signing key may appear.
CONTENT = 2; // Content key.
KEY_CONTROL = 3; // Key control block for license renewals. No key.
OPERATOR_SESSION = 4; // wrapped keys for auxiliary crypto operations.
ENTITLEMENT = 5; // Entitlement keys.
OEM_CONTENT = 6; // Partner-specific content key.
}
// The SecurityLevel enumeration allows the server to communicate the level
// of robustness required by the client, in order to use the key.
enum SecurityLevel {
// Software-based whitebox crypto is required.
SW_SECURE_CRYPTO = 1;
// Software crypto and an obfuscated decoder is required.
SW_SECURE_DECODE = 2;
// The key material and crypto operations must be performed within a
// hardware backed trusted execution environment.
HW_SECURE_CRYPTO = 3;
// The crypto and decoding of content must be performed within a hardware
// backed trusted execution environment.
HW_SECURE_DECODE = 4;
// The crypto, decoding and all handling of the media (compressed and
// uncompressed) must be handled within a hardware backed trusted
// execution environment.
HW_SECURE_ALL = 5;
}
message KeyControl {
// 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.
optional bytes key_control_block = 1;
optional bytes iv = 2;
}
message OutputProtection {
// Indicates whether HDCP is required on digital outputs, and which
// version should be used.
enum HDCP {
HDCP_NONE = 0;
HDCP_V1 = 1;
HDCP_V2 = 2;
HDCP_V2_1 = 3;
HDCP_V2_2 = 4;
HDCP_V2_3 = 5;
HDCP_NO_DIGITAL_OUTPUT = 0xff;
}
optional HDCP hdcp = 1 [default = HDCP_NONE];
// Indicate the CGMS setting to be inserted on analog output.
enum CGMS {
CGMS_NONE = 42;
COPY_FREE = 0;
COPY_ONCE = 2;
COPY_NEVER = 3;
}
optional CGMS cgms_flags = 2 [default = CGMS_NONE];
enum HdcpSrmRule {
HDCP_SRM_RULE_NONE = 0;
// In 'required_protection', this means most current SRM is required.
// Update the SRM on the device. If update cannot happen,
// do not allow the key.
// In 'requested_protection', this means most current SRM is requested.
// Update the SRM on the device. If update cannot happen,
// allow use of the key anyway.
CURRENT_SRM = 1;
}
optional HdcpSrmRule hdcp_srm_rule = 3 [default = HDCP_SRM_RULE_NONE];
// Optional requirement to indicate analog output is not allowed.
optional bool disable_analog_output = 4 [default = false];
// Optional requirement to indicate digital output is not allowed.
optional bool disable_digital_output = 5 [default = false];
// Optional. If set, it indicates digital video recording (DVR) is
// allowed.
optional bool allow_record = 6 [default = false];
}
message VideoResolutionConstraint {
// Minimum and maximum video resolutions in the range (height x width).
optional uint32 min_resolution_pixels = 1;
optional uint32 max_resolution_pixels = 2;
// Optional output protection requirements for this range. If not
// specified, the OutputProtection in the KeyContainer applies.
optional OutputProtection required_protection = 3;
}
message OperatorSessionKeyPermissions {
// Permissions/key usage flags for operator service keys
// (type = OPERATOR_SESSION).
optional bool allow_encrypt = 1 [default = false];
optional bool allow_decrypt = 2 [default = false];
optional bool allow_sign = 3 [default = false];
optional bool allow_signature_verify = 4 [default = false];
}
// KeyCategorySpec message is used to identify if current key is generated
// for a single content or a group of contents. Currently it is only used in
// CAS request.
message KeyCategorySpec {
// Represents what kind of content a key is used for.
enum KeyCategory {
// By default, key is created for single content.
SINGLE_CONTENT_KEY_DEFAULT = 0;
// Key is created for a group of contents.
GROUP_KEY = 1;
}
// Indicate if the current key is created for single content or for group
// use.
optional KeyCategory key_category = 1;
// Id for key category. If it is a key for single content, this id
// represents the content_id. Otherwise, it represents a group_id.
oneof content_or_group_id {
bytes content_id = 2;
bytes group_id = 3;
}
}
optional bytes id = 1;
optional bytes iv = 2;
optional bytes key = 3;
optional KeyType type = 4;
optional SecurityLevel level = 5 [default = SW_SECURE_CRYPTO];
optional OutputProtection required_protection = 6;
// NOTE: Use of requested_protection is not recommended as it is only
// supported on a small number of platforms.
optional OutputProtection requested_protection = 7;
optional KeyControl key_control = 8;
optional OperatorSessionKeyPermissions operator_session_key_permissions = 9;
// Optional video resolution constraints. If the video resolution of the
// content being decrypted/decoded falls within one of the specified ranges,
// the optional required_protections may be applied. Otherwise an error will
// be reported.
// NOTE: Use of this feature is not recommended, as it is only supported on
// a small number of platforms.
repeated VideoResolutionConstraint video_resolution_constraints = 10;
// Optional flag to indicate the key must only be used if the client
// supports anti rollback of the user table. Content provider can query the
// client capabilities to determine if the client support this feature.
optional bool anti_rollback_usage_table = 11 [default = false];
// Optional not limited to commonly known track types such as SD, HD.
// It can be some provider defined label to identify the track.
optional string track_label = 12;
// Optional. It is used to identify if current key is generated for a
// single content or a group of contents. Currently it is only used in CAS
// request.
optional KeyCategorySpec key_category_spec = 13;
}
optional LicenseIdentification id = 1;
optional Policy policy = 2;
repeated KeyContainer key = 3;
// Time of the request in seconds (UTC) as set in
// LicenseRequest.request_time. If this time is not set in the request,
// the local time at the license service is used in this field.
optional int64 license_start_time = 4;
// TODO(b/65054419): Deprecate remote_attestation_verified in favor of
// platform_verification_status, below.
optional bool remote_attestation_verified = 5 [default = false];
// Client token generated by the content provider. Optional.
optional bytes provider_client_token = 6;
// 4cc code specifying the CENC protection scheme as defined in the CENC 3.0
// specification. Propagated from Widevine PSSH box. Optional.
optional uint32 protection_scheme = 7;
// 8 byte verification field "HDCPDATA" followed by unsigned 32 bit minimum
// HDCP SRM version (whether the version is for HDCP1 SRM or HDCP2 SRM
// depends on client max_hdcp_version).
optional bytes srm_requirement = 8;
// If present this contains a signed SRM file (either HDCP1 SRM or HDCP2 SRM
// depending on client max_hdcp_version) that should be installed on the
// client device.
optional bytes srm_update = 9;
// Indicates the status of any type of platform verification performed by the
// server.
optional PlatformVerificationStatus platform_verification_status = 10
[default = PLATFORM_NO_VERIFICATION];
// IDs of the groups for which keys are delivered in this license, if any.
repeated bytes group_ids = 11;
// Optional. LicenseCategorySpec is used to indicate the license cateogry for
// a license. It could be used as a part of initial license issuance or shown
// as a part of license in license response.
optional LicenseCategorySpec license_category_spec = 12;
}
enum ProtocolVersion {
VERSION_2_0 = 20;
VERSION_2_1 = 21;
VERSION_2_2 = 22;
}
message LicenseRequest {
message ContentIdentification {
message WidevinePsshData {
repeated bytes pssh_data = 1;
optional LicenseType license_type = 2;
optional bytes request_id = 3; // Opaque, client-specified.
}
message WebmKeyId {
optional bytes header = 1;
optional LicenseType license_type = 2;
optional bytes request_id = 3; // Opaque, client-specified.
}
message ExistingLicense {
optional LicenseIdentification license_id = 1;
optional int64 seconds_since_started = 2;
optional int64 seconds_since_last_played = 3;
optional bytes session_usage_table_entry = 4;
}
message InitData {
enum InitDataType {
CENC = 1;
WEBM = 2;
}
optional InitDataType init_data_type = 1 [default = CENC];
optional bytes init_data = 2;
optional LicenseType license_type = 3;
optional bytes request_id = 4;
}
oneof content_id_variant {
// Exactly one of these must be present.
WidevinePsshData widevine_pssh_data = 1;
WebmKeyId webm_key_id = 2;
ExistingLicense existing_license = 3;
InitData init_data = 4;
}
}
enum RequestType {
NEW = 1;
RENEWAL = 2;
RELEASE = 3;
}
// The client_id provides information authenticating the calling device. It
// contains the Widevine keybox token that was installed on the device at the
// factory. This field or encrypted_client_id below is required for a valid
// license request, but both should never be present in the same request.
optional ClientIdentification client_id = 1;
optional ContentIdentification content_id = 2;
optional RequestType type = 3;
// Time of the request in seconds (UTC) as set by the client.
optional int64 request_time = 4;
// Old-style decimal-encoded string key control nonce.
optional bytes key_control_nonce_deprecated = 5;
optional ProtocolVersion protocol_version = 6 [default = VERSION_2_0];
// New-style uint32 key control nonce, please use instead of
// key_control_nonce_deprecated.
optional uint32 key_control_nonce = 7;
// Encrypted ClientIdentification message, used for privacy purposes.
optional EncryptedClientIdentification encrypted_client_id = 8;
}
message LicenseError {
enum Error {
// The device credentials are invalid. The device must re-provision.
INVALID_DRM_DEVICE_CERTIFICATE = 1;
// The device credentials have been revoked. Re-provisioning is not
// possible.
REVOKED_DRM_DEVICE_CERTIFICATE = 2;
// The service is currently unavailable due to the backend being down
// or similar circumstances.
SERVICE_UNAVAILABLE = 3;
}
optional Error error_code = 1;
}
message MetricData {
enum MetricType {
// The time spent in the 'stage', specified in microseconds.
LATENCY = 1;
// The UNIX epoch timestamp at which the 'stage' was first accessed in
// microseconds.
TIMESTAMP = 2;
}
message TypeValue {
optional MetricType type = 1;
// The value associated with 'type'. For example if type == LATENCY, the
// value would be the time in microseconds spent in this 'stage'.
optional int64 value = 2 [default = 0];
}
// 'stage' that is currently processing the SignedMessage. Required.
optional string stage_name = 1;
// metric and associated value.
repeated TypeValue metric_data = 2;
}
message VersionInfo {
// License SDK version reported by the Widevine License SDK. This field
// is populated automatically by the SDK.
optional string license_sdk_version = 1;
// Version of the service hosting the license SDK. This field is optional.
// It may be provided by the hosting service.
optional string license_service_version = 2;
}
message SignedMessage {
enum MessageType {
LICENSE_REQUEST = 1;
LICENSE = 2;
ERROR_RESPONSE = 3;
SERVICE_CERTIFICATE_REQUEST = 4;
SERVICE_CERTIFICATE = 5;
SUB_LICENSE = 6;
CAS_LICENSE_REQUEST = 7;
CAS_LICENSE = 8;
EXTERNAL_LICENSE_REQUEST = 9;
EXTERNAL_LICENSE = 10;
}
enum SessionKeyType {
UNDEFINED = 0;
WRAPPED_AES_KEY = 1;
EPHEMERAL_ECC_PUBLIC_KEY = 2;
}
optional MessageType type = 1;
optional bytes msg = 2;
// Required field that contains the signature of the bytes of msg.
// For license requests, the signing algorithm is determined by the
// certificate contained in the request.
// For license responses, the signing algorithm is HMAC with signing key based
// on |session_key|.
optional bytes signature = 3;
// If populated, the contents of this field will be signaled by the
// |session_key_type| type. If the |session_key_type| is WRAPPED_AES_KEY the
// key is the bytes of an encrypted AES key. If the |session_key_type| is
// EPHERMERAL_ECC_PUBLIC_KEY the field contains the bytes of an RFC5208 ASN1
// serialized ECC public key.
optional bytes session_key = 4;
// Remote attestation data which will be present in the initial license
// request for ChromeOS client devices operating in verified mode. Remote
// attestation challenge data is |msg| field above. Optional.
optional RemoteAttestation remote_attestation = 5;
repeated MetricData metric_data = 6;
// Version information from the SDK and license service. This information is
// provided in the license response.
optional VersionInfo service_version_info = 7;
// Optional field that contains the algorithm type used to generate the
// session_key and signature in a LICENSE message.
optional SessionKeyType session_key_type = 8 [default = WRAPPED_AES_KEY];
// The core message is the simple serialization of fields used by OEMCrypto.
// This field was introduced in OEMCrypto API v16.
optional bytes oemcrypto_core_message = 9;
// Optional field that indicates the hash algorithm used in signature scheme.
optional HashAlgorithmProto hash_algorithm = 10;
// If true it indicates that a LICENSE message session key was based on a key
// provided in a secondary encryption certificate. The secondary encryption
// certificate was provided by the client in a previous LICENSE_REQUEST
// message.
optional bool using_dual_certificate = 11;
}

View File

@@ -0,0 +1,79 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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.
////////////////////////////////////////////////////////////////////////////////
// Description:
// Provisioned device info format definitions.
syntax = "proto2";
package widevine;
import "protos/public/device_common.proto";
option java_package = "com.google.video.widevine.protos";
option java_outer_classname = "ProvisionedDeviceInfoProto";
// Contains device model information for a provisioned device.
message ProvisionedDeviceInfo {
enum WvSecurityLevel {
// Defined in Widevine Security Integration Guide for DASH on Android:
// http://doc/1Zum-fcJeoIw6KG1kDP_KepIE5h9gAZg0PaMtemBvk9c/edit#heading=h.1t3h5sf
LEVEL_UNSPECIFIED = 0;
LEVEL_1 = 1;
LEVEL_2 = 2;
LEVEL_3 = 3;
}
// Widevine initial provisioning / bootstrapping method. DRM certificates are
// required for retrieving licenses, so if a DRM certificate is not initially
// provisioned, then the provisioned credentials will be used to provision
// a DRM certificate via the Widevine Provisioning Service.
enum ProvisioningMethod {
// Don't use this.
PROVISIONING_METHOD_UNSPECIFIED = 0;
// Factory-provisioned device-unique keybox.
FACTORY_KEYBOX = 1;
// Factory-provisioned device-unique OEM certificate.
FACTORY_OEM_DEVICE_CERTIFICATE = 2;
// Factory-provisioned model-group OEM certificate.
FACTORY_OEM_GROUP_CERTIFICATE = 3;
// Factory-provisioned model-group DRM certificate (Level-3 "baked in").
FACTORY_DRM_GROUP_CERTIFICATE = 4;
// OTA-provisioned keybox (Level-1 ARC++).
OTA_KEYBOX = 5;
// OTA-provisioned device-unique OEM certificate.
OTA_OEM_DEVICE_CERTIFICATE = 6;
// OTA-provisioned model-group OEM certificate.
OTA_OEM_GROUP_CERTIFICATE = 7;
// OTA-provisioned device-unique DRM certificate (Bedrock).
OTA_DRM_DEVICE_CERTIFICATE = 8;
}
// Widevine system ID for the device. Mandatory.
optional uint32 system_id = 1;
// Name of system-on-a-chip. Optional.
optional string soc = 2;
// First registered manufacturer. Optional.
optional string manufacturer = 3;
// First registered manufacturer's model name. Matches "brand" in device
// metadata. Optional.
optional string model = 4;
// First registered type of device (Phone, Tablet, TV, etc).
optional string device_type = 5;
// First registered device model year. Optional.
optional uint32 model_year = 6;
// Widevine-defined security level. Optional.
optional WvSecurityLevel security_level = 7 [default = LEVEL_UNSPECIFIED];
// True if the certificate corresponds to a test (non production) device.
// Optional.
optional bool test_device = 8 [default = false];
// Indicates the type of device root of trust which was factory provisioned.
optional ProvisioningMethod provisioning_method = 9;
// A list of ModelInfo using the same system_id.
repeated DeviceModel model_info = 10;
}

View File

@@ -0,0 +1,31 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Remote attestation is used by ChromeOS device to authenticate itself
// to Widevine services for both licensing and keybox provisioning.
syntax = "proto2";
package widevine;
import "protos/public/client_identification.proto";
option java_package = "com.google.video.widevine.protos";
message RemoteAttestation {
// Encrypted ClientIdentification message containing the device remote
// attestation certificate. Required.
optional EncryptedClientIdentification certificate = 1;
// Bytes of salt which were added to the remote attestation challenge prior to
// signing it. Required.
optional bytes salt = 2;
// Signed remote attestation challenge + salt. Required.
optional bytes signature = 3;
}

View File

@@ -0,0 +1,32 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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.
////////////////////////////////////////////////////////////////////////////////
// Signed device certificate definition.
syntax = "proto2";
package widevine;
import "protos/public/hash_algorithm.proto";
option java_outer_classname = "SignedDrmCertificateProtos";
option java_package = "com.google.video.widevine.protos";
// DrmCertificate signed by a higher (CA) DRM certificate.
message SignedDrmCertificate {
// Serialized certificate. Required.
optional bytes drm_certificate = 1;
// Signature of certificate. Signed with root or intermediate
// certificate specified below. Required.
optional bytes signature = 2;
// SignedDrmCertificate used to sign this certificate.
optional SignedDrmCertificate signer = 3;
// Optional field that indicates the hash algorithm used in signature scheme.
optional HashAlgorithmProto hash_algorithm = 4;
}

Binary file not shown.

View File

@@ -0,0 +1,182 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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 PROVISIONING_SDK_PUBLIC_PROVISIONING_ENGINE_H_
#define PROVISIONING_SDK_PUBLIC_PROVISIONING_ENGINE_H_
#include <cstdint>
#include <functional>
#include <map>
#include <memory>
#include <string>
#include "common/certificate_type.h"
#include "provisioning_sdk/public/provisioning_status.h"
namespace widevine {
class ProvisioningEngineImpl;
class ProvisioningSession;
class ProvisioningSessionImpl;
// Session factory function used to implement third-party provisioning
// protocols.
// * |engine| is the ProvisioningEngineImpl which invokes the function.
// * |new_session| will point, on successful return, to the newly created
// ProvisioningSessionImpl.
// * Returns OK if successful, or an appropriate error status code otherwise.
typedef std::function<ProvisioningStatus(
const ProvisioningEngineImpl& engine,
std::unique_ptr<ProvisioningSessionImpl>* new_session)>
SessionFactory;
// Class which is used to implement a Widevine DRM device provisioning engine.
// There should be only one instance of ProvisioningEngine. The engine should
// be "Initialized" before being used. ProvisioningEngine::Initialize is the
// only method that is not thread-safe. After initializing the engine, it can
// be safely used in different threads.
class ProvisioningEngine {
public:
ProvisioningEngine();
virtual ~ProvisioningEngine();
// Initializes the provisioning engine with required credentials.
// * |certificate_type| indicates which type of certificate chains will be
// used for device provisioning via this engine.
// * |service_drm_certificate| is a Google-generated certificate used to
// authenticate the service provider for purposes of user privacy.
// * |service_private_key| is the encrypted PKCS#8 private RSA key
// corresponding to the service certificate.
// * |service_private_key_passphrase| is the password required to decrypt
// |service_private_key|, if any.
// * |provisioning_drm_certificate| is a Google-generated certificate used to
// sign intermediate DRM certificates.
// * |provisioning_private_key| is the encrypted PKCS#8 private RSA key
// corresponding to the provisioning certificate.
// * |provisioning_private_key_passphrase| is the password required to
// decrypt |provisioning_private_key|, if any.
// * |secret_spoid_sauce| is a stable secret used as a factor in the
// derivation of Stable Per-Origin IDentifiers.
// * Returns OK on success, or an appropriate error status code otherwise.
ProvisioningStatus Initialize(
CertificateType certificate_type,
const std::string& service_drm_certificate,
const std::string& service_private_key,
const std::string& service_private_key_passphrase,
const std::string& provisioning_drm_certificate,
const std::string& provisioning_private_key,
const std::string& provisioning_private_key_passphrase,
const std::string& secret_spoid_sauce);
// Third-party protocol registration method.
// * |protocol| is the provisioning protocol, as defined in the
// SignedProvisioningMessage message.
// * |session_factory| is the function which instantiates the appropriate
// ProvisioningSessionImpl object for the specified protocol.
void RegisterProtocol(int protocol,
SessionFactory session_factory);
// Set the certificate status list for this engine.
// * |certificate_status_list| is a certificate status list generated by the
// Widevine Provisioning Service.
// * |expiration_period| is the number of seconds until the
// |certificate_status_list| expires after its creation time
// (creation_time_seconds). Zero means it will never expire.
// * Returns OK on success, or an appropriate error status code otherwise.
virtual ProvisioningStatus SetCertificateStatusList(
const std::string& certificate_status_list,
uint32_t expiration_period_seconds);
// Generate an intermediate DRM certificate.
// * |system_id| is the Widevine system ID for the type of device.
// * |public_key| is a DER-encoded PKCS#1.5 RSAPublicKey message which will
// be embedded in the generated certificate.
// * |certificate| will contain the new intermediate certificate, upon
// successful return.
// * Returns OK on success, or an appropriate error status code otherwise.
// NOTE: The generated certificate and associated private key should be stored
// securely to be reused. They should also be propagated to all
// engines, including this one, by invoking
// |AddIntermediatedrmcertificate| on all active ProvisioningEngine(s).
ProvisioningStatus GenerateDrmIntermediateCertificate(
uint32_t system_id, const std::string& public_key,
std::string* certificate) const;
// Add an intermediate DRM certificate to the provisioning engine. This is
// usually done once for each supported device type.
// * |intermediate_cert| is the intermediate DRM certificate to be added.
// * |cert_private_key| is a PKCS#8 private key corresponding to
// |intermediate_cert|.
// * |cert_private_key_passphrase| is the passphrase for cert_private_key,
// if any.
// * Returns OK on success, or an appropriate error status code otherwise.
virtual ProvisioningStatus AddDrmIntermediateCertificate(
const std::string& intermediate_cert, const std::string& cert_private_key,
const std::string& cert_private_key_passphrase);
// Create a session to handle a certificate provisioning exchange between
// a client device and the provisioning server.
// * |protocol| is the protocol version for the session. If not sure, it
// probably ought to be |PROVISIONING_30|.
// * |device_public_key| is a DER-encoded PKCS#1.5 RSAPublicKey message which
// will used to create the DRM certificate to be provisioned onto the
// device.
// * |device_private_key| is a DER-encoded PKCS#8 PrivateKeyInfo message
// which contains the private key matching |device_public_key|.
// * |new_session| will point, on successful return, to the newly created
// ProvisioningSession.
// * Returns OK if successful, or an appropriate error status code otherwise.
// The key pairs can be re-used if the created session failed to process the
// message.
// NOTE: All ProvisioningSession objects must be deleted before the
// ProvisioningEngine which created them.
virtual ProvisioningStatus NewProvisioningSession(
const std::string& device_public_key,
const std::string& device_private_key,
std::unique_ptr<ProvisioningSession>* new_session) const;
// This is the same as NewProvisioningSession above, but with outputs reversed
// To get around CLIF bug https://github.com/google/clif/issues/30.
std::unique_ptr<ProvisioningSession> NewProvisioningSession(
const std::string& device_public_key,
const std::string& device_private_key, ProvisioningStatus* status) const;
// Generate a new device DRM certificate to be provisioned by means other than
// the Widevine provisioning protocol.
// NOTE: This API should only be used to provision devices which were
// manufactured without Widevine DRM support. It is meant to be used as
// an exception, and not the norm. Most devices should be provisioned
// by means of a ProvisioningSession.
// * |system_id| is the Widevine system ID for the type of device being
// provisioned.
// * |public_key| is a DER-encoded PKCS#1.5 RSAPublicKey message which will
// be embedded in the generated certificate.
// * |serial_number| is a binary std::string to be used as the generated DRM
// certificate serial number.
// * |certificate| will contain, upon successful return the generated
// certificate.
// * Returns OK on success, or an appropriate error status code otherwise.
ProvisioningStatus GenerateDeviceDrmCertificate(
uint32_t system_id, const std::string& public_key,
const std::string& serial_number, std::string* certificate) const;
private:
std::map<int, SessionFactory>
protocol_registry_;
#ifndef SWIGPYTHON
ProvisioningEngine(const ProvisioningEngine&) = delete;
ProvisioningEngine& operator=(const ProvisioningEngine&) = delete;
#endif
std::unique_ptr<ProvisioningEngineImpl> impl_;
};
} // namespace widevine
#endif // PROVISIONING_SDK_PUBLIC_PROVISIONING_ENGINE_H_

View File

@@ -0,0 +1,59 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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 PROVISIONING_SDK_PUBLIC_PROVISIONING_SESSION_H_
#define PROVISIONING_SDK_PUBLIC_PROVISIONING_SESSION_H_
#include <memory>
#include <string>
#include "provisioning_sdk/public/provisioning_status.h"
namespace widevine {
class ProvisionedDeviceInfo;
class ProvisioningSessionImpl;
// Class which is used to implement the provisioning session state machine.
class ProvisioningSession {
public:
virtual ~ProvisioningSession();
// Process a message from the client device.
// * |message| is the message received from the client device.
// * |response| will contain, upon successful return, a message to be sent
// back to the client device as a response to |message|.
// * |done| will indicate, upon successful return, whether the provisioning
// exchange is complete.
// Returns OK if successful, or an appropriate error status code otherwise.
virtual ProvisioningStatus ProcessMessage(const std::string& message,
std::string* response, bool* done);
// * Returns a ProvisioneddeviceInfo message containing information about the
// type of device being provisioned. May return nullptr.
virtual const ProvisionedDeviceInfo* GetDeviceInfo() const;
protected:
ProvisioningSession(); // To enable mocking.
private:
#ifndef SWIGPYTHON
friend class ProvisioningEngine;
ProvisioningSession(const ProvisioningSession&) = delete;
ProvisioningSession& operator=(const ProvisioningSession&) = delete;
#endif
explicit ProvisioningSession(std::unique_ptr<ProvisioningSessionImpl> impl);
std::unique_ptr<ProvisioningSessionImpl> impl_;
};
} // namespace widevine
#endif // PROVISIONING_SDK_PUBLIC_PROVISIONING_SESSION_H_

View File

@@ -0,0 +1,58 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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 PROVISIONING_SDK_PUBLIC_PROVISIONING_STATUS_H_
#define PROVISIONING_SDK_PUBLIC_PROVISIONING_STATUS_H_
#include <string>
namespace widevine {
enum ProvisioningStatus {
OK = 0,
INVALID_CERTIFICATE_TYPE = 1,
PROVISIONING_ENGINE_UNINITIALIZED = 2,
INVALID_SERVICE_DRM_CERTIFICATE = 3,
INVALID_PROVISIONER_DRM_CERTIFICATE = 5,
// Invalid provisioner private key or private key passphrase.
INVALID_PROVISIONER_PRIVATE_KEY = 6,
INVALID_INTERMEDIATE_DRM_CERTIFICATE = 7,
INVALID_INTERMEDIATE_PUBLIC_KEY = 8,
// Invalid intermediate private key or private key passphrase.
INVALID_INTERMEDIATE_PRIVATE_KEY = 9,
INVALID_STATUS_LIST = 10,
STATUS_LIST_EXPIRED = 11,
UNKNOWN_SYSTEM_ID = 12,
INVALID_DRM_DEVICE_PUBLIC_KEY = 13,
INVALID_DRM_DEVICE_PRIVATE_KEY = 14,
INVALID_REQUEST_MESSAGE = 15,
INVALID_MAC = 16,
MISSING_DEVICE_MODEL_CERT = 17,
DRM_DEVICE_CERTIFICATE_NOT_SET = 18,
DEVICE_REVOKED = 19,
INVALID_SERIAL_NUMBER = 20,
INTERNAL_ERROR = 21,
INVALID_SPOID_SAUCE = 22,
INVALID_PROTOCOL = 23,
INVALID_CONTEXT_KEY_DATA = 24,
INVALID_CONTEXT = 25,
PROTOCOL_ERROR = 26,
INVALID_KEYBOX_DEVICE_KEY = 27,
INVALID_SESSION_KEYS = 28,
INVALID_PREPROV_KEY = 29,
MISSING_PREPROV_KEY = 30,
REMOTE_ATTESTATION_VERIFICATION_FAILURE = 31,
NUM_PROVISIONING_STATUS,
};
// Returns the message std::string for the given ProvisioningStatus.
std::string GetProvisioningStatusMessage(ProvisioningStatus status);
} // namespace widevine
#endif // PROVISIONING_SDK_PUBLIC_PROVISIONING_STATUS_H_

View 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.
################################################################################
"""Installation file for the certificate_type module."""
import setup_common as common
import setuptools
if __name__ == '__main__':
setuptools.setup(
name='certificate_type',
ext_modules=[
setuptools.Extension(
name='certificate_type',
sources=[
'%s/certificate_type.cc' % common.WVCOMMON_SRC_DIR,
'%s/initcertificate_type.cc' % common.WVCOMMON_SRC_DIR,
'%s/clif/python/runtime.cc' % common.CLIF_PREFIX,
'%s/clif/python/slots.cc' % common.CLIF_PREFIX,
'%s/clif/python/types.cc' % common.CLIF_PREFIX,
],
include_dirs=[
common.SDK_ROOT_DIR, common.GEN_DIR, common.CLIF_PREFIX, '/'
],
extra_compile_args=['-std=c++11'],
library_dirs=[common.SDK_LIBRARY_DIR],
libraries=['provisioning_sdk'],
runtime_library_dirs=[common.SDK_LIBRARY_DIR],
install_requires=['enum34;python_version<"3.4"'],
),
],
)

View File

@@ -0,0 +1,27 @@
################################################################################
# Copyright 2016 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.
################################################################################
"""Utility functions for cryptography."""
import logging
from cryptography.hazmat import backends
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
def VerifySignature(public_key, signature, data):
hash_algorithm = hashes.SHA1()
salt_len = 20
logging.info('Verying signature.')
key = serialization.load_der_public_key(
public_key, backend=backends.default_backend())
key.verify(signature, data,
padding.PSS(padding.MGF1(hash_algorithm), salt_len),
hash_algorithm)

View File

@@ -0,0 +1,54 @@
################################################################################
# Copyright 2016 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.
################################################################################
import unittest
import test_data_utility
from provisioning_engine import ProvisioningEngine
from provisioning_status import ProvisioningStatus
class AddDrmIntermediateTest(unittest.TestCase):
def setUp(self):
self._engine = ProvisioningEngine()
test_data_utility.InitProvisionEngineWithTestData(
self._engine, verify_success=True)
def testGenerateDrmIntermediateCertificateWithValidExpirationPeriod(self):
test_data_utility.SetCertificateStatusListWithTestData(
self._engine, 0, verify_success=True)
test_data_utility.AddDrmIntermediateCertificateWithTestData(
self._engine, 2001, verify_success=True)
def testSetCertificateStatusListInvalid(self):
set_cert_status_list = self._engine.SetCertificateStatusList(
'INVALID_STATUS_LIST', 0)
self.assertEqual(ProvisioningStatus.INVALID_STATUS_LIST,
set_cert_status_list)
def testAddDrmIntermediateCertificateWithoutCertificateStatusList(self):
# Users should not be able to add DRM certificate without having
# certificate status list.
status = test_data_utility.AddDrmIntermediateCertificateWithTestData(
self._engine, 2001)
self.assertEqual(ProvisioningStatus.STATUS_LIST_EXPIRED, status)
def testAddDrmIntermediateCertificateSystemIdInvalid(self):
test_data_utility.SetCertificateStatusListWithTestData(
self._engine, 0, verify_success=True)
# system_id 9999 is not in the sample certificate status list
add_ca_status = test_data_utility.AddDrmIntermediateCertificateWithTestData(
self._engine, 9999)
self.assertEqual(ProvisioningStatus.UNKNOWN_SYSTEM_ID, add_ca_status)
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,67 @@
################################################################################
# Copyright 2016 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.
################################################################################
import unittest
from certificate_type import CertificateType
import crypto_utility
import test_data_provider
import test_data_utility
from provisioning_engine import ProvisioningEngine
from provisioning_status import ProvisioningStatus
from protos.public import signed_drm_certificate_pb2
class EngineGenerateCertificateTest(unittest.TestCase):
def setUp(self):
self._engine = ProvisioningEngine()
test_data_utility.InitProvisionEngineWithTestData(
self._engine, verify_success=True)
test_data_utility.SetCertificateStatusListWithTestData(
self._engine, 0, verify_success=True)
test_data_utility.AddDrmIntermediateCertificateWithTestData(
self._engine, 2001, verify_success=True)
self._data_provider = test_data_provider.TestDataProvider(
CertificateType.kCertificateTypeTesting)
def testSuccess(self):
status, signed_cert_string = self._engine.GenerateDeviceDrmCertificate(
2001, self._data_provider.device_public_key, 'DEVICE_SERIAL_NUMBER')
self.assertEqual(ProvisioningStatus.OK, status)
signed_cert = signed_drm_certificate_pb2.SignedDrmCertificate()
signed_cert.ParseFromString(signed_cert_string)
crypto_utility.VerifySignature(self._data_provider.ca_public_key,
signed_cert.signature,
signed_cert.drm_certificate)
def testEmptySerialNumber(self):
status, _ = self._engine.GenerateDeviceDrmCertificate(
2001, self._data_provider.device_public_key, '')
self.assertEqual(ProvisioningStatus.INVALID_SERIAL_NUMBER, status)
def testEmptyPublicKey(self):
status, _ = self._engine.GenerateDeviceDrmCertificate(
2001, '', 'DEVICE_SERIAL_NUMBER')
self.assertEqual(ProvisioningStatus.INVALID_DRM_DEVICE_PUBLIC_KEY, status)
def testInvalidPublicKey(self):
status, _ = self._engine.GenerateDeviceDrmCertificate(
2001, 'PUBLIC_KEY_MUST_BE_IN_DER_ENCODED_PKCS1_FORMAT',
'DEVICE_SERIAL_NUMBER')
self.assertEqual(ProvisioningStatus.INVALID_DRM_DEVICE_PUBLIC_KEY, status)
def testMissingIntermediateCertificate(self):
status, _ = self._engine.GenerateDeviceDrmCertificate(
2002, self._data_provider.device_public_key, 'DEVICE_SERIAL_NUMBER')
self.assertEqual(ProvisioningStatus.UNKNOWN_SYSTEM_ID, status)
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,167 @@
################################################################################
# Copyright 2016 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.
################################################################################
import unittest
from certificate_type import CertificateType
import test_data_provider
import test_data_utility
from provisioning_engine import ProvisioningEngine
from provisioning_status import ProvisioningStatus
class InitEngineTest(unittest.TestCase):
def setUp(self):
self._engine = ProvisioningEngine()
self._data_provider = test_data_provider.TestDataProvider(
CertificateType.kCertificateTypeTesting)
def testInitEngineSucceed(self):
status = test_data_utility.InitProvisionEngineWithTestData(
self._engine, verify_success=True)
self.assertEqual(ProvisioningStatus.OK, status)
def testSetCertificateStatusListWithoutInit(self):
status = self._engine.SetCertificateStatusList('CERTIFICATE_STATUS_LIST',
3600)
self.assertEqual(ProvisioningStatus.PROVISIONING_ENGINE_UNINITIALIZED,
status)
def testGenerateDrmIntermediateCertificateWithoutInit(self):
status, _ = self._engine.GenerateDrmIntermediateCertificate(
100, 'INTERMEDIATE_PUBLIC_KEY')
self.assertEqual(ProvisioningStatus.PROVISIONING_ENGINE_UNINITIALIZED,
status)
def testAddDrmIntermediateCertificateWithoutInit(self):
status = self._engine.AddDrmIntermediateCertificate(
'INTERMEDIATE_CERTIFICATE', 'INTERMEDIATE_PRIVATE_KEY',
'INTERMEDIATE_PRIVATE_KEY_PASSPHRASE')
self.assertEqual(ProvisioningStatus.PROVISIONING_ENGINE_UNINITIALIZED,
status)
def testGenerateDeviceDrmCertificateWithoutInit(self):
status, _ = self._engine.GenerateDeviceDrmCertificate(
100, 'DEVICE_PUBLIC_KEY', 'DEVICE_SERIAL_NUMBER')
self.assertEqual(ProvisioningStatus.PROVISIONING_ENGINE_UNINITIALIZED,
status)
def testNewProvisioningSessionWithoutInit(self):
session, status = self._engine.NewProvisioningSession(
'DEVICE_PUBLIC_KEY',
'DEVICE_PRIVATE_KEY')
self.assertEqual(ProvisioningStatus.PROVISIONING_ENGINE_UNINITIALIZED,
status)
self.assertIsNone(session)
def testInitEngineInvalidServiceDrmCert(self):
status = self._engine.Initialize(
CertificateType.kCertificateTypeTesting, 'INVALID_CERT',
self._data_provider.service_private_key,
self._data_provider.service_private_key_passphrase,
self._data_provider.provisioner_drm_cert,
self._data_provider.provisioner_private_key,
self._data_provider.provisioner_private_key_passphrase,
self._data_provider.provisioner_spoid_secret)
self.assertEqual(ProvisioningStatus.INVALID_SERVICE_DRM_CERTIFICATE, status)
def testInitEngineInvalidServicePrivateKey(self):
status = self._engine.Initialize(
CertificateType.kCertificateTypeTesting,
self._data_provider.service_drm_cert, 'INVALID_KEY',
self._data_provider.service_private_key_passphrase,
self._data_provider.provisioner_drm_cert,
self._data_provider.provisioner_private_key,
self._data_provider.provisioner_private_key_passphrase,
self._data_provider.provisioner_spoid_secret)
self.assertEqual(ProvisioningStatus.INVALID_SERVICE_DRM_CERTIFICATE, status)
def testInitEngineWrongServicePrivateKey(self):
status = self._engine.Initialize(
CertificateType.kCertificateTypeTesting,
self._data_provider.service_drm_cert,
self._data_provider.provisioner_private_key,
self._data_provider.service_private_key_passphrase,
self._data_provider.provisioner_drm_cert,
self._data_provider.provisioner_private_key,
self._data_provider.provisioner_private_key_passphrase,
self._data_provider.provisioner_spoid_secret)
self.assertEqual(ProvisioningStatus.INVALID_SERVICE_DRM_CERTIFICATE, status)
def testInitEngineInvalidServicePrivateKeyPassphrase(self):
status = self._engine.Initialize(
CertificateType.kCertificateTypeTesting,
self._data_provider.service_drm_cert,
self._data_provider.service_private_key, 'INVALID_PASSPHRASE',
self._data_provider.provisioner_drm_cert,
self._data_provider.provisioner_private_key,
self._data_provider.provisioner_private_key_passphrase,
self._data_provider.provisioner_spoid_secret)
self.assertEqual(ProvisioningStatus.INVALID_SERVICE_DRM_CERTIFICATE, status)
def testInitEngineInvalidDrmCert(self):
status = self._engine.Initialize(
CertificateType.kCertificateTypeTesting,
self._data_provider.service_drm_cert,
self._data_provider.service_private_key,
self._data_provider.service_private_key_passphrase, 'INVALID_CERT',
self._data_provider.provisioner_private_key,
self._data_provider.provisioner_private_key_passphrase,
self._data_provider.provisioner_spoid_secret)
self.assertEqual(ProvisioningStatus.INVALID_PROVISIONER_DRM_CERTIFICATE,
status)
def testInitEngineInvalidDrmPrivateKey(self):
status = self._engine.Initialize(
CertificateType.kCertificateTypeTesting,
self._data_provider.service_drm_cert,
self._data_provider.service_private_key,
self._data_provider.service_private_key_passphrase,
self._data_provider.provisioner_drm_cert, 'INVALID_KEY',
self._data_provider.provisioner_private_key_passphrase,
self._data_provider.provisioner_spoid_secret)
self.assertEqual(ProvisioningStatus.INVALID_PROVISIONER_PRIVATE_KEY, status)
def testInitEngineWrongDrmPrivateKey(self):
status = self._engine.Initialize(
CertificateType.kCertificateTypeTesting,
self._data_provider.service_drm_cert,
self._data_provider.service_private_key,
self._data_provider.service_private_key_passphrase,
self._data_provider.provisioner_drm_cert,
self._data_provider.service_private_key,
self._data_provider.provisioner_private_key_passphrase,
self._data_provider.provisioner_spoid_secret)
self.assertEqual(ProvisioningStatus.INVALID_PROVISIONER_PRIVATE_KEY, status)
def testInitEngineInvalidDrmPrivateKeyPassphrase(self):
status = self._engine.Initialize(
CertificateType.kCertificateTypeTesting,
self._data_provider.service_drm_cert,
self._data_provider.service_private_key,
self._data_provider.service_private_key_passphrase,
self._data_provider.provisioner_drm_cert,
self._data_provider.provisioner_private_key_passphrase,
'INVALID_PASSPHRASE', self._data_provider.provisioner_spoid_secret)
self.assertEqual(ProvisioningStatus.INVALID_PROVISIONER_PRIVATE_KEY, status)
def testInitEngineInvalidSpoidSecret(self):
status = self._engine.Initialize(
CertificateType.kCertificateTypeTesting,
self._data_provider.service_drm_cert,
self._data_provider.service_private_key,
self._data_provider.service_private_key_passphrase,
self._data_provider.provisioner_drm_cert,
self._data_provider.provisioner_private_key,
self._data_provider.provisioner_private_key_passphrase, '')
self.assertEqual(ProvisioningStatus.INVALID_SPOID_SAUCE, status)
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,110 @@
################################################################################
# Copyright 2016 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.
################################################################################
import unittest
from certificate_type import CertificateType
import crypto_utility
import test_data_provider
import test_data_utility
from provisioning_engine import ProvisioningEngine
from provisioning_status import ProvisioningStatus
from protos.public import certificate_provisioning_pb2
from protos.public import signed_drm_certificate_pb2
class NewSessionTest(unittest.TestCase):
def setUp(self):
self._engine = ProvisioningEngine()
test_data_utility.InitProvisionEngineWithTestData(
self._engine, verify_success=True)
test_data_utility.SetCertificateStatusListWithTestData(
self._engine, 0, verify_success=True)
self._data_provider = test_data_provider.TestDataProvider(
CertificateType.kCertificateTypeTesting)
def testNewSessionSuccess(self):
test_data_utility.AddDrmIntermediateCertificateWithTestData(
self._engine, 2001, verify_success=True)
(new_session, _) = test_data_utility.NewProvisioningSessionWithTestData(
self._engine, verify_success=True)
(status, raw_response, _) = new_session.ProcessMessage(
self._data_provider.message)
assert ProvisioningStatus.OK == status
signed_request = test_data_utility.ConvertToSignedProvisioningMessage(
self._data_provider.message)
unsigned_request = certificate_provisioning_pb2.ProvisioningRequest()
unsigned_request.ParseFromString(signed_request.message)
signed_response = test_data_utility.ConvertToSignedProvisioningMessage(
raw_response)
self._VerifyMessageSignature(self._data_provider.service_public_key,
signed_response)
unsigned_response = certificate_provisioning_pb2.ProvisioningResponse()
unsigned_response.ParseFromString(signed_response.message)
self._VerifyProvisioningResponse(unsigned_request, unsigned_response)
def testProcessInvalidMessage(self):
test_data_utility.AddDrmIntermediateCertificateWithTestData(
self._engine, 2001, verify_success=True)
(new_session, _) = test_data_utility.NewProvisioningSessionWithTestData(
self._engine)
(status, _, _) = new_session.ProcessMessage('INVALID_MESSAGE')
self.assertEqual(ProvisioningStatus.INVALID_REQUEST_MESSAGE, status)
def testNewSessionWithoutIntermediateCert(self):
(new_session, _) = test_data_utility.NewProvisioningSessionWithTestData(
self._engine, verify_success=True)
(status, _, _) = new_session.ProcessMessage(self._data_provider.message)
self.assertEqual(ProvisioningStatus.MISSING_DEVICE_MODEL_CERT,
status)
def testNewSessionInvalidDevicePublicKey(self):
test_data_utility.AddDrmIntermediateCertificateWithTestData(
self._engine, 2001, verify_success=True)
(_, session_status) = self._engine.NewProvisioningSession(
'INVALID_PUBLIC_KEY',
self._data_provider.device_private_key)
self.assertEqual(ProvisioningStatus.INVALID_DRM_DEVICE_PUBLIC_KEY,
session_status)
def testNewSessionInvalidDevicePrivateKey(self):
test_data_utility.AddDrmIntermediateCertificateWithTestData(
self._engine, 2001, verify_success=True)
(_, session_status) = self._engine.NewProvisioningSession(
self._data_provider.device_public_key,
'INVALID_PRIVATE_KEY')
self.assertEqual(ProvisioningStatus.INVALID_DRM_DEVICE_PRIVATE_KEY,
session_status)
def _VerifyMessageSignature(self, public_key, signed_response):
crypto_utility.VerifySignature(public_key, signed_response.signature,
signed_response.message)
def _VerifyCertSignature(self, public_key, signed_cert):
crypto_utility.VerifySignature(public_key, signed_cert.signature,
signed_cert.drm_certificate)
def _VerifyProvisioningResponse(self, request, response):
self.assertEqual(request.nonce, response.nonce)
signed_cert = signed_drm_certificate_pb2.SignedDrmCertificate()
signed_cert.ParseFromString(response.device_certificate)
self._VerifyCertSignature(self._data_provider.ca_public_key, signed_cert)
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,44 @@
################################################################################
# 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.
################################################################################
from "common/python/certificate_type.h" import *
from "provisioning_sdk/public/python/provisioning_status.h" import *
from "provisioning_sdk/public/python/provisioning_session.h" import *
from "provisioning_sdk/public/provisioning_engine.h":
namespace `widevine`:
class ProvisioningEngine:
def Initialize(self,
certificate_type: CertificateType,
service_certificate: bytes,
service_private_key: bytes,
service_private_key_passhprase: bytes,
provisioning_drm_certificate: bytes,
provisioning_private_key: bytes,
provisioning_private_key_passhprase: bytes,
secret_spoid_sauce: bytes) -> ProvisioningStatus
def SetCertificateStatusList(self,
certificate_status_list: bytes,
expiration_period_seconds: int) -> ProvisioningStatus
def GenerateDrmIntermediateCertificate(self,
system_id: int,
public_key: bytes) -> (status: ProvisioningStatus,
certificate: bytes)
def AddDrmIntermediateCertificate(self,
intermediate_cert: bytes,
cert_private_key: bytes,
cert_private_key_passhprase: bytes) -> ProvisioningStatus
def NewProvisioningSession(self,
device_public_key: bytes,
device_private_key: bytes) -> (new_session: ProvisioningSession,
status: ProvisioningStatus)
def GenerateDeviceDrmCertificate(self,
system_id: int,
public_key: bytes,
serial_number: bytes) -> (status: ProvisioningStatus,
certificate: bytes)

View File

@@ -0,0 +1,45 @@
################################################################################
# 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.
################################################################################
"""Installation file for the provisioning_engine module."""
import certificate_type
import provisioning_session
import provisioning_status
import setup_common as common
import setuptools
if __name__ == '__main__':
setuptools.setup(
name='provisioning_engine',
ext_modules=[
setuptools.Extension(
name='provisioning_engine',
sources=[
'%s/provisioning_engine.cc' % common.SDK_SRC_DIR,
'%s/initprovisioning_engine.cc' % common.SDK_SRC_DIR,
'%s/clif/python/pyproto.cc' % common.CLIF_PREFIX,
'%s/clif/python/runtime.cc' % common.CLIF_PREFIX,
'%s/clif/python/slots.cc' % common.CLIF_PREFIX,
'%s/clif/python/types.cc' % common.CLIF_PREFIX,
],
include_dirs=[
common.SDK_ROOT_DIR, common.GEN_DIR, common.CLIF_PREFIX, '/'
],
extra_compile_args=['-std=c++11'],
library_dirs=[common.SDK_LIBRARY_DIR],
libraries=['provisioning_sdk', 'protobuf'],
runtime_library_dirs=[common.SDK_LIBRARY_DIR],
install_requires=['enum34;python_version<"3.4"'],
extra_objects=[
certificate_type.__file__,
provisioning_status.__file__,
provisioning_session.__file__,
],
),
],
)

View File

@@ -0,0 +1,16 @@
################################################################################
# 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.
################################################################################
from "provisioning_sdk/public/python/provisioning_status.h" import *
from "provisioning_sdk/public/provisioning_session.h":
namespace `widevine`:
class ProvisioningSession:
def ProcessMessage(self, message: bytes) -> (status: ProvisioningStatus,
response: bytes,
done: bool)

View File

@@ -0,0 +1,38 @@
################################################################################
# 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.
################################################################################
"""Installation file for the provisioning_session module."""
import provisioning_status
import setup_common as common
import setuptools
if __name__ == '__main__':
setuptools.setup(
name='provisioning_session',
ext_modules=[
setuptools.Extension(
name='provisioning_session',
sources=[
'%s/provisioning_session.cc' % common.SDK_SRC_DIR,
'%s/initprovisioning_session.cc' % common.SDK_SRC_DIR,
'%s/clif/python/runtime.cc' % common.CLIF_PREFIX,
'%s/clif/python/slots.cc' % common.CLIF_PREFIX,
'%s/clif/python/types.cc' % common.CLIF_PREFIX,
],
include_dirs=[
common.SDK_ROOT_DIR, common.GEN_DIR, common.CLIF_PREFIX, '/'
],
extra_compile_args=['-std=c++11'],
library_dirs=[common.SDK_LIBRARY_DIR],
libraries=['provisioning_sdk'],
runtime_library_dirs=[common.SDK_LIBRARY_DIR],
install_requires=['enum34;python_version<"3.4"'],
extra_objects=[provisioning_status.__file__],
),
],
)

View File

@@ -0,0 +1,11 @@
################################################################################
# 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.
################################################################################
from "provisioning_sdk/public/provisioning_status.h":
namespace `widevine`:
enum ProvisioningStatus

View 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.
################################################################################
"""Installation file for the provisioning_status module."""
import setup_common as common
import setuptools
if __name__ == '__main__':
setuptools.setup(
name='provisioning_status',
ext_modules=[
setuptools.Extension(
name='provisioning_status',
sources=[
'%s/provisioning_status.cc' % common.SDK_SRC_DIR,
'%s/initprovisioning_status.cc' % common.SDK_SRC_DIR,
'%s/clif/python/runtime.cc' % common.CLIF_PREFIX,
'%s/clif/python/slots.cc' % common.CLIF_PREFIX,
'%s/clif/python/types.cc' % common.CLIF_PREFIX,
],
include_dirs=[
common.SDK_ROOT_DIR, common.GEN_DIR, common.CLIF_PREFIX, '/'
],
extra_compile_args=['-std=c++11'],
library_dirs=[common.SDK_LIBRARY_DIR],
libraries=['provisioning_sdk'],
runtime_library_dirs=[common.SDK_LIBRARY_DIR],
install_requires=['enum34;python_version<"3.4"'],
),
],
)

View File

@@ -0,0 +1,35 @@
################################################################################
# Copyright 2016 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.
################################################################################
import unittest
import test_data_utility
from provisioning_engine import ProvisioningEngine
from provisioning_status import ProvisioningStatus
class SetCertificateStatusListTest(unittest.TestCase):
def setUp(self):
self._engine = ProvisioningEngine()
test_data_utility.InitProvisionEngineWithTestData(
self._engine, verify_success=True)
def testSetCertificateStatusListSuccess(self):
test_data_utility.SetCertificateStatusListWithTestData(
self._engine, 0, verify_success=True)
def testSetCertificateStatusListInvalid(self):
set_cert_status_list = self._engine.SetCertificateStatusList(
'INVALID_STATUS_LIST', 0)
self.assertEqual(ProvisioningStatus.INVALID_STATUS_LIST,
set_cert_status_list)
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,38 @@
################################################################################
# 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.
################################################################################
"""Common definitions for Provisioning SDK python setup files."""
import os
GEN_DIRNAME = 'test_genfiles'
def _GetSdkRootDir():
"""Obtains folder containing |GEN_DIRNAME| that is considered as root dir."""
current_dir = os.path.realpath(os.path.dirname(__file__))
while not os.path.isdir(os.path.join(current_dir, GEN_DIRNAME)):
current_dir = os.path.dirname(current_dir)
os.chdir(current_dir)
return current_dir
SDK_ROOT_DIR = _GetSdkRootDir()
GEN_DIR = '%s/%s' % (SDK_ROOT_DIR, GEN_DIRNAME)
SDK_LIBRARY_DIR = os.path.join(SDK_ROOT_DIR, 'bazel-bin', 'provisioning_sdk',
'public')
if not os.path.exists(SDK_LIBRARY_DIR):
SDK_LIBRARY_DIR = SDK_ROOT_DIR
CLIF_PREFIX = os.environ['CLIF_PREFIX']
BUILD_DIR = os.environ['PYEXT_BUILD_DIR']
WVCOMMON_SRC_DIR = '%s/common/python' % GEN_DIR
WVPROTO_SRC_DIR = '%s/protos/public' % GEN_DIR
SDK_SRC_DIR = '%s/provisioning_sdk/public/python' % GEN_DIR

View File

@@ -0,0 +1,107 @@
# Lint as: python2, python3
################################################################################
# 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.
################################################################################
"""Class that provides test data for Provisioning SDK testing."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
from certificate_type import CertificateType
_TEST_CERT_DATA_FOLDER = os.path.join('example', 'example_data')
_DEV_CERT_DATA_FOLDER = os.path.join('example', 'dev_cert_example_data')
class TestDataProvider(object):
"""For for Test Data."""
def __init__(self, cert_type):
"""Initializes the TestData for Provisioning SDK tests."""
assert (cert_type in (CertificateType.kCertificateTypeDevelopment,
CertificateType.kCertificateTypeTesting))
self._cert_type = cert_type
def _GetTestData(self, filename):
"""Helps read test data files such as certs and keys for SDK testing."""
current_dir = os.path.realpath(os.path.dirname(__file__))
if self._cert_type == CertificateType.kCertificateTypeDevelopment:
subfolder_path = _DEV_CERT_DATA_FOLDER
elif self._cert_type == CertificateType.kCertificateTypeTesting:
subfolder_path = _TEST_CERT_DATA_FOLDER
while not os.path.isdir(os.path.join(current_dir, subfolder_path)):
current_dir = os.path.dirname(current_dir)
filename = os.path.join(current_dir, subfolder_path, filename)
try:
with open(filename, 'rb') as data_file:
data = data_file.read()
return data
except IOError:
print('TestDataProvider: Failed to read \'%s\'' % filename)
return None
@property
def service_drm_cert(self):
return self._GetTestData('service.cert')
@property
def service_public_key(self):
return self._GetTestData('service.public')
@property
def service_private_key(self):
return self._GetTestData('service.encrypted.private')
@property
def service_private_key_passphrase(self):
return self._GetTestData('service.passphrase')
@property
def provisioner_drm_cert(self):
return self._GetTestData('provisioner.cert')
@property
def provisioner_private_key(self):
return self._GetTestData('provisioner.encrypted.private')
@property
def provisioner_private_key_passphrase(self):
return self._GetTestData('provisioner.passphrase')
@property
def provisioner_spoid_secret(self):
return self._GetTestData('provisioner.spoid_secret')
@property
def ca_public_key(self):
return self._GetTestData('intermediate.public')
@property
def ca_private_key(self):
return self._GetTestData('intermediate.encrypted.private')
@property
def ca_private_key_passphrase(self):
return self._GetTestData('intermediate.passphrase')
@property
def device_public_key(self):
return self._GetTestData('device.public')
@property
def device_private_key(self):
return self._GetTestData('device.private')
@property
def message(self):
return self._GetTestData('message')
@property
def certificate_list(self):
return self._GetTestData('certificate_list')

View File

@@ -0,0 +1,184 @@
################################################################################
# Copyright 2016 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.
################################################################################
"""Utility class for Provisioning SDK testing."""
import logging
from certificate_type import CertificateType
import test_data_provider
from provisioning_status import ProvisioningStatus
from protos.public import certificate_provisioning_pb2
logging.basicConfig(level=logging.DEBUG)
def InitProvisionEngineWithTestData(
engine,
verify_success=False,
cert_type=CertificateType.kCertificateTypeTesting):
"""Initialize the provisioning engine with sample credentials.
Args:
engine: a ProvisioningEngine instance
verify_success: whether to verify that resulting status code equals OK
cert_type: The type of certificate to use for initializing SDK -
{kCertificateTypeTesting/kCertificateTypeDevelopment}
Returns:
OK on success, or an appropriate error status code otherwise.
"""
data_provider = test_data_provider.TestDataProvider(cert_type)
logging.info('Adding service certificate.')
logging.info('Initializing provisioning engine with test data.')
status = engine.Initialize(cert_type, data_provider.service_drm_cert,
data_provider.service_private_key,
data_provider.service_private_key_passphrase,
data_provider.provisioner_drm_cert,
data_provider.provisioner_private_key,
data_provider.provisioner_private_key_passphrase,
data_provider.provisioner_spoid_secret)
if verify_success:
assert ProvisioningStatus.OK == status
return status
def SetCertificateStatusListWithTestData(
engine,
expiration_period_seconds,
verify_success=False,
cert_type=CertificateType.kCertificateTypeTesting):
"""Set the certificate status list with sample certificate status list.
Args:
engine: a ProvisioningEngine instance
expiration_period_seconds: number of seconds until certificate_status_list
expires after its creation time
verify_success: whether to verify that resulting status code equals OK
cert_type: The type of certificate to use for initializing SDK -
{kCertificateTypeTesting/kCertificateTypeDevelopment}
Returns:
OK on success, or an appropriate error status code otherwise.
"""
logging.info('Setting certificate status list with test data.')
data_provider = test_data_provider.TestDataProvider(cert_type)
certificate_status_list = data_provider.certificate_list
status = engine.SetCertificateStatusList(certificate_status_list,
expiration_period_seconds)
if verify_success:
assert ProvisioningStatus.OK == status
return status
def AddDrmIntermediateCertificateWithTestData(
engine,
system_id,
verify_success=False,
cert_type=CertificateType.kCertificateTypeTesting):
"""Generate an intermediate DRM cert and add it to provisioning engine.
The intermediate DRM certificate is generated with sample public key and
is added to the provisioning engine with sample certificate private key and
passphrase.
Args:
engine: a ProvisioningEngine instance
system_id: Widevine system ID for the type of device
verify_success: whether to verify that resulting status code equals OK
cert_type: The type of certificate to use for initializing SDK -
{kCertificateTypeTesting/kCertificateTypeDevelopment}
Returns:
OK on success, or an appropriate error status code otherwise.
"""
logging.info('Generating DRM intermediate certificate for system_id <%d>.',
system_id)
data_provider = test_data_provider.TestDataProvider(cert_type)
gen_status, ca_certificate = engine.GenerateDrmIntermediateCertificate(
system_id, data_provider.ca_public_key)
assert ProvisioningStatus.OK == gen_status
logging.info('Adding DRM intermediate certificate.')
add_ca_status = engine.AddDrmIntermediateCertificate(
ca_certificate, data_provider.ca_private_key,
data_provider.ca_private_key_passphrase)
if verify_success:
assert ProvisioningStatus.OK == add_ca_status
return add_ca_status
def GenerateDeviceDrmCertificate(
engine,
system_id,
serial_number,
verify_success=False,
cert_type=CertificateType.kCertificateTypeTesting):
"""Generate a device DRM certificate.
Args:
engine: a ProvisioningEngine instance
system_id: Widevine system ID for the type of device
serial_number: The serial number for the device DRM certificate.
verify_success: whether to verify that resulting status code equals OK
cert_type: The type of certificate to use for initializing SDK -
{kCertificateTypeTesting/kCertificateTypeDevelopment}
Returns:
OK on success, or an appropriate error status code otherwise.
"""
logging.info(
'Generating Device cert for system_id <%d> and serial_number <%s>.',
system_id, serial_number)
data_provider = test_data_provider.TestDataProvider(cert_type)
gen_status, ca_certificate = engine.GenerateDeviceDrmCertificate(
system_id, data_provider.device_public_key, serial_number)
if verify_success:
assert ProvisioningStatus.OK == gen_status
return ca_certificate
def NewProvisioningSessionWithTestData(
engine,
verify_success=False,
cert_type=CertificateType.kCertificateTypeTesting):
"""Create a provisioning session with sample device public and private keys.
Args:
engine: a ProvisioningEngine instance
verify_success: whether to verify that resulting status code equals OK
cert_type: The type of certificate to use for initializing SDK -
{kCertificateTypeTesting/kCertificateTypeDevelopment}
Returns:
new_session: A new provisioning_session.
status: OK on success, or an appropriate error status code otherwise.
"""
logging.info('Starting a new provisioning session with'
'sample device public and private keys.')
data_provider = test_data_provider.TestDataProvider(cert_type)
new_session, status = engine.NewProvisioningSession(
data_provider.device_public_key,
data_provider.device_private_key)
if verify_success:
assert (ProvisioningStatus.OK == status), 'status = %r' % status
return new_session, status
def ConvertToSignedProvisioningMessage(serialized_message):
signed_message = certificate_provisioning_pb2.SignedProvisioningMessage()
signed_message.ParseFromString(serialized_message)
return signed_message

116
run_tests.sh Executable file
View File

@@ -0,0 +1,116 @@
#!/bin/bash
################################################################################
# Copyright 2016 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.
################################################################################
#
# This script generates a directory that stores the intermediate artifacts
# needed for testing.
#
# Prerequirements (if running the script directly):
# - Python 2.7 or later
# - pip: https://pip.pypa.io/en/latest/installing/
# - Python cryptography package: https://cryptography.io/en/latest/installation/
# - Protocol compiler: https://github.com/google/protobuf#protocol-compiler-installation
# On Ubuntu: sudo apt-get install protobuf-compiler
# - Protobuf Python runtime (version 3.0 or later): sudo pip install protobuf
# - CLIF: https://github.com/google/clif
# Environment Variables:
# - TOOLS_PATH: colon-delimited paths to additional tools such as protoc.
# - CLIF_PREFIX: prefix path to CLIF installation.
set -ex
cd "$(dirname "$0")"
if [[ -v TOOLS_PATH ]]; then
export PATH=$PATH:$TOOLS_PATH
fi
if ! which protoc 2>/dev/null; then
echo >&2 "Protobuf is required but not found (did you set TOOLS_PATH?). Aborting."
exit 1
fi
if ! [[ -v CLIF_PREFIX ]]; then
echo >&2 "CLIF_PREFIX not set. Defaulting to '$HOME/opt'."
export CLIF_PREFIX=$HOME/opt
fi
PYCLIF="$CLIF_PREFIX/clif/bin/pyclif"
PYCLIF_PROTO="$CLIF_PREFIX/clif/bin/pyclif_proto"
CLIF_INC="-I$CLIF_PREFIX"
if ! [[ -x $PYCLIF ]]; then
echo >&2 "CLIF is required but not found."
exit 1
fi
# Get the path of the native python C++ header files.
PYTHON_INC="-I$(printf "from distutils.sysconfig import get_python_inc\nprint(get_python_inc())\n" | python)"
SRC_DIR="$(pwd)"
GEN_DIR="$(pwd)/test_genfiles"
PROTO_GEN_DIR="$GEN_DIR/protos/public"
COMMON_GEN_DIR="$GEN_DIR/common/python"
SDK_PYTHON_GEN_DIR="$GEN_DIR/provisioning_sdk/public/python"
export PYEXT_BUILD_DIR="$(pwd)/python_ext_build"
PYEXT_INSTALL_DIR="$(pwd)/python_env"
rm -rf "$GEN_DIR"
rm -rf "$PYEXT_BUILD_DIR"
rm -rf "$PYEXT_INSTALL_DIR"
mkdir -p "$PROTO_GEN_DIR"
mkdir -p "$COMMON_GEN_DIR"
mkdir -p "$SDK_PYTHON_GEN_DIR"
mkdir -p "$PYEXT_BUILD_DIR"
# Generate C++ outputs.
# The protos are needed to compile the public header provisioning_engine.h.
protoc -I="$SRC_DIR" --cpp_out="$GEN_DIR" "$SRC_DIR/protos/public/client_identification.proto"
protoc -I="$SRC_DIR" --cpp_out="$GEN_DIR" "$SRC_DIR/protos/public/remote_attestation.proto"
protoc -I="$SRC_DIR" --cpp_out="$GEN_DIR" "$SRC_DIR/protos/public/certificate_provisioning.proto"
# Generate py outputs.
protoc -I="$SRC_DIR" --python_out="$GEN_DIR" "$SRC_DIR/protos/public/client_identification.proto"
protoc -I="$SRC_DIR" --python_out="$GEN_DIR" "$SRC_DIR/protos/public/hash_algorithm.proto"
protoc -I="$SRC_DIR" --python_out="$GEN_DIR" "$SRC_DIR/protos/public/remote_attestation.proto"
protoc -I="$SRC_DIR" --python_out="$GEN_DIR" "$SRC_DIR/protos/public/provisioned_device_info.proto"
protoc -I="$SRC_DIR" --python_out="$GEN_DIR" "$SRC_DIR/protos/public/certificate_provisioning.proto"
protoc -I="$SRC_DIR" --python_out="$GEN_DIR" "$SRC_DIR/protos/public/signed_drm_certificate.proto"
# Generate CLIF Python wrappers.
"$PYCLIF" --modname certificate_type --ccdeps_out="$COMMON_GEN_DIR/certificate_type.cc" --ccinit_out="$COMMON_GEN_DIR/initcertificate_type.cc" --header_out="$COMMON_GEN_DIR/certificate_type.h" --cc_flags="-std=c++11 -I$SRC_DIR $PYTHON_INC $CLIF_INC" "$SRC_DIR/common/python/certificate_type.clif"
"$PYCLIF" --modname provisioning_status --ccdeps_out="$SDK_PYTHON_GEN_DIR/provisioning_status.cc" --ccinit_out="$SDK_PYTHON_GEN_DIR/initprovisioning_status.cc" --header_out="$SDK_PYTHON_GEN_DIR/provisioning_status.h" --cc_flags="-std=c++11 -I$SRC_DIR $PYTHON_INC $CLIF_INC" "$SRC_DIR/provisioning_sdk/public/python/provisioning_status.clif"
"$PYCLIF" --modname provisioning_session --ccdeps_out="$SDK_PYTHON_GEN_DIR/provisioning_session.cc" --ccinit_out="$SDK_PYTHON_GEN_DIR/initprovisioning_session.cc" --header_out="$SDK_PYTHON_GEN_DIR/provisioning_session.h" --cc_flags="-std=c++11 -I$SRC_DIR -I$GEN_DIR $PYTHON_INC $CLIF_INC" --include_paths="$GEN_DIR" "$SRC_DIR/provisioning_sdk/public/python/provisioning_session.clif"
"$PYCLIF" --modname provisioning_engine --ccdeps_out="$SDK_PYTHON_GEN_DIR/provisioning_engine.cc" --ccinit_out="$SDK_PYTHON_GEN_DIR/initprovisioning_engine.cc" --header_out="$SDK_PYTHON_GEN_DIR/provisioning_engine.h" --cc_flags="-std=c++11 -I$SRC_DIR -I$GEN_DIR $PYTHON_INC $CLIF_INC" --include_paths="$GEN_DIR" "$SRC_DIR/provisioning_sdk/public/python/provisioning_engine.clif"
# Create virtual Python environment, build extensions, and install onto virtual
# environment.
cp -a provisioning_sdk/public/python/* test_genfiles/
cd test_genfiles
rm -rf "$PYEXT_INSTALL_DIR"
virtualenv "$PYEXT_INSTALL_DIR"
"$PYEXT_INSTALL_DIR/bin/python" "$PYEXT_INSTALL_DIR/bin/pip" install enum34
"$PYEXT_INSTALL_DIR/bin/python" "$PYEXT_INSTALL_DIR/bin/pip" install protobuf
"$PYEXT_INSTALL_DIR/bin/python" "$PYEXT_INSTALL_DIR/bin/pip" install cryptography
"$PYEXT_INSTALL_DIR/bin/python" certificate_type_setup.py build --build-base="$PYEXT_BUILD_DIR" install
"$PYEXT_INSTALL_DIR/bin/python" provisioning_status_setup.py build --build-base="$PYEXT_BUILD_DIR" install
"$PYEXT_INSTALL_DIR/bin/python" provisioning_session_setup.py build --build-base="$PYEXT_BUILD_DIR" install
"$PYEXT_INSTALL_DIR/bin/python" provisioning_engine_setup.py build --build-base="$PYEXT_BUILD_DIR" install
shopt -s globstar
for d in "protos"/**/; do
touch -- "$d/__init__.py";
done
"$PYEXT_INSTALL_DIR/bin/python" init_engine_test.py
"$PYEXT_INSTALL_DIR/bin/python" set_certificate_status_list_test.py
"$PYEXT_INSTALL_DIR/bin/python" drm_intermediate_certificate_test.py
"$PYEXT_INSTALL_DIR/bin/python" engine_generate_certificate_test.py
"$PYEXT_INSTALL_DIR/bin/python" new_session_test.py