Release provisioning sdk b3889b8
Change-Id: Ib423c4bada1ec2c47eff174b0d99dc9c8813a5ed
This commit is contained in:
BIN
example/example_data/certificate_list
Normal file
BIN
example/example_data/certificate_list
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/provider.cert
Normal file
BIN
example/example_data/provider.cert
Normal file
Binary file not shown.
BIN
example/example_data/provider.encrypted.private
Normal file
BIN
example/example_data/provider.encrypted.private
Normal file
Binary file not shown.
1
example/example_data/provider.passphrase
Normal file
1
example/example_data/provider.passphrase
Normal file
@@ -0,0 +1 @@
|
|||||||
|
provider_passphrase
|
||||||
BIN
example/example_data/provisioning_message_generator
Executable file
BIN
example/example_data/provisioning_message_generator
Executable 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.
BIN
example/example_data/user.private
Normal file
BIN
example/example_data/user.private
Normal file
Binary file not shown.
BIN
example/example_data/user.public
Normal file
BIN
example/example_data/user.public
Normal file
Binary file not shown.
104
example/provisioning_example.cc
Normal file
104
example/provisioning_example.cc
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "provisioning_sdk/public/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::OK;
|
||||||
|
using widevine::ProvisioningEngine;
|
||||||
|
using widevine::ProvisioningSession;
|
||||||
|
using widevine::kCertDevelopment;
|
||||||
|
|
||||||
|
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(
|
||||||
|
kCertDevelopment, GetContents("example_data/service.cert"),
|
||||||
|
GetContents("example_data/service.encrypted.private"),
|
||||||
|
GetContents("example_data/service.passphrase"),
|
||||||
|
GetContents("example_data/provider.cert"),
|
||||||
|
GetContents("example_data/provider.encrypted.private"),
|
||||||
|
GetContents("example_data/provider.passphrase")) != 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/user.public"),
|
||||||
|
GetContents("example_data/user.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
libprovisioning_sdk.so
Executable file
BIN
libprovisioning_sdk.so
Executable file
Binary file not shown.
88
protos/public/certificate_provisioning.proto
Normal file
88
protos/public/certificate_provisioning.proto
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||||
|
// Author: tinskip@google.com (Thomas Inskip)
|
||||||
|
//
|
||||||
|
// Description:
|
||||||
|
// Public protocol buffer definitions for Widevine Device Certificate
|
||||||
|
// Provisioning protocol.
|
||||||
|
|
||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
package widevine;
|
||||||
|
option java_package = "com.google.video.widevine.protos";
|
||||||
|
|
||||||
|
import "protos/public/client_identification.proto";
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provisioning request sent by client devices to provisioning service.
|
||||||
|
message ProvisioningRequest {
|
||||||
|
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 origin_id {
|
||||||
|
// Stable identifier, unique for each device + application (or origin).
|
||||||
|
// Required if doing per-origin provisioning.
|
||||||
|
bytes stable_id = 4;
|
||||||
|
// Stable content provider ID.
|
||||||
|
bytes provider_id = 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
// 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
|
||||||
|
// SignedDrmDeviceCertificate. 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialized ProvisioningRequest or ProvisioningResponse signed with
|
||||||
|
// The message authentication key.
|
||||||
|
message SignedProvisioningMessage {
|
||||||
|
enum ProtocolVersion {
|
||||||
|
VERSION_2 = 2; // Keybox factory-provisioned devices.
|
||||||
|
VERSION_3 = 3; // OEM certificate factory-provisioned devices.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialized ProvisioningRequest or ProvisioningResponse. Required.
|
||||||
|
optional bytes message = 1;
|
||||||
|
// HMAC-SHA256 (Keybox) or RSASSA-PSS (OEM) signature of message. Required.
|
||||||
|
optional bytes signature = 2;
|
||||||
|
// Version number of provisioning protocol.
|
||||||
|
optional ProtocolVersion protocol_version = 3 [default = VERSION_2];
|
||||||
|
}
|
||||||
82
protos/public/client_identification.proto
Normal file
82
protos/public/client_identification.proto
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||||
|
// Author: tinskip@google.com (Thomas Inskip)
|
||||||
|
//
|
||||||
|
// 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_NO_DIGITAL_OUTPUT = 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptedClientIdentification message used to hold ClientIdentification
|
||||||
|
// messages encrypted for privacy purposes.
|
||||||
|
message EncryptedClientIdentification {
|
||||||
|
// Service ID for which the ClientIdentifcation is encrypted (owner of service
|
||||||
|
// certificate).
|
||||||
|
optional string service_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;
|
||||||
|
}
|
||||||
39
protos/public/provisioned_device_info.proto
Normal file
39
protos/public/provisioned_device_info.proto
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// Description:
|
||||||
|
// Provisioned device info format definitions.
|
||||||
|
|
||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
package widevine;
|
||||||
|
|
||||||
|
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 system ID for the device. Mandatory.
|
||||||
|
optional uint32 system_id = 1;
|
||||||
|
// Name of system-on-a-chip. Optional.
|
||||||
|
optional string soc = 2;
|
||||||
|
// Name of manufacturer. Optional.
|
||||||
|
optional string manufacturer = 3;
|
||||||
|
// Manufacturer's model name. Matches "brand" in device metadata. Optional.
|
||||||
|
optional string model = 4;
|
||||||
|
// Type of device (Phone, Tablet, TV, etc).
|
||||||
|
optional string device_type = 5;
|
||||||
|
// 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];
|
||||||
|
}
|
||||||
19
protos/public/signed_device_certificate.proto
Normal file
19
protos/public/signed_device_certificate.proto
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
// Signed device certificate definition.
|
||||||
|
|
||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
package widevine;
|
||||||
|
|
||||||
|
option java_outer_classname = "SignedDeviceCertificateProtos";
|
||||||
|
option java_package = "com.google.video.widevine.protos";
|
||||||
|
|
||||||
|
// DrmDeviceCertificate signed by a higher (CA) DRM certificate.
|
||||||
|
message SignedDrmDeviceCertificate {
|
||||||
|
// Serialized certificate. Required.
|
||||||
|
optional bytes drm_certificate = 1;
|
||||||
|
// Signature of certificate. Signed with root or intermediate
|
||||||
|
// certificate specified below. Required.
|
||||||
|
optional bytes signature = 2;
|
||||||
|
// SignedDrmDeviceCertificate used to sign this certificate.
|
||||||
|
optional SignedDrmDeviceCertificate signer = 3;
|
||||||
|
}
|
||||||
14
provisioning_sdk/public/certificate_type.h
Normal file
14
provisioning_sdk/public/certificate_type.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#ifndef PROVISIONING_SDK_PUBLIC_CERTIFICATE_TYPE_H_
|
||||||
|
#define PROVISIONING_SDK_PUBLIC_CERTIFICATE_TYPE_H_
|
||||||
|
|
||||||
|
namespace widevine {
|
||||||
|
|
||||||
|
enum CertificateType {
|
||||||
|
kCertTesting = 0,
|
||||||
|
kCertDevelopment,
|
||||||
|
kCertProduction,
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace widevine
|
||||||
|
|
||||||
|
#endif // PROVISIONING_SDK_PUBLIC_CERTIFICATE_TYPE_H_
|
||||||
142
provisioning_sdk/public/provisioning_engine.h
Normal file
142
provisioning_sdk/public/provisioning_engine.h
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
|
||||||
|
#ifndef PROVISIONING_SDK_PUBLIC_PROVISIONING_ENGINE_H_
|
||||||
|
#define PROVISIONING_SDK_PUBLIC_PROVISIONING_ENGINE_H_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "provisioning_sdk/public/certificate_type.h"
|
||||||
|
#include "provisioning_sdk/public/provisioning_status.h"
|
||||||
|
|
||||||
|
namespace widevine {
|
||||||
|
|
||||||
|
class ProvisioningEngineImpl;
|
||||||
|
class ProvisioningSession;
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
~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.
|
||||||
|
// * 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);
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
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.
|
||||||
|
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 provisioning exchange between a client device
|
||||||
|
// and the provisioning server.
|
||||||
|
// * |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.
|
||||||
|
ProvisioningStatus NewProvisioningSession(
|
||||||
|
const std::string& device_public_key,
|
||||||
|
const std::string& device_private_key,
|
||||||
|
std::unique_ptr<ProvisioningSession>* new_session) 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.
|
||||||
|
// * |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:
|
||||||
|
#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_
|
||||||
50
provisioning_sdk/public/provisioning_session.h
Normal file
50
provisioning_sdk/public/provisioning_session.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
|
||||||
|
#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:
|
||||||
|
~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, and the ProvisioningSession can be deleted.
|
||||||
|
// Returns OK if successful, or an appropriate error status code otherwise.
|
||||||
|
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.
|
||||||
|
const ProvisionedDeviceInfo* GetDeviceInfo() const;
|
||||||
|
|
||||||
|
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_
|
||||||
41
provisioning_sdk/public/provisioning_status.h
Normal file
41
provisioning_sdk/public/provisioning_status.h
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
|
||||||
|
#ifndef PROVISIONING_SDK_PUBLIC_PROVISIONING_STATUS_H_
|
||||||
|
#define PROVISIONING_SDK_PUBLIC_PROVISIONING_STATUS_H_
|
||||||
|
|
||||||
|
namespace widevine {
|
||||||
|
|
||||||
|
enum ProvisioningStatus {
|
||||||
|
OK = 0,
|
||||||
|
INVALID_CERTIFICATE_TYPE = 1,
|
||||||
|
PROVISIONING_ENGINE_UNINITIALIZED = 2,
|
||||||
|
INVALID_SERVICE_DRM_CERTIFICATE = 3,
|
||||||
|
// Invalid service private key or private key passphrase.
|
||||||
|
INVALID_SERVICE_PRIVATE_KEY = 4,
|
||||||
|
INVALID_PROVISIONING_DRM_CERTIFICATE = 5,
|
||||||
|
// Invalid provisioning private key or private key passphrase.
|
||||||
|
INVALID_PROVISIONING_PRIVATE_KEY = 6,
|
||||||
|
INVALID_INTERMEDIATE_DRM_CERTIFICATE = 7,
|
||||||
|
// Invalid intermediate private key or private key passphrase.
|
||||||
|
INVALID_INTERMEDIATE_PRIVATE_KEY = 8,
|
||||||
|
INVALID_STATUS_LIST = 9,
|
||||||
|
STATUS_LIST_EXPIRED = 10,
|
||||||
|
UNKNOWN_SYSTEM_ID = 11,
|
||||||
|
INVALID_DEVICE_PUBLIC_KEY = 12,
|
||||||
|
INVALID_DEVICE_PRIVATE_KEY = 13,
|
||||||
|
INVALID_REQUEST_MESSAGE = 14,
|
||||||
|
INVALID_MAC = 15,
|
||||||
|
MISSING_DRM_INTERMEDIATE_CERT = 16,
|
||||||
|
DRM_DEVICE_CERTIFICATE_NOT_SET = 17,
|
||||||
|
DEVICE_REVOKED = 18,
|
||||||
|
INVALID_SERIAL_NUMBER = 19,
|
||||||
|
INTERNAL_ERROR = 20,
|
||||||
|
NUM_PROVISIONING_STATUS,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns the message std::string for the given ProvisioningStatus.
|
||||||
|
const char* GetProvisioningStatusMessage(ProvisioningStatus status);
|
||||||
|
|
||||||
|
} // namespace widevine
|
||||||
|
|
||||||
|
#endif // PROVISIONING_SDK_PUBLIC_PROVISIONING_STATUS_H_
|
||||||
19
provisioning_sdk/public/python/base.i
Normal file
19
provisioning_sdk/public/python/base.i
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
%include "std_string.i"
|
||||||
|
%include "typemaps.i"
|
||||||
|
|
||||||
|
%define %ignoreall %ignore ""; %enddef
|
||||||
|
%define %unignore %rename("%s") %enddef
|
||||||
|
%define %unignoreall %rename("%s") ""; %enddef
|
||||||
|
|
||||||
|
%define COPY_TYPEMAPS(oldtype, newtype)
|
||||||
|
typedef oldtype newtype;
|
||||||
|
%apply oldtype * OUTPUT { newtype * OUTPUT };
|
||||||
|
%apply oldtype & OUTPUT { newtype & OUTPUT };
|
||||||
|
%apply oldtype * INPUT { newtype * INPUT };
|
||||||
|
%apply oldtype & INPUT { newtype & INPUT };
|
||||||
|
%apply oldtype * INOUT { newtype * INOUT };
|
||||||
|
%apply oldtype & INOUT { newtype & INOUT };
|
||||||
|
%enddef
|
||||||
|
|
||||||
|
COPY_TYPEMAPS(int, int32);
|
||||||
|
COPY_TYPEMAPS(unsigned int, uint32);
|
||||||
20
provisioning_sdk/public/python/certificate_type.i
Normal file
20
provisioning_sdk/public/python/certificate_type.i
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// Swig file to generate a Python library for:
|
||||||
|
// provisioning_sdk/public/certificate_type.h
|
||||||
|
|
||||||
|
%module pywrapcertificate_type
|
||||||
|
|
||||||
|
%include "base.i"
|
||||||
|
|
||||||
|
%{
|
||||||
|
#include "provisioning_sdk/public/certificate_type.h"
|
||||||
|
%}
|
||||||
|
|
||||||
|
%ignoreall
|
||||||
|
|
||||||
|
%unignore widevine;
|
||||||
|
%unignore widevine::CertificateType;
|
||||||
|
%unignore widevine::kCertDevelopment;
|
||||||
|
|
||||||
|
%include "provisioning_sdk/public/certificate_type.h"
|
||||||
|
|
||||||
|
%unignoreall
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import unittest
|
||||||
|
|
||||||
|
import pywrapprovisioning_engine
|
||||||
|
import pywrapprovisioning_status
|
||||||
|
import test_data_utility
|
||||||
|
|
||||||
|
|
||||||
|
class AddDrmIntermediateTest(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self._engine = pywrapprovisioning_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(pywrapprovisioning_status.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(pywrapprovisioning_status.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(pywrapprovisioning_status.UNKNOWN_SYSTEM_ID, add_ca_status)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
142
provisioning_sdk/public/python/init_engine_test.py
Normal file
142
provisioning_sdk/public/python/init_engine_test.py
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
import unittest
|
||||||
|
|
||||||
|
import pywrapcertificate_type
|
||||||
|
import pywrapprovisioning_engine
|
||||||
|
import pywrapprovisioning_status
|
||||||
|
import test_data_utility
|
||||||
|
|
||||||
|
|
||||||
|
class InitEngineTest(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self._engine = pywrapprovisioning_engine.ProvisioningEngine()
|
||||||
|
|
||||||
|
def testInitEngineSucceed(self):
|
||||||
|
test_data_utility.InitProvisionEngineWithTestData(
|
||||||
|
self._engine, verify_success=True)
|
||||||
|
|
||||||
|
def testSetCertificateStatusListWithoutInit(self):
|
||||||
|
status = self._engine.SetCertificateStatusList('CERTIFICATE_STATUS_LIST',
|
||||||
|
3600)
|
||||||
|
self.assertEqual(
|
||||||
|
pywrapprovisioning_status.PROVISIONING_ENGINE_UNINITIALIZED, status)
|
||||||
|
|
||||||
|
def testGenerateDrmIntermediateCertificateWithoutInit(self):
|
||||||
|
status, _ = self._engine.GenerateDrmIntermediateCertificate(
|
||||||
|
100, 'INTERMEDIATE_PUBLIC_KEY')
|
||||||
|
self.assertEqual(
|
||||||
|
pywrapprovisioning_status.PROVISIONING_ENGINE_UNINITIALIZED, status)
|
||||||
|
|
||||||
|
def testAddDrmIntermediateCertificateWithoutInit(self):
|
||||||
|
status = self._engine.AddDrmIntermediateCertificate(
|
||||||
|
'INTERMEDIATE_CERTIFICATE', 'INTERMEDIATE_PRIVATE_KEY',
|
||||||
|
'INTERMEDIATE_PRIVATE_KEY_PASSPHRASE')
|
||||||
|
self.assertEqual(
|
||||||
|
pywrapprovisioning_status.PROVISIONING_ENGINE_UNINITIALIZED, status)
|
||||||
|
|
||||||
|
def testGenerateDeviceDrmCertificateWithoutInit(self):
|
||||||
|
status, _ = self._engine.GenerateDeviceDrmCertificate(
|
||||||
|
100, 'DEVICE_PUBLIC_KEY', 'DEVICE_SERIAL_NUMBER')
|
||||||
|
self.assertEqual(
|
||||||
|
pywrapprovisioning_status.PROVISIONING_ENGINE_UNINITIALIZED, status)
|
||||||
|
|
||||||
|
def testNewProvisioningSessionWithoutInit(self):
|
||||||
|
status, session = self._engine.NewProvisioningSession('DEVICE_PUBLIC_KEY',
|
||||||
|
'DEVICE_PRIVATE_KEY')
|
||||||
|
self.assertEqual(
|
||||||
|
pywrapprovisioning_status.PROVISIONING_ENGINE_UNINITIALIZED, status)
|
||||||
|
self.assertIsNone(session)
|
||||||
|
|
||||||
|
def testInitEngineInvalidServiceDrmCert(self):
|
||||||
|
status = self._engine.Initialize(
|
||||||
|
pywrapcertificate_type.kCertDevelopment, 'INVALID_CERT',
|
||||||
|
test_data_utility.SERVICE_PRIVATE_KEY,
|
||||||
|
test_data_utility.SERVICE_PRIVATE_KEY_PASS,
|
||||||
|
test_data_utility.PROVISIONING_DRM_CERT,
|
||||||
|
test_data_utility.PROVISIONING_PRIVATE_KEY,
|
||||||
|
test_data_utility.PROVISIONING_PRIVATE_KEY_PASS)
|
||||||
|
self.assertEqual(pywrapprovisioning_status.INVALID_SERVICE_DRM_CERTIFICATE,
|
||||||
|
status)
|
||||||
|
|
||||||
|
def testInitEngineInvalidServicePrivateKey(self):
|
||||||
|
status = self._engine.Initialize(
|
||||||
|
pywrapcertificate_type.kCertDevelopment,
|
||||||
|
test_data_utility.SERVICE_DRM_CERT, 'INVALID_KEY',
|
||||||
|
test_data_utility.SERVICE_PRIVATE_KEY_PASS,
|
||||||
|
test_data_utility.PROVISIONING_DRM_CERT,
|
||||||
|
test_data_utility.PROVISIONING_PRIVATE_KEY,
|
||||||
|
test_data_utility.PROVISIONING_PRIVATE_KEY_PASS)
|
||||||
|
self.assertEqual(pywrapprovisioning_status.INVALID_SERVICE_PRIVATE_KEY,
|
||||||
|
status)
|
||||||
|
|
||||||
|
def testInitEngineWrongServicePrivateKey(self):
|
||||||
|
status = self._engine.Initialize(
|
||||||
|
pywrapcertificate_type.kCertDevelopment,
|
||||||
|
test_data_utility.SERVICE_DRM_CERT,
|
||||||
|
test_data_utility.PROVISIONING_PRIVATE_KEY,
|
||||||
|
test_data_utility.SERVICE_PRIVATE_KEY_PASS,
|
||||||
|
test_data_utility.PROVISIONING_DRM_CERT,
|
||||||
|
test_data_utility.PROVISIONING_PRIVATE_KEY,
|
||||||
|
test_data_utility.PROVISIONING_PRIVATE_KEY_PASS)
|
||||||
|
self.assertEqual(pywrapprovisioning_status.INVALID_SERVICE_PRIVATE_KEY,
|
||||||
|
status)
|
||||||
|
|
||||||
|
def testInitEngineInvalidServicePrivateKeyPassphrase(self):
|
||||||
|
status = self._engine.Initialize(
|
||||||
|
pywrapcertificate_type.kCertDevelopment,
|
||||||
|
test_data_utility.SERVICE_DRM_CERT,
|
||||||
|
test_data_utility.SERVICE_PRIVATE_KEY, 'INVALID_PASSPHRASE',
|
||||||
|
test_data_utility.PROVISIONING_DRM_CERT,
|
||||||
|
test_data_utility.PROVISIONING_PRIVATE_KEY,
|
||||||
|
test_data_utility.PROVISIONING_PRIVATE_KEY_PASS)
|
||||||
|
self.assertEqual(pywrapprovisioning_status.INVALID_SERVICE_PRIVATE_KEY,
|
||||||
|
status)
|
||||||
|
|
||||||
|
def testInitEngineInvalidDrmCert(self):
|
||||||
|
status = self._engine.Initialize(
|
||||||
|
pywrapcertificate_type.kCertDevelopment,
|
||||||
|
test_data_utility.SERVICE_DRM_CERT,
|
||||||
|
test_data_utility.SERVICE_PRIVATE_KEY,
|
||||||
|
test_data_utility.SERVICE_PRIVATE_KEY_PASS, 'INVALID_CERT',
|
||||||
|
test_data_utility.PROVISIONING_PRIVATE_KEY,
|
||||||
|
test_data_utility.PROVISIONING_PRIVATE_KEY_PASS)
|
||||||
|
self.assertEqual(
|
||||||
|
pywrapprovisioning_status.INVALID_PROVISIONING_DRM_CERTIFICATE, status)
|
||||||
|
|
||||||
|
def testInitEngineInvalidDrmPrivateKey(self):
|
||||||
|
status = self._engine.Initialize(
|
||||||
|
pywrapcertificate_type.kCertDevelopment,
|
||||||
|
test_data_utility.SERVICE_DRM_CERT,
|
||||||
|
test_data_utility.SERVICE_PRIVATE_KEY,
|
||||||
|
test_data_utility.SERVICE_PRIVATE_KEY_PASS,
|
||||||
|
test_data_utility.PROVISIONING_DRM_CERT, 'INVALID_KEY',
|
||||||
|
test_data_utility.PROVISIONING_PRIVATE_KEY_PASS)
|
||||||
|
self.assertEqual(pywrapprovisioning_status.INVALID_PROVISIONING_PRIVATE_KEY,
|
||||||
|
status)
|
||||||
|
|
||||||
|
def testInitEngineWrongDrmPrivateKey(self):
|
||||||
|
status = self._engine.Initialize(
|
||||||
|
pywrapcertificate_type.kCertDevelopment,
|
||||||
|
test_data_utility.SERVICE_DRM_CERT,
|
||||||
|
test_data_utility.SERVICE_PRIVATE_KEY,
|
||||||
|
test_data_utility.SERVICE_PRIVATE_KEY_PASS,
|
||||||
|
test_data_utility.PROVISIONING_DRM_CERT,
|
||||||
|
test_data_utility.SERVICE_PRIVATE_KEY,
|
||||||
|
test_data_utility.PROVISIONING_PRIVATE_KEY_PASS)
|
||||||
|
self.assertEqual(pywrapprovisioning_status.INVALID_PROVISIONING_PRIVATE_KEY,
|
||||||
|
status)
|
||||||
|
|
||||||
|
def testInitEngineInvalidDrmPrivateKeyPassphrase(self):
|
||||||
|
status = self._engine.Initialize(pywrapcertificate_type.kCertDevelopment,
|
||||||
|
test_data_utility.SERVICE_DRM_CERT,
|
||||||
|
test_data_utility.SERVICE_PRIVATE_KEY,
|
||||||
|
test_data_utility.SERVICE_PRIVATE_KEY_PASS,
|
||||||
|
test_data_utility.PROVISIONING_DRM_CERT,
|
||||||
|
test_data_utility.PROVISIONING_PRIVATE_KEY,
|
||||||
|
'INVALID_PASSPHRASE')
|
||||||
|
self.assertEqual(pywrapprovisioning_status.INVALID_PROVISIONING_PRIVATE_KEY,
|
||||||
|
status)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
107
provisioning_sdk/public/python/new_session_test.py
Normal file
107
provisioning_sdk/public/python/new_session_test.py
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
import unittest
|
||||||
|
|
||||||
|
from cryptography.hazmat.backends import default_backend
|
||||||
|
from cryptography.hazmat.primitives.asymmetric import padding
|
||||||
|
from cryptography.hazmat.primitives.serialization import load_der_public_key
|
||||||
|
|
||||||
|
import pywrapprovisioning_engine
|
||||||
|
import pywrapprovisioning_status
|
||||||
|
import test_data_utility
|
||||||
|
from protos.public import certificate_provisioning_pb2
|
||||||
|
from protos.public import signed_device_certificate_pb2
|
||||||
|
|
||||||
|
|
||||||
|
class NewSessionTest(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self._engine = pywrapprovisioning_engine.ProvisioningEngine()
|
||||||
|
test_data_utility.InitProvisionEngineWithTestData(
|
||||||
|
self._engine, verify_success=True)
|
||||||
|
test_data_utility.SetCertificateStatusListWithTestData(
|
||||||
|
self._engine, 0, verify_success=True)
|
||||||
|
|
||||||
|
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(test_data_utility.MESSAGE)
|
||||||
|
test_data_utility.AssertSuccess(status, 'Failed to create session.')
|
||||||
|
|
||||||
|
signed_request = test_data_utility.ConvertToSignedProvisioningMessage(
|
||||||
|
test_data_utility.MESSAGE)
|
||||||
|
|
||||||
|
unsigned_request = certificate_provisioning_pb2.ProvisioningRequest()
|
||||||
|
unsigned_request.ParseFromString(signed_request.message)
|
||||||
|
|
||||||
|
signed_response = test_data_utility.ConvertToSignedProvisioningMessage(
|
||||||
|
raw_response)
|
||||||
|
|
||||||
|
self._VerifyMessageSignature(test_data_utility.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(pywrapprovisioning_status.INVALID_REQUEST_MESSAGE, status)
|
||||||
|
|
||||||
|
def testNewSessionWithoutIntermediateCert(self):
|
||||||
|
(_, new_session) = test_data_utility.NewProvisioningSessionWithTestData(
|
||||||
|
self._engine, verify_success=True)
|
||||||
|
(status, _, _) = new_session.ProcessMessage(test_data_utility.MESSAGE)
|
||||||
|
self.assertEqual(pywrapprovisioning_status.MISSING_DRM_INTERMEDIATE_CERT,
|
||||||
|
status)
|
||||||
|
|
||||||
|
def testNewSessionInvalidDevicePublicKey(self):
|
||||||
|
test_data_utility.AddDrmIntermediateCertificateWithTestData(
|
||||||
|
self._engine, 2001, verify_success=True)
|
||||||
|
(session_status, _) = self._engine.NewProvisioningSession(
|
||||||
|
'INVALID_PUBLIC_KEY', test_data_utility.DEVICE_PRIVATE_KEY)
|
||||||
|
self.assertEqual(pywrapprovisioning_status.INVALID_DEVICE_PUBLIC_KEY,
|
||||||
|
session_status)
|
||||||
|
|
||||||
|
def testNewSessionInvalidDevicePrivateKey(self):
|
||||||
|
test_data_utility.AddDrmIntermediateCertificateWithTestData(
|
||||||
|
self._engine, 2001, verify_success=True)
|
||||||
|
(session_status, _) = self._engine.NewProvisioningSession(
|
||||||
|
test_data_utility.DEVICE_PUBLIC_KEY, 'INVALID_PRIVATE_KEY')
|
||||||
|
self.assertEqual(pywrapprovisioning_status.INVALID_DEVICE_PRIVATE_KEY,
|
||||||
|
session_status)
|
||||||
|
|
||||||
|
def _VerifyMessageSignature(self, public_key, signed_response):
|
||||||
|
self._VerifySignature(public_key, signed_response.signature,
|
||||||
|
signed_response.message)
|
||||||
|
|
||||||
|
def _VerifyCertSignature(self, public_key, signed_cert):
|
||||||
|
self._VerifySignature(public_key, signed_cert.signature,
|
||||||
|
signed_cert.drm_certificate)
|
||||||
|
|
||||||
|
def _VerifyProvisioningResponse(self, request, response):
|
||||||
|
self.assertEqual(request.nonce, response.nonce)
|
||||||
|
|
||||||
|
signed_cert = signed_device_certificate_pb2.SignedDrmDeviceCertificate()
|
||||||
|
signed_cert.ParseFromString(response.device_certificate)
|
||||||
|
|
||||||
|
self._VerifyCertSignature(test_data_utility.CA_PUBLIC_KEY, signed_cert)
|
||||||
|
|
||||||
|
def _VerifySignature(self, public_key, signature, data):
|
||||||
|
key = load_der_public_key(public_key, backend=default_backend())
|
||||||
|
key.verify(signature, data,
|
||||||
|
padding.PSS(
|
||||||
|
padding.MGF1(test_data_utility.HASH_ALGORITHM),
|
||||||
|
test_data_utility.SALT_LEN),
|
||||||
|
test_data_utility.HASH_ALGORITHM)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
41
provisioning_sdk/public/python/provisioning_engine.i
Normal file
41
provisioning_sdk/public/python/provisioning_engine.i
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
// Swig file to generate a Python library for:
|
||||||
|
// provisioning_sdk/public/provisioning_engine.h
|
||||||
|
|
||||||
|
%module pywrapprovisioning_engine
|
||||||
|
|
||||||
|
%include "base.i"
|
||||||
|
%include "unique_ptr.i"
|
||||||
|
%import(module="pywrapprovisioning_session") "provisioning_sdk/public/python/provisioning_session.i"
|
||||||
|
|
||||||
|
UNIQUE_PTR_ARGOUT(widevine::ProvisioningSession, new_session);
|
||||||
|
|
||||||
|
%apply int { CertificateType, ProvisioningStatus };
|
||||||
|
%apply int32 { int32_t };
|
||||||
|
%apply uint32 { uint32_t };
|
||||||
|
|
||||||
|
%apply std::string* OUTPUT { std::string* certificate };
|
||||||
|
|
||||||
|
%{
|
||||||
|
#include "provisioning_sdk/public/provisioning_engine.h"
|
||||||
|
#include "provisioning_sdk/public/provisioning_session.h"
|
||||||
|
using namespace widevine;
|
||||||
|
%}
|
||||||
|
|
||||||
|
%ignoreall
|
||||||
|
|
||||||
|
%unignore widevine;
|
||||||
|
%unignore widevine::ProvisioningSession;
|
||||||
|
|
||||||
|
%unignore widevine::ProvisioningEngine;
|
||||||
|
%unignore widevine::ProvisioningEngine::ProvisioningEngine;
|
||||||
|
%unignore widevine::ProvisioningEngine::~ProvisioningEngine;
|
||||||
|
%unignore widevine::ProvisioningEngine::SetCertificateStatusList;
|
||||||
|
%unignore widevine::ProvisioningEngine::Initialize;
|
||||||
|
%unignore widevine::ProvisioningEngine::GenerateDrmIntermediateCertificate;
|
||||||
|
%unignore widevine::ProvisioningEngine::AddDrmIntermediateCertificate;
|
||||||
|
%unignore widevine::ProvisioningEngine::NewProvisioningSession;
|
||||||
|
%unignore widevine::ProvisioningEngine::GenerateDeviceDrmCertificate;
|
||||||
|
|
||||||
|
%include "provisioning_sdk/public/provisioning_engine.h"
|
||||||
|
|
||||||
|
%unignoreall
|
||||||
29
provisioning_sdk/public/python/provisioning_session.i
Normal file
29
provisioning_sdk/public/python/provisioning_session.i
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// Swig file to generate a Python library for:
|
||||||
|
// provisioning_sdk/public/provisioning_session.h
|
||||||
|
|
||||||
|
%module pywrapprovisioning_session
|
||||||
|
|
||||||
|
%include "base.i"
|
||||||
|
|
||||||
|
%apply bool* OUTPUT { bool* done };
|
||||||
|
|
||||||
|
%apply int { ProvisioningStatus };
|
||||||
|
|
||||||
|
%apply std::string* OUTPUT { std::string* response };
|
||||||
|
|
||||||
|
%{
|
||||||
|
#include "provisioning_sdk/public/provisioning_session.h"
|
||||||
|
using namespace widevine;
|
||||||
|
%}
|
||||||
|
|
||||||
|
%ignoreall
|
||||||
|
|
||||||
|
%unignore widevine;
|
||||||
|
%unignore widevine::ProvisioningSession;
|
||||||
|
%unignore widevine::ProvisioningSession::~ProvisioningSession;
|
||||||
|
%unignore widevine::ProvisioningSession::ProcessMessage;
|
||||||
|
|
||||||
|
|
||||||
|
%include "provisioning_sdk/public/provisioning_session.h"
|
||||||
|
|
||||||
|
%unignoreall
|
||||||
34
provisioning_sdk/public/python/provisioning_status.i
Normal file
34
provisioning_sdk/public/python/provisioning_status.i
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// Swig file to generate a Python library for:
|
||||||
|
// provisioning_sdk/public/provisioning_status.h
|
||||||
|
|
||||||
|
%module pywrapprovisioning_status
|
||||||
|
|
||||||
|
%include "base.i"
|
||||||
|
|
||||||
|
%{
|
||||||
|
#include "provisioning_sdk/public/provisioning_status.h"
|
||||||
|
%}
|
||||||
|
|
||||||
|
%ignoreall
|
||||||
|
|
||||||
|
%unignore widevine;
|
||||||
|
%unignore widevine::ProvisioningStatus;
|
||||||
|
%unignore widevine::OK;
|
||||||
|
%unignore widevine::PROVISIONING_ENGINE_UNINITIALIZED;
|
||||||
|
%unignore widevine::INVALID_SERVICE_DRM_CERTIFICATE;
|
||||||
|
%unignore widevine::INVALID_SERVICE_PRIVATE_KEY;
|
||||||
|
%unignore widevine::INVALID_PROVISIONING_DRM_CERTIFICATE;
|
||||||
|
%unignore widevine::INVALID_PROVISIONING_PRIVATE_KEY;
|
||||||
|
%unignore widevine::INVALID_STATUS_LIST;
|
||||||
|
%unignore widevine::STATUS_LIST_EXPIRED;
|
||||||
|
%unignore widevine::UNKNOWN_SYSTEM_ID;
|
||||||
|
%unignore widevine::INVALID_DEVICE_PUBLIC_KEY;
|
||||||
|
%unignore widevine::INVALID_DEVICE_PRIVATE_KEY;
|
||||||
|
%unignore widevine::INVALID_REQUEST_MESSAGE;
|
||||||
|
%unignore widevine::MISSING_DRM_INTERMEDIATE_CERT;
|
||||||
|
%unignore widevine::DEVICE_REVOKED;
|
||||||
|
%unignore widevine::GetProvisioningStatusMessage;
|
||||||
|
|
||||||
|
%include "provisioning_sdk/public/provisioning_status.h"
|
||||||
|
|
||||||
|
%unignoreall
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import unittest
|
||||||
|
|
||||||
|
import pywrapprovisioning_engine
|
||||||
|
import pywrapprovisioning_status
|
||||||
|
import test_data_utility
|
||||||
|
|
||||||
|
|
||||||
|
class SetCertificateStatusListTest(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self._engine = pywrapprovisioning_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(pywrapprovisioning_status.INVALID_STATUS_LIST,
|
||||||
|
set_cert_status_list)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
55
provisioning_sdk/public/python/setup.py
Normal file
55
provisioning_sdk/public/python/setup.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
"""setup script to build Python wrappers using swig configurations."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from distutils.core import Extension
|
||||||
|
from distutils.core import setup
|
||||||
|
|
||||||
|
OUT_DIRNAME = 'test_genfiles'
|
||||||
|
|
||||||
|
|
||||||
|
def GetSdkRootDir():
|
||||||
|
"""Obtains folder containing |OUT_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, OUT_DIRNAME)):
|
||||||
|
current_dir = os.path.dirname(current_dir)
|
||||||
|
return current_dir
|
||||||
|
|
||||||
|
|
||||||
|
SDK_ROOT_DIR = GetSdkRootDir()
|
||||||
|
|
||||||
|
SWIG_CONFIG_FILE = os.path.join(SDK_ROOT_DIR, OUT_DIRNAME, '%s.i')
|
||||||
|
SWIG_CONFIG_MODULE_PATH = OUT_DIRNAME + '.%s'
|
||||||
|
|
||||||
|
SDK_LIBRARY_DIR = os.path.join(SDK_ROOT_DIR, 'bazel-bin', 'provisioning_sdk',
|
||||||
|
'public')
|
||||||
|
|
||||||
|
|
||||||
|
def ProvisioningSwigExtension(extension_name):
|
||||||
|
return Extension(
|
||||||
|
name=SWIG_CONFIG_MODULE_PATH % ('_pywrap' + extension_name),
|
||||||
|
sources=[SWIG_CONFIG_FILE % extension_name],
|
||||||
|
include_dirs=[SDK_ROOT_DIR],
|
||||||
|
swig_opts=['-c++'],
|
||||||
|
library_dirs=[SDK_ROOT_DIR, SDK_LIBRARY_DIR],
|
||||||
|
runtime_library_dirs=[SDK_ROOT_DIR, SDK_LIBRARY_DIR],
|
||||||
|
libraries=['provisioning_sdk'],
|
||||||
|
extra_compile_args=['-std=c++11'])
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
os.chdir(SDK_ROOT_DIR)
|
||||||
|
setup(
|
||||||
|
name='provisioning_sdk',
|
||||||
|
ext_modules=[
|
||||||
|
ProvisioningSwigExtension('certificate_type'),
|
||||||
|
ProvisioningSwigExtension('provisioning_status'),
|
||||||
|
ProvisioningSwigExtension('provisioning_session'),
|
||||||
|
ProvisioningSwigExtension('provisioning_engine')
|
||||||
|
],
|
||||||
|
py_modules=[
|
||||||
|
SWIG_CONFIG_MODULE_PATH % 'pywrapcertificate_type',
|
||||||
|
SWIG_CONFIG_MODULE_PATH % 'pywarpprovisioning_status',
|
||||||
|
SWIG_CONFIG_MODULE_PATH % 'pywrapprovisioning_session',
|
||||||
|
SWIG_CONFIG_MODULE_PATH % 'pywrapprovisioning_engine'
|
||||||
|
])
|
||||||
146
provisioning_sdk/public/python/test_data_utility.py
Normal file
146
provisioning_sdk/public/python/test_data_utility.py
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
"""Utility class for Provisioning SDK testing."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from cryptography.hazmat.primitives import hashes
|
||||||
|
|
||||||
|
import pywrapcertificate_type
|
||||||
|
import pywrapprovisioning_status
|
||||||
|
from protos.public import certificate_provisioning_pb2
|
||||||
|
|
||||||
|
HASH_ALGORITHM = hashes.SHA1()
|
||||||
|
SALT_LEN = 20
|
||||||
|
|
||||||
|
TEST_DATA_FOLDER = os.path.join('example', 'example_data')
|
||||||
|
|
||||||
|
|
||||||
|
def GetTestData(filename):
|
||||||
|
current_dir = os.path.realpath(os.path.dirname(__file__))
|
||||||
|
while not os.path.isdir(os.path.join(current_dir, TEST_DATA_FOLDER)):
|
||||||
|
current_dir = os.path.dirname(current_dir)
|
||||||
|
filename = os.path.join(current_dir, TEST_DATA_FOLDER, filename)
|
||||||
|
with open(filename, 'rb') as data_file:
|
||||||
|
data = data_file.read()
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
SERVICE_DRM_CERT = GetTestData('service.cert')
|
||||||
|
SERVICE_PUBLIC_KEY = GetTestData('service.public')
|
||||||
|
SERVICE_PRIVATE_KEY = GetTestData('service.encrypted.private')
|
||||||
|
SERVICE_PRIVATE_KEY_PASS = GetTestData('service.passphrase')
|
||||||
|
PROVISIONING_DRM_CERT = GetTestData('provider.cert')
|
||||||
|
PROVISIONING_PRIVATE_KEY = GetTestData('provider.encrypted.private')
|
||||||
|
PROVISIONING_PRIVATE_KEY_PASS = GetTestData('provider.passphrase')
|
||||||
|
CA_PUBLIC_KEY = GetTestData('intermediate.public')
|
||||||
|
DEVICE_PUBLIC_KEY = GetTestData('user.public')
|
||||||
|
DEVICE_PRIVATE_KEY = GetTestData('user.private')
|
||||||
|
MESSAGE = GetTestData('message')
|
||||||
|
|
||||||
|
|
||||||
|
def InitProvisionEngineWithTestData(engine, verify_success=False):
|
||||||
|
"""Initialize the provisioning engine with sample credentials.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
engine: a pywrapprovisioning_engine.ProvisioningEngine instance
|
||||||
|
verify_success: whether to verify that resulting status code equals OK
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
OK on success, or an appropriate error status code otherwise.
|
||||||
|
"""
|
||||||
|
status = engine.Initialize(pywrapcertificate_type.kCertDevelopment,
|
||||||
|
SERVICE_DRM_CERT, SERVICE_PRIVATE_KEY,
|
||||||
|
SERVICE_PRIVATE_KEY_PASS, PROVISIONING_DRM_CERT,
|
||||||
|
PROVISIONING_PRIVATE_KEY,
|
||||||
|
PROVISIONING_PRIVATE_KEY_PASS)
|
||||||
|
if verify_success:
|
||||||
|
AssertSuccess(status, 'Failed to initialize.')
|
||||||
|
return status
|
||||||
|
|
||||||
|
|
||||||
|
def SetCertificateStatusListWithTestData(engine,
|
||||||
|
expiration_period_seconds,
|
||||||
|
verify_success=False):
|
||||||
|
"""Set the certificate status list with sample certificate status list.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
engine: a pywrapprovisioning_engine.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
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
OK on success, or an appropriate error status code otherwise.
|
||||||
|
"""
|
||||||
|
certificate_status_list = GetTestData('certificate_list')
|
||||||
|
|
||||||
|
status = engine.SetCertificateStatusList(certificate_status_list,
|
||||||
|
expiration_period_seconds)
|
||||||
|
|
||||||
|
if verify_success:
|
||||||
|
AssertSuccess(status, 'Failed to set certificate status list.')
|
||||||
|
|
||||||
|
return status
|
||||||
|
|
||||||
|
|
||||||
|
def AddDrmIntermediateCertificateWithTestData(engine,
|
||||||
|
system_id,
|
||||||
|
verify_success=False):
|
||||||
|
"""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 pywrapprovisioning_engine.ProvisioningEngine instance
|
||||||
|
system_id: Widevine system ID for the type of device
|
||||||
|
verify_success: whether to verify that resulting status code equals OK
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
OK on success, or an appropriate error status code otherwise.
|
||||||
|
"""
|
||||||
|
ca_private_key = GetTestData('intermediate.encrypted.private')
|
||||||
|
ca_private_key_passphrase = GetTestData('intermediate.passphrase')
|
||||||
|
|
||||||
|
gen_status, ca_certificate = engine.GenerateDrmIntermediateCertificate(
|
||||||
|
system_id, CA_PUBLIC_KEY)
|
||||||
|
AssertSuccess(gen_status, 'Failed to generate intermediate certificate.')
|
||||||
|
|
||||||
|
add_ca_status = engine.AddDrmIntermediateCertificate(
|
||||||
|
ca_certificate, ca_private_key, ca_private_key_passphrase)
|
||||||
|
|
||||||
|
if verify_success:
|
||||||
|
AssertSuccess(add_ca_status, 'Failed to add intermediate certificate.')
|
||||||
|
|
||||||
|
return add_ca_status
|
||||||
|
|
||||||
|
|
||||||
|
def NewProvisioningSessionWithTestData(engine, verify_success=False):
|
||||||
|
"""Create a provisioning session with sample device public and private keys.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
engine: a pywrapprovisioning_engine.ProvisioningEngine instance
|
||||||
|
verify_success: whether to verify that resulting status code equals OK
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
status: OK on success, or an appropriate error status code otherwise.
|
||||||
|
new_session: A new provisioning_session.
|
||||||
|
"""
|
||||||
|
status, new_session = engine.NewProvisioningSession(DEVICE_PUBLIC_KEY,
|
||||||
|
DEVICE_PRIVATE_KEY)
|
||||||
|
|
||||||
|
if verify_success:
|
||||||
|
AssertSuccess(status, 'Failed to create session.')
|
||||||
|
|
||||||
|
return (status, new_session)
|
||||||
|
|
||||||
|
|
||||||
|
def AssertSuccess(status, message=None):
|
||||||
|
"""Assert status equals OK."""
|
||||||
|
assert pywrapprovisioning_status.OK == status, message
|
||||||
|
|
||||||
|
|
||||||
|
def ConvertToSignedProvisioningMessage(serialized_message):
|
||||||
|
signed_message = certificate_provisioning_pb2.SignedProvisioningMessage()
|
||||||
|
signed_message.ParseFromString(serialized_message)
|
||||||
|
return signed_message
|
||||||
43
provisioning_sdk/public/python/unique_ptr.i
Normal file
43
provisioning_sdk/public/python/unique_ptr.i
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
namespace std {
|
||||||
|
template <class T> class unique_ptr {};
|
||||||
|
}
|
||||||
|
|
||||||
|
%define _UNIQUE_PTR_TEMPLATE(type)
|
||||||
|
template <> class std::unique_ptr <type> {};
|
||||||
|
%enddef
|
||||||
|
|
||||||
|
%define UNIQUE_PTR(type)
|
||||||
|
_UNIQUE_PTR_TEMPLATE(type);
|
||||||
|
|
||||||
|
%typemap(out) std::unique_ptr<type> %{
|
||||||
|
$result = SWIG_NewPointerObj(
|
||||||
|
SWIG_as_voidptr($1.release()), $descriptor(type*), SWIG_POINTER_OWN);
|
||||||
|
%}
|
||||||
|
%enddef
|
||||||
|
|
||||||
|
%define UNIQUE_PTR_WITH_ERROR(type, err_str)
|
||||||
|
_UNIQUE_PTR_TEMPLATE(type);
|
||||||
|
|
||||||
|
%typemap(out) std::unique_ptr<type> %{
|
||||||
|
if ($1) {
|
||||||
|
$result = SWIG_NewPointerObj(
|
||||||
|
SWIG_as_voidptr($1.release()), $descriptor(type*), SWIG_POINTER_OWN);
|
||||||
|
} else {
|
||||||
|
SWIG_exception(SWIG_ValueError, err_str);
|
||||||
|
}
|
||||||
|
%}
|
||||||
|
%enddef
|
||||||
|
|
||||||
|
%define UNIQUE_PTR_ARGOUT(type, arg_name)
|
||||||
|
_UNIQUE_PTR_TEMPLATE(type)
|
||||||
|
|
||||||
|
%typemap(in, numinputs=0) std::unique_ptr<type>* arg_name
|
||||||
|
(std::unique_ptr<type> temp) %{
|
||||||
|
$1 = &temp;
|
||||||
|
%}
|
||||||
|
|
||||||
|
%typemap(argout) std::unique_ptr<type>* arg_name %{
|
||||||
|
%append_output(SWIG_NewPointerObj(SWIG_as_voidptr($1->release()),
|
||||||
|
$descriptor(type*), SWIG_POINTER_OWN));
|
||||||
|
%}
|
||||||
|
%enddef
|
||||||
41
run_tests.sh
Executable file
41
run_tests.sh
Executable file
@@ -0,0 +1,41 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
# - swig: http://www.i.org/download.html
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
hash protoc 2>/dev/null || { echo >&2 "protobuf is required but not installed. Aborting."; exit 1; }
|
||||||
|
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
|
rm -rf test_genfiles
|
||||||
|
mkdir test_genfiles
|
||||||
|
|
||||||
|
protoc -I="$(pwd)" --python_out="$(pwd)/test_genfiles" "$(pwd)/protos/public/client_identification.proto"
|
||||||
|
protoc -I="$(pwd)" --python_out="$(pwd)/test_genfiles" "$(pwd)/protos/public/provisioned_device_info.proto"
|
||||||
|
protoc -I="$(pwd)" --python_out="$(pwd)/test_genfiles" "$(pwd)/protos/public/certificate_provisioning.proto"
|
||||||
|
protoc -I="$(pwd)" --python_out="$(pwd)/test_genfiles" "$(pwd)/protos/public/signed_device_certificate.proto"
|
||||||
|
|
||||||
|
cp provisioning_sdk/public/python/* test_genfiles/
|
||||||
|
cd test_genfiles
|
||||||
|
python setup.py build_ext --inplace
|
||||||
|
|
||||||
|
shopt -s globstar
|
||||||
|
for d in "protos"/**/; do
|
||||||
|
touch -- "$d/__init__.py";
|
||||||
|
done;
|
||||||
|
|
||||||
|
python init_engine_test.py
|
||||||
|
python set_certificate_status_list_test.py
|
||||||
|
python drm_intermediate_certificate_test.py
|
||||||
|
python new_session_test.py
|
||||||
Reference in New Issue
Block a user