Update to support OEMCrypto v16 with ODK
This commit is contained in:
22
common/certificate_type.h
Normal file
22
common/certificate_type.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright 2017 Google LLC.
|
||||||
|
//
|
||||||
|
// This software is licensed under the terms defined in the Widevine Master
|
||||||
|
// License Agreement. For a copy of this agreement, please contact
|
||||||
|
// widevine-licensing@google.com.
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef COMMON_CERTIFICATE_TYPE_H_
|
||||||
|
#define COMMON_CERTIFICATE_TYPE_H_
|
||||||
|
|
||||||
|
namespace widevine {
|
||||||
|
|
||||||
|
enum CertificateType {
|
||||||
|
kCertificateTypeTesting,
|
||||||
|
kCertificateTypeDevelopment,
|
||||||
|
kCertificateTypeProduction,
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace widevine
|
||||||
|
|
||||||
|
#endif // COMMON_CERTIFICATE_TYPE_H_
|
||||||
11
common/python/certificate_type.clif
Normal file
11
common/python/certificate_type.clif
Normal 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
|
||||||
BIN
example/example_data/certificate_list
Normal file
BIN
example/example_data/certificate_list
Normal file
Binary file not shown.
BIN
example/example_data/device.private
Normal file
BIN
example/example_data/device.private
Normal file
Binary file not shown.
BIN
example/example_data/device.public
Normal file
BIN
example/example_data/device.public
Normal file
Binary file not shown.
BIN
example/example_data/intermediate.cert
Normal file
BIN
example/example_data/intermediate.cert
Normal file
Binary file not shown.
BIN
example/example_data/intermediate.encrypted.private
Normal file
BIN
example/example_data/intermediate.encrypted.private
Normal file
Binary file not shown.
1
example/example_data/intermediate.passphrase
Normal file
1
example/example_data/intermediate.passphrase
Normal file
@@ -0,0 +1 @@
|
|||||||
|
intermediate_passphrase
|
||||||
BIN
example/example_data/intermediate.public
Normal file
BIN
example/example_data/intermediate.public
Normal file
Binary file not shown.
BIN
example/example_data/message
Normal file
BIN
example/example_data/message
Normal file
Binary file not shown.
BIN
example/example_data/provisioner.cert
Normal file
BIN
example/example_data/provisioner.cert
Normal file
Binary file not shown.
BIN
example/example_data/provisioner.encrypted.private
Normal file
BIN
example/example_data/provisioner.encrypted.private
Normal file
Binary file not shown.
1
example/example_data/provisioner.passphrase
Normal file
1
example/example_data/provisioner.passphrase
Normal file
@@ -0,0 +1 @@
|
|||||||
|
provider_passphrase
|
||||||
BIN
example/example_data/provisioner.public
Normal file
BIN
example/example_data/provisioner.public
Normal file
Binary file not shown.
4
example/example_data/provisioner.spoid_secret
Normal file
4
example/example_data/provisioner.spoid_secret
Normal 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.
|
||||||
BIN
example/example_data/root.private
Normal file
BIN
example/example_data/root.private
Normal file
Binary file not shown.
BIN
example/example_data/service.cert
Normal file
BIN
example/example_data/service.cert
Normal file
Binary file not shown.
BIN
example/example_data/service.encrypted.private
Normal file
BIN
example/example_data/service.encrypted.private
Normal file
Binary file not shown.
1
example/example_data/service.passphrase
Normal file
1
example/example_data/service.passphrase
Normal file
@@ -0,0 +1 @@
|
|||||||
|
service_passphrase
|
||||||
BIN
example/example_data/service.public
Normal file
BIN
example/example_data/service.public
Normal file
Binary file not shown.
113
example/provisioning_example.cc
Normal file
113
example/provisioning_example.cc
Normal 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;
|
||||||
|
}
|
||||||
BIN
example/provisioning_message_generator
Executable file
BIN
example/provisioning_message_generator
Executable file
Binary file not shown.
BIN
libprovisioning_sdk.so
Executable file
BIN
libprovisioning_sdk.so
Executable file
Binary file not shown.
188
protos/public/certificate_provisioning.proto
Normal file
188
protos/public/certificate_provisioning.proto
Normal 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;
|
||||||
|
}
|
||||||
131
protos/public/client_identification.proto
Normal file
131
protos/public/client_identification.proto
Normal 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;
|
||||||
|
}
|
||||||
172
protos/public/device_common.proto
Normal file
172
protos/public/device_common.proto
Normal 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;
|
||||||
|
}
|
||||||
81
protos/public/external_license.proto
Normal file
81
protos/public/external_license.proto
Normal 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;
|
||||||
|
}
|
||||||
20
protos/public/hash_algorithm.proto
Normal file
20
protos/public/hash_algorithm.proto
Normal 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;
|
||||||
|
}
|
||||||
522
protos/public/license_protocol.proto
Normal file
522
protos/public/license_protocol.proto
Normal 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;
|
||||||
|
}
|
||||||
79
protos/public/provisioned_device_info.proto
Normal file
79
protos/public/provisioned_device_info.proto
Normal 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;
|
||||||
|
}
|
||||||
31
protos/public/remote_attestation.proto
Normal file
31
protos/public/remote_attestation.proto
Normal 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;
|
||||||
|
}
|
||||||
32
protos/public/signed_drm_certificate.proto
Normal file
32
protos/public/signed_drm_certificate.proto
Normal 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.
182
provisioning_sdk/public/provisioning_engine.h
Normal file
182
provisioning_sdk/public/provisioning_engine.h
Normal 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_
|
||||||
59
provisioning_sdk/public/provisioning_session.h
Normal file
59
provisioning_sdk/public/provisioning_session.h
Normal 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_
|
||||||
58
provisioning_sdk/public/provisioning_status.h
Normal file
58
provisioning_sdk/public/provisioning_status.h
Normal 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_
|
||||||
36
provisioning_sdk/public/python/certificate_type_setup.py
Normal file
36
provisioning_sdk/public/python/certificate_type_setup.py
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
################################################################################
|
||||||
|
# Copyright 2018 Google LLC.
|
||||||
|
#
|
||||||
|
# This software is licensed under the terms defined in the Widevine Master
|
||||||
|
# License Agreement. For a copy of this agreement, please contact
|
||||||
|
# widevine-licensing@google.com.
|
||||||
|
################################################################################
|
||||||
|
"""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"'],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
27
provisioning_sdk/public/python/crypto_utility.py
Normal file
27
provisioning_sdk/public/python/crypto_utility.py
Normal 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)
|
||||||
@@ -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()
|
||||||
@@ -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()
|
||||||
167
provisioning_sdk/public/python/init_engine_test.py
Normal file
167
provisioning_sdk/public/python/init_engine_test.py
Normal 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()
|
||||||
110
provisioning_sdk/public/python/new_session_test.py
Normal file
110
provisioning_sdk/public/python/new_session_test.py
Normal 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()
|
||||||
44
provisioning_sdk/public/python/provisioning_engine.clif
Normal file
44
provisioning_sdk/public/python/provisioning_engine.clif
Normal 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)
|
||||||
45
provisioning_sdk/public/python/provisioning_engine_setup.py
Normal file
45
provisioning_sdk/public/python/provisioning_engine_setup.py
Normal 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__,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
16
provisioning_sdk/public/python/provisioning_session.clif
Normal file
16
provisioning_sdk/public/python/provisioning_session.clif
Normal 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)
|
||||||
38
provisioning_sdk/public/python/provisioning_session_setup.py
Normal file
38
provisioning_sdk/public/python/provisioning_session_setup.py
Normal 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__],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
11
provisioning_sdk/public/python/provisioning_status.clif
Normal file
11
provisioning_sdk/public/python/provisioning_status.clif
Normal 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
|
||||||
36
provisioning_sdk/public/python/provisioning_status_setup.py
Normal file
36
provisioning_sdk/public/python/provisioning_status_setup.py
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
################################################################################
|
||||||
|
# Copyright 2018 Google LLC.
|
||||||
|
#
|
||||||
|
# This software is licensed under the terms defined in the Widevine Master
|
||||||
|
# License Agreement. For a copy of this agreement, please contact
|
||||||
|
# widevine-licensing@google.com.
|
||||||
|
################################################################################
|
||||||
|
"""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"'],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
@@ -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()
|
||||||
38
provisioning_sdk/public/python/setup_common.py
Normal file
38
provisioning_sdk/public/python/setup_common.py
Normal 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
|
||||||
107
provisioning_sdk/public/python/test_data_provider.py
Normal file
107
provisioning_sdk/public/python/test_data_provider.py
Normal 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')
|
||||||
184
provisioning_sdk/public/python/test_data_utility.py
Normal file
184
provisioning_sdk/public/python/test_data_utility.py
Normal 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
116
run_tests.sh
Executable 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
|
||||||
Reference in New Issue
Block a user