114 lines
4.2 KiB
C++
114 lines
4.2 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
// 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;
|
|
}
|