Refactor and cleanup codes. No functional changes.

This commit is contained in:
KongQun Yang
2019-01-23 15:16:31 -08:00
parent 84f66d2320
commit 93265ab9d1
207 changed files with 14893 additions and 3332 deletions

View File

@@ -1,5 +1,5 @@
################################################################################
# Copyright 2016 Google Inc.
# 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
@@ -12,7 +12,9 @@
package_group(
name = "internal",
packages = [
"//arcpp_provisioning/...",
"//provisioning_sdk/...",
"//sigma101_provisioning/...",
],
)
@@ -27,14 +29,21 @@ cc_library(
deps = [
":oem_device_cert",
"//base",
"@abseil_repo//absl/synchronization",
"//common:aes_cbc_util",
"//common:certificate_type",
"//common:crypto_util",
"//common:drm_root_certificate",
"//common:drm_service_certificate",
"//common:random_util",
"//common:rsa_key",
"//provisioning_sdk/internal/certificates:root_certificates",
"//provisioning_sdk/public:certificate_type",
"//provisioning_sdk/internal/certificates:root_oem_certificates",
"//provisioning_sdk/public:provisioning_status",
"//protos/public:device_certificate_proto",
"//protos/public:certificate_provisioning_proto",
"//protos/public:device_certificate_status_proto",
"//protos/public:drm_certificate_proto",
"//protos/public:provisioned_device_info_proto",
"//protos/public:signed_device_certificate_proto",
"//protos/public:signed_drm_certificate_proto",
],
)
@@ -45,9 +54,15 @@ cc_test(
deps = [
":provisioning_engine_impl",
"//base",
"//external:gtest_main",
"//testing:gunit_main",
"//common:certificate_type",
"//common:drm_service_certificate",
"//common:mock_rsa_key",
"//provisioning_sdk/public:certificate_type",
"//common:rsa_test_keys",
"//common:rsa_util",
"//common:status",
"//common:test_drm_certificates",
"//protos/public:certificate_provisioning_proto",
],
)
@@ -56,18 +71,9 @@ cc_library(
srcs = ["provisioning_session_impl.cc"],
hdrs = ["provisioning_session_impl.h"],
deps = [
":oem_device_cert",
":provisioning_engine_impl",
"//base",
"//common:aes_cbc_util",
"//common:random_util",
"//common:rsa_key",
"//common:sha_util",
"//provisioning_sdk/public:provisioning_status",
"//protos/public:certificate_provisioning_proto",
"//protos/public:client_identification_proto",
"//protos/public:device_certificate_proto",
"//protos/public:provisioned_device_info_proto",
],
)
@@ -75,11 +81,46 @@ cc_test(
name = "provisioning_session_impl_test",
size = "small",
srcs = ["provisioning_session_impl_test.cc"],
deps = [
":provisioning_engine_impl",
":provisioning_session_impl",
"//testing:gunit_main",
"//common:mock_rsa_key",
],
)
cc_library(
name = "provisioning30_session_impl",
srcs = ["provisioning30_session_impl.cc"],
hdrs = ["provisioning30_session_impl.h"],
deps = [
":oem_device_cert",
":provisioning_engine_impl",
":provisioning_session_impl",
"//external:gtest_main",
"//base",
"//common:aes_cbc_util",
"//common:drm_service_certificate",
"//common:random_util",
"//common:rsa_key",
"//common:sha_util",
"//provisioning_sdk/public:provisioning_status",
"//protos/public:certificate_provisioning_proto",
"//protos/public:client_identification_proto",
"//protos/public:drm_certificate_proto",
"//protos/public:provisioned_device_info_proto",
],
)
cc_test(
name = "provisioning30_session_impl_test",
size = "small",
srcs = ["provisioning30_session_impl_test.cc"],
deps = [
":oem_device_cert",
":provisioning30_session_impl",
":provisioning_engine_impl",
":provisioning_session_impl",
"//testing:gunit_main",
"//common:aes_cbc_util",
"//common:mock_rsa_key",
"//common:sha_util",
@@ -92,11 +133,12 @@ cc_library(
hdrs = ["oem_device_cert.h"],
deps = [
"//base",
"@abseil_repo//absl/memory",
"//external:openssl",
"//common:certificate_type",
"//common:openssl_util",
"//common:rsa_key",
"//provisioning_sdk/internal/certificates:root_certificates",
"//provisioning_sdk/public:certificate_type",
"//provisioning_sdk/internal/certificates:root_oem_certificates",
],
)
@@ -106,7 +148,8 @@ cc_test(
srcs = ["oem_device_cert_test.cc"],
deps = [
":oem_device_cert",
"//external:gtest_main",
"//provisioning_sdk/internal/certificates:test_certificates",
"//testing:gunit_main",
"//common:rsa_key",
"//provisioning_sdk/internal/certificates:test_oem_certificates",
],
)

View File

@@ -1,5 +1,5 @@
################################################################################
# Copyright 2016 Google Inc.
# 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
@@ -13,37 +13,13 @@ package(
)
cc_library(
name = "root_certificates",
name = "root_oem_certificates",
srcs = [
"root_certificates.cc",
":drm_ca_root_dev_cert",
":drm_ca_root_prod_cert",
":drm_ca_root_test_cert",
"root_oem_certificates.cc",
":oem_ca_root_dev_der",
":oem_ca_root_prod_der",
],
hdrs = ["root_certificates.h"],
)
genrule(
name = "drm_ca_root_test_cert",
srcs = ["drm_ca_root_test.cert"],
outs = ["drm_ca_root_test_cert.h"],
cmd = "cd $$(dirname $<) && xxd -i $$(basename $<) $$OLDPWD/$@",
)
genrule(
name = "drm_ca_root_dev_cert",
srcs = ["drm_ca_root_dev.cert"],
outs = ["drm_ca_root_dev_cert.h"],
cmd = "cd $$(dirname $<) && xxd -i $$(basename $<) $$OLDPWD/$@",
)
genrule(
name = "drm_ca_root_prod_cert",
srcs = ["drm_ca_root_prod.cert"],
outs = ["drm_ca_root_prod_cert.h"],
cmd = "cd $$(dirname $<) && xxd -i $$(basename $<) $$OLDPWD/$@",
hdrs = ["root_oem_certificates.h"],
)
genrule(
@@ -61,9 +37,9 @@ genrule(
)
cc_library(
name = "test_certificates",
name = "test_oem_certificates",
srcs = [
"test_certificates.cc",
"test_oem_certificates.cc",
":backwards_chain_der",
":expired_2000_chain_der",
":invalid_chain_der",
@@ -71,7 +47,7 @@ cc_library(
":sysid_2001_chain_der",
":sysid_2001_public_key_der",
],
hdrs = ["test_certificates.h"],
hdrs = ["test_oem_certificates.h"],
)
genrule(

View File

@@ -1,38 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// 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 "provisioning_sdk/internal/certificates/root_certificates.h"
#include "provisioning_sdk/internal/certificates/drm_ca_root_dev_cert.h"
#include "provisioning_sdk/internal/certificates/drm_ca_root_prod_cert.h"
#include "provisioning_sdk/internal/certificates/drm_ca_root_test_cert.h"
#include "provisioning_sdk/internal/certificates/oem_ca_root_dev_cert.h"
#include "provisioning_sdk/internal/certificates/oem_ca_root_prod_cert.h"
namespace widevine {
RootCertificates::RootCertificates()
: drm_root_test_certificate_(
drm_ca_root_test_cert,
drm_ca_root_test_cert + drm_ca_root_test_cert_len),
drm_root_dev_certificate_(
drm_ca_root_dev_cert,
drm_ca_root_dev_cert + drm_ca_root_dev_cert_len),
drm_root_prod_certificate_(
drm_ca_root_prod_cert,
drm_ca_root_prod_cert + drm_ca_root_prod_cert_len),
oem_root_dev_certificate_(
oem_ca_root_dev_cert_der,
oem_ca_root_dev_cert_der + oem_ca_root_dev_cert_der_len),
oem_root_prod_certificate_(
oem_ca_root_prod_cert_der,
oem_ca_root_prod_cert_der + oem_ca_root_prod_cert_der_len) {}
RootCertificates::~RootCertificates() {}
} // namespace widevine

View File

@@ -1,56 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// 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_INTERNAL_CERTIFICATES_ROOT_CERTIFICATES_H_
#define PROVISIONING_SDK_INTERNAL_CERTIFICATES_ROOT_CERTIFICATES_H_
#include <string>
namespace widevine {
// This class contains DRM and OEM root certificates.
class RootCertificates {
public:
RootCertificates();
~RootCertificates();
const std::string& drm_root_test_certificate() const {
return drm_root_test_certificate_;
}
const std::string& drm_root_dev_certificate() const {
return drm_root_dev_certificate_;
}
const std::string& drm_root_prod_certificate() const {
return drm_root_prod_certificate_;
}
const std::string& oem_root_dev_certificate() const {
return oem_root_dev_certificate_;
}
const std::string& oem_root_prod_certificate() const {
return oem_root_prod_certificate_;
}
private:
RootCertificates(const RootCertificates&) = delete;
RootCertificates& operator=(const RootCertificates&) = delete;
std::string drm_root_test_certificate_;
std::string drm_root_dev_certificate_;
std::string drm_root_prod_certificate_;
std::string oem_root_dev_certificate_;
std::string oem_root_prod_certificate_;
};
} // namespace widevine
#endif // PROVISIONING_SDK_INTERNAL_CERTIFICATES_ROOT_CERTIFICATES_H_

View File

@@ -0,0 +1,26 @@
////////////////////////////////////////////////////////////////////////////////
// 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 "provisioning_sdk/internal/certificates/root_oem_certificates.h"
#include "provisioning_sdk/internal/certificates/oem_ca_root_dev_cert.h"
#include "provisioning_sdk/internal/certificates/oem_ca_root_prod_cert.h"
namespace widevine {
RootOemCertificates::RootOemCertificates()
: oem_root_dev_certificate_(
oem_ca_root_dev_cert_der,
oem_ca_root_dev_cert_der + oem_ca_root_dev_cert_der_len),
oem_root_prod_certificate_(
oem_ca_root_prod_cert_der,
oem_ca_root_prod_cert_der + oem_ca_root_prod_cert_der_len) {}
RootOemCertificates::~RootOemCertificates() {}
} // namespace widevine

View File

@@ -0,0 +1,40 @@
////////////////////////////////////////////////////////////////////////////////
// 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_INTERNAL_CERTIFICATES_ROOT_OEM_CERTIFICATES_H_
#define PROVISIONING_SDK_INTERNAL_CERTIFICATES_ROOT_OEM_CERTIFICATES_H_
#include <string>
namespace widevine {
// This class contains development and production OEM root certificates.
class RootOemCertificates {
public:
RootOemCertificates();
~RootOemCertificates();
const std::string& oem_root_dev_certificate() const {
return oem_root_dev_certificate_;
}
const std::string& oem_root_prod_certificate() const {
return oem_root_prod_certificate_;
}
private:
RootOemCertificates(const RootOemCertificates&) = delete;
RootOemCertificates& operator=(const RootOemCertificates&) = delete;
std::string oem_root_dev_certificate_;
std::string oem_root_prod_certificate_;
};
} // namespace widevine
#endif // PROVISIONING_SDK_INTERNAL_CERTIFICATES_ROOT_OEM_CERTIFICATES_H_

View File

@@ -1,12 +1,12 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
// 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 "provisioning_sdk/internal/certificates/test_certificates.h"
#include "provisioning_sdk/internal/certificates/test_oem_certificates.h"
#include "provisioning_sdk/internal/certificates/backwards_chain.h"
#include "provisioning_sdk/internal/certificates/expired_2000_chain.h"
@@ -17,7 +17,7 @@
namespace widevine {
TestCertificates::TestCertificates()
TestOemCertificates::TestOemCertificates()
: single_certificate_chain_der_(
single_cert_chain_der,
single_cert_chain_der + single_cert_chain_der_len),
@@ -35,6 +35,6 @@ TestCertificates::TestCertificates()
invalid_certificate_chain_der_(
invalid_chain_der, invalid_chain_der + invalid_chain_der_len) {}
TestCertificates::~TestCertificates() {}
TestOemCertificates::~TestOemCertificates() {}
} // namespace widevine

View File

@@ -1,24 +1,24 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
// 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_INTERNAL_CERTIFICATES_TEST_CERTIFICATES_H_
#define PROVISIONING_SDK_INTERNAL_CERTIFICATES_TEST_CERTIFICATES_H_
#ifndef PROVISIONING_SDK_INTERNAL_CERTIFICATES_TEST_OEM_CERTIFICATES_H_
#define PROVISIONING_SDK_INTERNAL_CERTIFICATES_TEST_OEM_CERTIFICATES_H_
#include <string>
namespace widevine {
// This class contains DER-encoded test certificates. The keys for these
// This class contains DER-encoded test OEM certificates. The keys for these
// certificates came from common/rsa_test_keys.h.
class TestCertificates {
class TestOemCertificates {
public:
TestCertificates();
~TestCertificates();
TestOemCertificates();
~TestOemCertificates();
const std::string& single_certificate_chain_der() const {
return single_certificate_chain_der_;
@@ -45,8 +45,8 @@ class TestCertificates {
}
private:
TestCertificates(const TestCertificates&) = delete;
TestCertificates& operator=(const TestCertificates&) = delete;
TestOemCertificates(const TestOemCertificates&) = delete;
TestOemCertificates& operator=(const TestOemCertificates&) = delete;
std::string single_certificate_chain_der_;
// leaf + intermediate certificates.
@@ -60,4 +60,4 @@ class TestCertificates {
} // namespace widevine
#endif // PROVISIONING_SDK_INTERNAL_CERTIFICATES_TEST_CERTIFICATES_H_
#endif // PROVISIONING_SDK_INTERNAL_CERTIFICATES_TEST_OEM_CERTIFICATES_H_

View File

@@ -1,5 +1,5 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
// 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
@@ -11,10 +11,12 @@
#include <string.h>
#include "glog/logging.h"
#include "absl/memory/memory.h"
#include "openssl/asn1.h"
#include "openssl/pkcs7.h"
#include "openssl/x509.h"
#include "openssl/x509v3.h"
#include "provisioning_sdk/internal/certificates/root_certificates.h"
#include "provisioning_sdk/internal/certificates/root_oem_certificates.h"
namespace widevine {
namespace {
@@ -29,7 +31,7 @@ bool ExtractPublicKey(X509* x509, std::unique_ptr<RsaPublicKey>* public_key) {
LOG(WARNING) << "X509_get_pubkey failed.";
return false;
}
public_key->reset(new RsaPublicKey(EVP_PKEY_get1_RSA(pkey.get())));
*public_key = absl::make_unique<RsaPublicKey>(EVP_PKEY_get1_RSA(pkey.get()));
return true;
}
@@ -105,12 +107,12 @@ OemDeviceCert::OemDeviceCert() {}
OemDeviceCert::~OemDeviceCert() {}
bool OemDeviceCert::Initialize(CertificateType certificate_type) {
RootCertificates root_certificates;
RootOemCertificates root_certificates;
switch (certificate_type) {
case kCertTesting:
case kCertDevelopment:
case kCertificateTypeTesting:
case kCertificateTypeDevelopment:
return Initialize(root_certificates.oem_root_dev_certificate());
case kCertProduction:
case kCertificateTypeProduction:
return Initialize(root_certificates.oem_root_prod_certificate());
default:
LOG(WARNING) << "Invalid certificate type " << certificate_type;

View File

@@ -1,5 +1,5 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
// 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
@@ -14,9 +14,9 @@
#include <memory>
#include <string>
#include "common/certificate_type.h"
#include "common/openssl_util.h"
#include "common/rsa_key.h"
#include "provisioning_sdk/public/certificate_type.h"
namespace widevine {

View File

@@ -1,5 +1,5 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
// 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
@@ -8,19 +8,20 @@
#include "provisioning_sdk/internal/oem_device_cert.h"
#include "gtest/gtest.h"
#include "provisioning_sdk/internal/certificates/test_certificates.h"
#include "testing/gunit.h"
#include "common/rsa_key.h"
#include "provisioning_sdk/internal/certificates/test_oem_certificates.h"
namespace widevine {
class OemDeviceCertTest : public ::testing::Test {
protected:
void SetUp() override {
ASSERT_TRUE(oem_device_cert_.Initialize(kCertTesting));
ASSERT_TRUE(oem_device_cert_.Initialize(kCertificateTypeTesting));
}
OemDeviceCert oem_device_cert_;
TestCertificates test_certificates_;
TestOemCertificates test_oem_certificates_;
};
TEST_F(OemDeviceCertTest, EmptyCertificateChain) {
@@ -45,7 +46,7 @@ TEST_F(OemDeviceCertTest, OnlyOneCertificateInCertificateChain) {
uint32_t system_id;
std::string oem_ca_serial_number;
EXPECT_FALSE(oem_device_cert_.VerifyCertificateChain(
test_certificates_.single_certificate_chain_der(), &leaf_public_key,
test_oem_certificates_.single_certificate_chain_der(), &leaf_public_key,
&system_id, &oem_ca_serial_number));
}
@@ -54,11 +55,11 @@ TEST_F(OemDeviceCertTest, ValidCertificateChain) {
uint32_t system_id;
std::string oem_ca_serial_number;
ASSERT_TRUE(oem_device_cert_.VerifyCertificateChain(
test_certificates_.valid_certificate_chain_der(), &leaf_public_key,
test_oem_certificates_.valid_certificate_chain_der(), &leaf_public_key,
&system_id, &oem_ca_serial_number));
std::unique_ptr<RsaPublicKey> public_key(RsaPublicKey::Create(
test_certificates_.valid_certificate_public_key_der()));
test_oem_certificates_.valid_certificate_public_key_der()));
ASSERT_TRUE(public_key);
EXPECT_TRUE(leaf_public_key->MatchesPublicKey(*public_key));
EXPECT_EQ(2001u, system_id);
@@ -70,7 +71,7 @@ TEST_F(OemDeviceCertTest, ExpiredCertificateChain) {
uint32_t system_id;
std::string oem_ca_serial_number;
ASSERT_FALSE(oem_device_cert_.VerifyCertificateChain(
test_certificates_.expired_certificate_chain_der(), &leaf_public_key,
test_oem_certificates_.expired_certificate_chain_der(), &leaf_public_key,
&system_id, &oem_ca_serial_number));
}
@@ -79,8 +80,8 @@ TEST_F(OemDeviceCertTest, OutOfOrderCertificateChain) {
uint32_t system_id;
std::string oem_ca_serial_number;
ASSERT_FALSE(oem_device_cert_.VerifyCertificateChain(
test_certificates_.backwards_certificate_chain_der(), &leaf_public_key,
&system_id, &oem_ca_serial_number));
test_oem_certificates_.backwards_certificate_chain_der(),
&leaf_public_key, &system_id, &oem_ca_serial_number));
}
TEST_F(OemDeviceCertTest, CertificateChainNotSignedByRoot) {
@@ -88,7 +89,7 @@ TEST_F(OemDeviceCertTest, CertificateChainNotSignedByRoot) {
uint32_t system_id;
std::string oem_ca_serial_number;
ASSERT_FALSE(oem_device_cert_.VerifyCertificateChain(
test_certificates_.invalid_certificate_chain_der(), &leaf_public_key,
test_oem_certificates_.invalid_certificate_chain_der(), &leaf_public_key,
&system_id, &oem_ca_serial_number));
}

View File

@@ -0,0 +1,235 @@
////////////////////////////////////////////////////////////////////////////////
// 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 "provisioning_sdk/internal/provisioning30_session_impl.h"
#include <stddef.h>
#include "glog/logging.h"
#include "common/aes_cbc_util.h"
#include "common/random_util.h"
#include "common/rsa_key.h"
#include "common/sha_util.h"
#include "provisioning_sdk/internal/provisioning_engine_impl.h"
#include "provisioning_sdk/public/provisioning_status.h"
#define LOG_EVERY_N_WITH_PROTO(message, proto) \
LOG_EVERY_N(WARNING, FLAGS_prov_sdk_log_every_n) \
<< (message) << " [proto: " << (proto).ShortDebugString() << "]"
namespace widevine {
Provisioning30SessionImpl::Provisioning30SessionImpl(
const ProvisioningEngineImpl& engine, const OemDeviceCert& oem_device_cert,
const RsaPrivateKey& service_private_key)
: ProvisioningSessionImpl(engine),
oem_device_cert_(oem_device_cert),
service_private_key_(service_private_key) {}
ProvisioningStatus Provisioning30SessionImpl::ProcessMessage(
const std::string& message, std::string* response, bool* done) {
SignedProvisioningMessage signed_request;
ProvisioningRequest request;
if (!ValidateAndDeserializeRequest(message, &signed_request, &request))
return INVALID_REQUEST_MESSAGE;
ClientIdentification client_id;
if (request.has_encrypted_client_id()) {
if (!DecryptClientIdentification(request.encrypted_client_id(), &client_id))
return INVALID_REQUEST_MESSAGE;
} else {
DCHECK(request.has_client_id());
client_id.Swap(request.mutable_client_id());
}
if (client_id.type() != ClientIdentification::OEM_DEVICE_CERTIFICATE) {
LOG_EVERY_N_WITH_PROTO("Invalid client_id type", client_id);
return INVALID_REQUEST_MESSAGE;
}
if (client_id.token().empty()) {
LOG_EVERY_N_WITH_PROTO("Missing client_id.token", client_id);
return INVALID_REQUEST_MESSAGE;
}
std::unique_ptr<RsaPublicKey> cert_public_key;
uint32_t system_id;
std::string oem_ca_serial_number;
if (!oem_device_cert_.VerifyCertificateChain(client_id.token(),
&cert_public_key, &system_id,
&oem_ca_serial_number)) {
LOG_EVERY_N_WITH_PROTO("Invalid token", client_id);
return INVALID_REQUEST_MESSAGE;
}
if (!cert_public_key->VerifySignature(signed_request.message(),
signed_request.signature())) {
LOG_EVERY_N_WITH_PROTO("Signature verification failed", client_id);
return INVALID_REQUEST_MESSAGE;
}
// Save device_info for query later.
device_info_ = engine_.GetDeviceInfo(system_id);
std::string certificate_serial_number;
if (request.has_spoid()) {
certificate_serial_number = request.spoid();
} else {
// Generate stable serial number.
const std::string stable_data(client_id.token() + request.stable_id() +
request.provider_id() +
engine_.secret_spoid_sauce());
const std::string hash = Sha256_Hash(stable_data);
const size_t RootCertificateSerialNumberSize = 16;
certificate_serial_number = hash.substr(0, RootCertificateSerialNumberSize);
}
ProvisioningResponse provisioning_response;
ProvisioningStatus status = GenerateProvisioningResponse(
system_id, oem_ca_serial_number, request.provider_id(),
certificate_serial_number, *cert_public_key, &provisioning_response);
if (status != OK) return status;
provisioning_response.set_nonce(request.nonce());
// Sign the response.
SignedProvisioningMessage signed_message;
if (!provisioning_response.SerializeToString(
signed_message.mutable_message())) {
LOG(WARNING) << "Error serializing ProvisioningResponse.";
return INTERNAL_ERROR;
}
if (!service_private_key_.GenerateSignature(
signed_message.message(), signed_message.mutable_signature())) {
LOG(WARNING) << "Failed to sign ProvisioningResponse.";
return INTERNAL_ERROR;
}
if (!signed_message.SerializeToString(response)) {
LOG(WARNING) << "Error serializing SignedProvisioningMessage.";
return INTERNAL_ERROR;
}
*done = true;
return OK;
}
bool Provisioning30SessionImpl::ValidateAndDeserializeRequest(
const std::string& message, SignedProvisioningMessage* signed_request,
ProvisioningRequest* request) const {
if (!signed_request->ParseFromString(message)) {
LOG_EVERY_N(WARNING, FLAGS_prov_sdk_log_every_n)
<< "Failed to parse SignedProvisioningMessage.";
return false;
}
VLOG(1) << "signed_request: " << signed_request->ShortDebugString();
if (signed_request->message().empty()) {
LOG_EVERY_N_WITH_PROTO("Missing message", *signed_request);
return false;
}
if (signed_request->signature().empty()) {
LOG_EVERY_N_WITH_PROTO("Missing signature", *signed_request);
return false;
}
if (!request->ParseFromString(signed_request->message())) {
LOG_EVERY_N_WITH_PROTO("Failed to parse ProvisioningRequest",
*signed_request);
return false;
}
if (request->has_encrypted_client_id()) {
const EncryptedClientIdentification& encrypted_client_id =
request->encrypted_client_id();
if (encrypted_client_id.encrypted_client_id().empty()) {
LOG_EVERY_N_WITH_PROTO("Missing encrypted_client_id",
encrypted_client_id);
return false;
}
if (encrypted_client_id.encrypted_client_id_iv().empty()) {
LOG_EVERY_N_WITH_PROTO("Missing encrypted_client_id_iv",
encrypted_client_id);
return false;
}
if (encrypted_client_id.encrypted_privacy_key().empty()) {
LOG_EVERY_N_WITH_PROTO("Missing encrypted_privacy_key",
encrypted_client_id);
return false;
}
} else if (!request->has_client_id()) {
LOG_EVERY_N_WITH_PROTO("Missing clear_or_encrypted_client_id", *request);
return false;
}
const size_t kMinimumRequiredNonceLength = 4;
if (request->nonce().size() < kMinimumRequiredNonceLength) {
LOG_EVERY_N_WITH_PROTO("Missing or invalid nonce", *request);
return false;
}
return true;
}
bool Provisioning30SessionImpl::DecryptClientIdentification(
const EncryptedClientIdentification& encrypted_client_id,
ClientIdentification* client_id) {
std::string privacy_key;
if (!service_private_key_.Decrypt(encrypted_client_id.encrypted_privacy_key(),
&privacy_key)) {
LOG_EVERY_N_WITH_PROTO("Failed to decrypt encrypted_privacy_key",
encrypted_client_id);
return false;
}
std::string serialized_client_id(crypto_util::DecryptAesCbc(
privacy_key, encrypted_client_id.encrypted_client_id_iv(),
encrypted_client_id.encrypted_client_id()));
if (serialized_client_id.empty()) {
LOG_EVERY_N_WITH_PROTO("Failed to decrypt client_id", encrypted_client_id);
return false;
}
if (!client_id->ParseFromString(serialized_client_id)) {
LOG_EVERY_N_WITH_PROTO("Failed to parse client_id", encrypted_client_id);
return false;
}
return true;
}
ProvisioningStatus Provisioning30SessionImpl::GenerateProvisioningResponse(
uint32_t system_id, const std::string& oem_ca_serial_number,
const std::string& provider_id, const std::string& certificate_serial_number,
const RsaPublicKey& cert_public_key, ProvisioningResponse* response) {
ProvisioningStatus status = engine_.GenerateProviderDeviceDrmCertificate(
system_id, oem_ca_serial_number, provider_id, device_drm_public_key_,
certificate_serial_number, response->mutable_device_certificate());
if (status != OK) return status;
const size_t kAesKeySize = 16;
const size_t kIvSize = 16;
// Encrypt private key.
std::string message_key;
if (!RandomBytes(kAesKeySize, &message_key)) {
LOG(WARNING) << "Failed to generate message_key.";
return INTERNAL_ERROR;
}
std::string iv;
if (!RandomBytes(kIvSize, &iv)) {
LOG(WARNING) << "Failed to generate iv.";
return INTERNAL_ERROR;
}
response->set_device_rsa_key_iv(iv);
response->set_device_rsa_key(
crypto_util::EncryptAesCbc(message_key, iv, device_drm_private_key_));
if (response->device_rsa_key().empty()) {
LOG(WARNING) << "Failed to encrypt device_rsa_key";
return INTERNAL_ERROR;
}
if (!cert_public_key.Encrypt(message_key, response->mutable_wrapping_key())) {
LOG(WARNING) << "Failed to encrypt wrapping_key";
return INTERNAL_ERROR;
}
return OK;
}
} // namespace widevine

View File

@@ -0,0 +1,78 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
// ProvisioningSession internal implementation.
#ifndef PROVISIONING_SDK_INTERNAL_PROVISIONING30_SESSION_IMPL_H_
#define PROVISIONING_SDK_INTERNAL_PROVISIONING30_SESSION_IMPL_H_
#include <stdint.h>
#include <memory>
#include <string>
#include <utility>
#include "common/rsa_key.h"
#include "provisioning_sdk/internal/oem_device_cert.h"
#include "provisioning_sdk/internal/provisioning_session_impl.h"
#include "provisioning_sdk/public/provisioning_status.h"
#include "protos/public/certificate_provisioning.pb.h"
#include "protos/public/client_identification.pb.h"
#include "protos/public/drm_certificate.pb.h"
#include "protos/public/provisioned_device_info.pb.h"
namespace widevine {
class ProvisioningEngineImpl;
class Provisioning30SessionImpl : public ProvisioningSessionImpl {
public:
Provisioning30SessionImpl(const ProvisioningEngineImpl& engine,
const OemDeviceCert& oem_device_cert,
const RsaPrivateKey& service_private_key);
// 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.
ProvisioningStatus ProcessMessage(const std::string& message,
std::string* response,
bool* done) override;
// * Returns a ProvisioneddeviceInfo message containing information about the
// type of device being provisioned. May return nullptr.
const ProvisionedDeviceInfo* GetDeviceInfo() const override {
return device_info_.get();
}
private:
Provisioning30SessionImpl(const Provisioning30SessionImpl&) = delete;
Provisioning30SessionImpl& operator=(const Provisioning30SessionImpl&) =
delete;
bool ValidateAndDeserializeRequest(const std::string& message,
SignedProvisioningMessage* signed_request,
ProvisioningRequest* request) const;
bool DecryptClientIdentification(
const EncryptedClientIdentification& encrypted_client_id,
ClientIdentification* client_id);
ProvisioningStatus GenerateProvisioningResponse(
uint32_t system_id, const std::string& oem_ca_serial_number,
const std::string& provider_id, const std::string& certificate_serial_number,
const RsaPublicKey& cert_public_key, ProvisioningResponse* response);
const OemDeviceCert& oem_device_cert_;
const RsaPrivateKey& service_private_key_;
std::shared_ptr<ProvisionedDeviceInfo> device_info_;
};
} // namespace widevine
#endif // PROVISIONING_SDK_INTERNAL_PROVISIONING30_SESSION_IMPL_H_

View File

@@ -0,0 +1,406 @@
////////////////////////////////////////////////////////////////////////////////
// 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 "provisioning_sdk/internal/provisioning30_session_impl.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "common/aes_cbc_util.h"
#include "common/mock_rsa_key.h"
#include "common/sha_util.h"
#include "provisioning_sdk/internal/oem_device_cert.h"
#include "provisioning_sdk/internal/provisioning_engine_impl.h"
using ::testing::_;
using ::testing::ByMove;
using ::testing::DoAll;
using ::testing::IsEmpty;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SetArgPointee;
namespace {
const char kEncryptedClientIdIv[] = "sixteen_bytes_iv";
const char kPrivacyKey[] = "privacy_key_16B_";
const char kProviderId[] = "testing_provider";
const char kClientToken[] = "client_id_token";
const char kDevicePublicKey[] = "device_public_key";
const char kEncryptedPrivacyKey[] = "encrypted_privacy_key";
const char kDevicePrivateKey[] = "device_private_key";
const char kWrappingKey[] = "wrapping_key";
const char kDeviceCertificate[] = "device_certificate";
const char kNonce[] = "testing_nonce";
const char kSignature[] = "generated_signature";
// Derives Stable Per-Origin IDentifiers.
std::string DeriveSpoid(const std::string& client_token, const std::string& provider_id,
const std::string& secret_sauce) {
return widevine::Sha256_Hash(client_token + provider_id + secret_sauce)
.substr(0, 16);
}
} // namespace
namespace widevine {
class MockProvisioningEngineImpl : public ProvisioningEngineImpl {
public:
MOCK_CONST_METHOD6(GenerateProviderDeviceDrmCertificate,
ProvisioningStatus(uint32_t system_id,
const std::string& oem_ca_serial_number,
const std::string& provider_id,
const std::string& public_key,
const std::string& certificate_serial_number,
std::string* certificate));
};
class MockOemDeviceCert : public OemDeviceCert {
public:
// gmock does not support SetArgPointee on std::unique_ptr, so we have to
// workaround it with a trick.
MOCK_CONST_METHOD4(DoVerifyCertificateChain,
bool(const std::string& certificate_chain,
RsaPublicKey** leaf_public_key, uint32_t* system_id,
std::string* oem_ca_serial_number));
bool VerifyCertificateChain(const std::string& certificate_chain,
std::unique_ptr<RsaPublicKey>* leaf_public_key,
uint32_t* system_id,
std::string* oem_ca_serial_number) const override {
RsaPublicKey* raw_leaf_public_key = nullptr;
if (!DoVerifyCertificateChain(certificate_chain, &raw_leaf_public_key,
system_id, oem_ca_serial_number)) {
return false;
}
*leaf_public_key = std::unique_ptr<RsaPublicKey>(raw_leaf_public_key);
return true;
}
};
class Provisioning30SessionImplTest : public ::testing::Test {
protected:
Provisioning30SessionImplTest()
: session_impl_(mock_engine_impl_, mock_oem_device_cert_,
mock_service_private_key_) {
mock_rsa_key_factory_ = new MockRsaKeyFactory;
session_impl_.set_rsa_key_factory(
std::unique_ptr<RsaKeyFactory>(mock_rsa_key_factory_));
}
Provisioning30SessionImpl session_impl_;
MockRsaKeyFactory* mock_rsa_key_factory_ = nullptr;
MockProvisioningEngineImpl mock_engine_impl_;
MockOemDeviceCert mock_oem_device_cert_;
MockRsaPrivateKey mock_service_private_key_;
};
class Provisioning30SessionImplProcessTest
: public Provisioning30SessionImplTest {
public:
void SetUp() override {
MockRsaPublicKey* mock_rsa_public_key = new MockRsaPublicKey;
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey(kDevicePublicKey))
.WillOnce(
Return(ByMove(std::unique_ptr<RsaPublicKey>(mock_rsa_public_key))));
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs8PrivateKey(kDevicePrivateKey, IsEmpty()))
.WillOnce(Return(
ByMove(std::unique_ptr<RsaPrivateKey>(new MockRsaPrivateKey))));
EXPECT_CALL(*mock_rsa_public_key, MatchesPrivateKey(_))
.WillOnce(Return(true));
ASSERT_EQ(OK,
session_impl_.Initialize(kDevicePublicKey, kDevicePrivateKey));
// Setup Provisioning Message.
client_id_.set_type(ClientIdentification::OEM_DEVICE_CERTIFICATE);
client_id_.set_token(kClientToken);
EncryptedClientIdentification* encrypted_client_id =
prov_request_.mutable_encrypted_client_id();
encrypted_client_id->set_encrypted_client_id(crypto_util::EncryptAesCbc(
kPrivacyKey, kEncryptedClientIdIv, client_id_.SerializeAsString()));
encrypted_client_id->set_encrypted_client_id_iv(kEncryptedClientIdIv);
encrypted_client_id->set_encrypted_privacy_key(kEncryptedPrivacyKey);
prov_request_.set_provider_id(kProviderId);
prov_request_.set_nonce(kNonce);
signed_prov_message_.set_message(prov_request_.SerializeAsString());
signed_prov_message_.set_signature("testing_signature");
}
ClientIdentification client_id_;
ProvisioningRequest prov_request_;
SignedProvisioningMessage signed_prov_message_;
};
TEST_F(Provisioning30SessionImplProcessTest, InvalidMessage) {
std::string response;
bool done;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage("invalid_message", &response, &done));
}
TEST_F(Provisioning30SessionImplProcessTest, EmptyMessage) {
std::string response;
bool done;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage("", &response, &done));
}
TEST_F(Provisioning30SessionImplProcessTest, MissingMessage) {
signed_prov_message_.clear_message();
std::string response;
bool done;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response, &done));
}
TEST_F(Provisioning30SessionImplProcessTest, MissingSignature) {
signed_prov_message_.clear_signature();
std::string response;
bool done;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response, &done));
}
TEST_F(Provisioning30SessionImplProcessTest, MissingClientId) {
prov_request_.clear_encrypted_client_id();
signed_prov_message_.set_message(prov_request_.SerializeAsString());
std::string response;
bool done;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response, &done));
}
TEST_F(Provisioning30SessionImplProcessTest, MissingEncryptedClientId) {
prov_request_.mutable_encrypted_client_id()->clear_encrypted_client_id();
signed_prov_message_.set_message(prov_request_.SerializeAsString());
std::string response;
bool done;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response, &done));
}
TEST_F(Provisioning30SessionImplProcessTest, MissingEncryptedClientIdIv) {
prov_request_.mutable_encrypted_client_id()->clear_encrypted_client_id_iv();
signed_prov_message_.set_message(prov_request_.SerializeAsString());
std::string response;
bool done;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response, &done));
}
TEST_F(Provisioning30SessionImplProcessTest, MissingEncryptedPrivacyKey) {
prov_request_.mutable_encrypted_client_id()->clear_encrypted_privacy_key();
signed_prov_message_.set_message(prov_request_.SerializeAsString());
std::string response;
bool done;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response, &done));
}
TEST_F(Provisioning30SessionImplProcessTest, InvalidNonce) {
// Nonce should be at least 4 buytes.
const char kNonceWithLessThanFourBytes[] = "xx";
prov_request_.set_nonce(kNonceWithLessThanFourBytes);
signed_prov_message_.set_message(prov_request_.SerializeAsString());
std::string response;
bool done;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response, &done));
}
TEST_F(Provisioning30SessionImplProcessTest, PrivacyKeyDecryptionFailed) {
EXPECT_CALL(mock_service_private_key_, Decrypt(kEncryptedPrivacyKey, _))
.WillOnce(Return(false));
std::string response;
bool done;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response, &done));
}
TEST_F(Provisioning30SessionImplProcessTest, InvalidEncryptedClientId) {
prov_request_.mutable_encrypted_client_id()->set_encrypted_client_id(
"invalid_encrypted_client_id");
signed_prov_message_.set_message(prov_request_.SerializeAsString());
EXPECT_CALL(mock_service_private_key_, Decrypt(kEncryptedPrivacyKey, _))
.WillOnce(DoAll(SetArgPointee<1>(kPrivacyKey), Return(true)));
std::string response;
bool done;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response, &done));
}
TEST_F(Provisioning30SessionImplProcessTest, VerifyCertificateChainFailed) {
EXPECT_CALL(mock_service_private_key_, Decrypt(kEncryptedPrivacyKey, _))
.WillOnce(DoAll(SetArgPointee<1>(kPrivacyKey), Return(true)));
EXPECT_CALL(mock_oem_device_cert_,
DoVerifyCertificateChain(kClientToken, _, _, _))
.WillOnce(Return(false));
std::string response;
bool done;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response, &done));
}
TEST_F(Provisioning30SessionImplProcessTest,
ClearClientIdVerifyCertificateChainFailed) {
*prov_request_.mutable_client_id() = client_id_;
prov_request_.clear_encrypted_client_id();
signed_prov_message_.set_message(prov_request_.SerializeAsString());
EXPECT_CALL(mock_oem_device_cert_,
DoVerifyCertificateChain(kClientToken, _, _, _))
.WillOnce(Return(false));
std::string response;
bool done;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response, &done));
}
TEST_F(Provisioning30SessionImplProcessTest, ClearClientIdInvalidClientIdType) {
client_id_.set_type(ClientIdentification::KEYBOX);
*prov_request_.mutable_client_id() = client_id_;
prov_request_.clear_encrypted_client_id();
signed_prov_message_.set_message(prov_request_.SerializeAsString());
std::string response;
bool done;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response, &done));
}
TEST_F(Provisioning30SessionImplProcessTest, ClearClientIdMissingToken) {
client_id_.clear_token();
*prov_request_.mutable_client_id() = client_id_;
prov_request_.clear_encrypted_client_id();
signed_prov_message_.set_message(prov_request_.SerializeAsString());
std::string response;
bool done;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response, &done));
}
TEST_F(Provisioning30SessionImplProcessTest, VerifySignatureFailed) {
EXPECT_CALL(mock_service_private_key_, Decrypt(kEncryptedPrivacyKey, _))
.WillOnce(DoAll(SetArgPointee<1>(kPrivacyKey), Return(true)));
MockRsaPublicKey* mock_cert_public_key = new MockRsaPublicKey;
EXPECT_CALL(mock_oem_device_cert_,
DoVerifyCertificateChain(kClientToken, _, _, _))
.WillOnce(DoAll(SetArgPointee<1>(mock_cert_public_key), Return(true)));
EXPECT_CALL(*mock_cert_public_key,
VerifySignature(signed_prov_message_.message(),
signed_prov_message_.signature()))
.WillOnce(Return(false));
std::string response;
bool done;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response, &done));
}
TEST_F(Provisioning30SessionImplProcessTest, GenerateDeviceCertificateFailed) {
const uint32_t kSystemId = 1234;
const char kExpectedOemSerialNumber[] = "test_oem_serial_number";
EXPECT_CALL(mock_service_private_key_, Decrypt(kEncryptedPrivacyKey, _))
.WillOnce(DoAll(SetArgPointee<1>(kPrivacyKey), Return(true)));
MockRsaPublicKey* mock_cert_public_key = new MockRsaPublicKey;
EXPECT_CALL(mock_oem_device_cert_,
DoVerifyCertificateChain(kClientToken, _, _, _))
.WillOnce(DoAll(
SetArgPointee<1>(mock_cert_public_key), SetArgPointee<2>(kSystemId),
SetArgPointee<3>(kExpectedOemSerialNumber), Return(true)));
EXPECT_CALL(*mock_cert_public_key,
VerifySignature(signed_prov_message_.message(),
signed_prov_message_.signature()))
.WillOnce(Return(true));
EXPECT_CALL(
mock_engine_impl_,
GenerateProviderDeviceDrmCertificate(
kSystemId, kExpectedOemSerialNumber, kProviderId, kDevicePublicKey,
DeriveSpoid(kClientToken, kProviderId, ""), _))
.WillOnce(Return(INTERNAL_ERROR));
std::string response;
bool done;
EXPECT_EQ(INTERNAL_ERROR,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response, &done));
}
TEST_F(Provisioning30SessionImplProcessTest, Success) {
const uint32_t kSystemId = 1234;
EXPECT_CALL(mock_service_private_key_, Decrypt(kEncryptedPrivacyKey, _))
.WillOnce(DoAll(SetArgPointee<1>(kPrivacyKey), Return(true)));
MockRsaPublicKey* mock_cert_public_key = new MockRsaPublicKey;
EXPECT_CALL(mock_oem_device_cert_,
DoVerifyCertificateChain(kClientToken, _, _, _))
.WillOnce(DoAll(SetArgPointee<1>(mock_cert_public_key),
SetArgPointee<2>(kSystemId), Return(true)));
EXPECT_CALL(*mock_cert_public_key,
VerifySignature(signed_prov_message_.message(),
signed_prov_message_.signature()))
.WillOnce(Return(true));
EXPECT_CALL(mock_engine_impl_, GenerateProviderDeviceDrmCertificate(
kSystemId, _, _, kDevicePublicKey, _, _))
.WillOnce(DoAll(SetArgPointee<5>(kDeviceCertificate), Return(OK)));
std::string message_key;
EXPECT_CALL(*mock_cert_public_key, Encrypt(_, _))
.WillOnce(DoAll(SaveArg<0>(&message_key), SetArgPointee<1>(kWrappingKey),
Return(true)));
std::string message;
EXPECT_CALL(mock_service_private_key_, GenerateSignature(_, _))
.WillOnce(DoAll(SaveArg<0>(&message), SetArgPointee<1>(kSignature),
Return(true)));
std::string response;
bool done;
ASSERT_EQ(OK, session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response, &done));
// Verify the response.
EXPECT_TRUE(done);
SignedProvisioningMessage signed_prov_message;
ASSERT_TRUE(signed_prov_message.ParseFromString(response));
EXPECT_EQ(message, signed_prov_message.message());
EXPECT_EQ(kSignature, signed_prov_message.signature());
ProvisioningResponse prov_response;
ASSERT_TRUE(prov_response.ParseFromString(message));
EXPECT_EQ(
kDevicePrivateKey,
crypto_util::DecryptAesCbc(message_key, prov_response.device_rsa_key_iv(),
prov_response.device_rsa_key()));
EXPECT_EQ(kDeviceCertificate, prov_response.device_certificate());
EXPECT_EQ(kNonce, prov_response.nonce());
EXPECT_EQ(kWrappingKey, prov_response.wrapping_key());
}
} // namespace widevine

View File

@@ -1,5 +1,5 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
// 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
@@ -10,16 +10,21 @@
#include <stddef.h>
#include <time.h>
#include <cstdint>
#include <limits>
#include <memory>
#include <string>
#include <utility>
#include "glog/logging.h"
#include "absl/synchronization/mutex.h"
#include "common/aes_cbc_util.h"
#include "common/certificate_type.h"
#include "common/crypto_util.h"
#include "common/drm_root_certificate.h"
#include "common/drm_service_certificate.h"
#include "common/random_util.h"
#include "common/rsa_key.h"
#include "provisioning_sdk/internal/certificates/root_certificates.h"
#include "provisioning_sdk/internal/certificates/root_oem_certificates.h"
#include "provisioning_sdk/public/provisioning_status.h"
#define LOG_WITH_PROTO(message, proto) \
@@ -28,68 +33,24 @@
namespace widevine {
namespace {
// Verify that |certificate| is signed by |public_key|. If |public_key| is null,
// |certificate| should be self signed.
bool VerifyAndExtractCertificate(const RsaPublicKey* public_key,
const std::string& certificate,
SignedDrmDeviceCertificate* signed_drm_cert,
DrmDeviceCertificate* drm_cert) {
DCHECK(signed_drm_cert);
DCHECK(drm_cert);
if (!signed_drm_cert->ParseFromString(certificate)) {
LOG(WARNING) << "Failed to parse SignedDrmDeviceCertificate.";
return false;
}
if (signed_drm_cert->drm_certificate().empty()) {
LOG_WITH_PROTO("Missing drm_certificate", *signed_drm_cert);
return false;
}
if (signed_drm_cert->signature().empty()) {
LOG_WITH_PROTO("Missing signature", *signed_drm_cert);
return false;
}
const size_t kContextEncryptionKeySize(32);
const size_t kContextEncryptionIvSize(16);
const size_t kContextMacKeySize(32);
if (!drm_cert->ParseFromString(signed_drm_cert->drm_certificate())) {
LOG_WITH_PROTO("Failed to parse DrmDeviceCertificate", *signed_drm_cert);
return false;
}
if (drm_cert->public_key().empty()) {
LOG_WITH_PROTO("Missing public_key", *drm_cert);
return false;
}
std::unique_ptr<RsaPublicKey> local_public_key;
if (!public_key) {
local_public_key.reset(RsaPublicKey::Create(drm_cert->public_key()));
if (!local_public_key) {
LOG_WITH_PROTO("Invalid root public key", *drm_cert);
return false;
}
public_key = local_public_key.get();
}
if (!public_key->VerifySignature(signed_drm_cert->drm_certificate(),
signed_drm_cert->signature())) {
LOG_WITH_PROTO("Signature verification failed", *signed_drm_cert);
return false;
}
return true;
}
bool GenerateCertificate(DrmDeviceCertificate::CertificateType type,
uint32_t system_id, const std::string& provider_id,
const std::string& serial_number, const std::string& public_key,
bool GenerateCertificate(DrmCertificate::Type type, uint32_t system_id,
const std::string& provider_id, const std::string& serial_number,
const std::string& public_key,
const RsaPrivateKey& signing_key,
const SignedDrmDeviceCertificate& signer,
const SignedDrmCertificate& signer,
std::string* certificate) {
DCHECK(type == DrmDeviceCertificate::DRM_INTERMEDIATE ||
type == DrmDeviceCertificate::DRM_USER_DEVICE);
DCHECK(type == DrmCertificate::DEVICE_MODEL ||
type == DrmCertificate::DEVICE);
if (serial_number.empty()) {
LOG(WARNING) << "Require an non-empty serial number.";
return false;
}
DrmDeviceCertificate drm_cert;
DrmCertificate drm_cert;
drm_cert.set_type(type);
drm_cert.set_system_id(system_id);
if (!provider_id.empty()) drm_cert.set_provider_id(provider_id);
@@ -97,20 +58,19 @@ bool GenerateCertificate(DrmDeviceCertificate::CertificateType type,
drm_cert.set_creation_time_seconds(time(nullptr));
drm_cert.set_public_key(public_key);
SignedDrmDeviceCertificate signed_cert;
if (!drm_cert.SerializeToString(
signed_cert.mutable_drm_certificate())) {
LOG(WARNING) << "Error serializing DrmDeviceCertificate.";
SignedDrmCertificate signed_cert;
if (!drm_cert.SerializeToString(signed_cert.mutable_drm_certificate())) {
LOG(WARNING) << "Error serializing DrmCertificate.";
return false;
}
if (!signing_key.GenerateSignature(signed_cert.drm_certificate(),
signed_cert.mutable_signature())) {
LOG(WARNING) << "Failed to generate signature for DrmDeviceCertificate.";
LOG(WARNING) << "Failed to generate signature for DrmCertificate.";
return false;
}
*signed_cert.mutable_signer() = signer;
if (!signed_cert.SerializeToString(certificate)) {
LOG(WARNING) << "Failed to serialize SignedDrmDeviceCertificate to string.";
LOG(WARNING) << "Failed to serialize SignedDrmCertificate to string.";
return false;
}
return true;
@@ -135,8 +95,12 @@ bool IsSerialNumberEq(const std::string& a, const std::string& b) {
} // namespace
// NOTE: certificate_expiration_seconds_utc_ not initialized in initialization
// list due to bug in clang and/or CLIF which causes the initialization to be
// skipped.
ProvisioningEngineImpl::ProvisioningEngineImpl()
: rsa_key_factory_(new RsaKeyFactory) {}
: rsa_key_factory_(new RsaKeyFactory),
certificate_expiration_seconds_utc_(0) {}
ProvisioningEngineImpl::~ProvisioningEngineImpl() {}
@@ -148,38 +112,41 @@ ProvisioningStatus ProvisioningEngineImpl::Initialize(
const std::string& provisioning_private_key,
const std::string& provisioning_private_key_passphrase,
const std::string& secret_spoid_sauce) {
if (!LoadDrmRootPublicKey(certificate_type)) return INVALID_CERTIFICATE_TYPE;
Status status;
SignedDrmDeviceCertificate signed_drm_cert;
DrmDeviceCertificate drm_cert;
if (!VerifyAndExtractCertificate(root_public_key_.get(),
drm_service_certificate, &signed_drm_cert,
&drm_cert)) {
return INVALID_SERVICE_DRM_CERTIFICATE;
if (!drm_root_certificate_) {
status = DrmRootCertificate::CreateByType(certificate_type,
&drm_root_certificate_);
if (!status.ok()) {
LOG(ERROR) << status;
return INVALID_CERTIFICATE_TYPE;
}
}
if (drm_cert.type() != DrmDeviceCertificate::SERVICE) {
LOG(WARNING) << "Expecting SERVICE certificate.";
return INVALID_SERVICE_DRM_CERTIFICATE;
}
service_public_key_ =
rsa_key_factory_->CreateFromPkcs1PublicKey(drm_cert.public_key());
if (!service_public_key_) return INVALID_SERVICE_DRM_CERTIFICATE;
service_private_key_ = rsa_key_factory_->CreateFromPkcs8PrivateKey(
service_private_key, service_private_key_passphrase);
if (!service_private_key_) return INVALID_SERVICE_PRIVATE_KEY;
if (!service_public_key_->MatchesPrivateKey(*service_private_key_)) {
LOG(WARNING) << "Services public key and private key do not match.";
return INVALID_SERVICE_PRIVATE_KEY;
drm_root_public_key_ = rsa_key_factory_->CreateFromPkcs1PublicKey(
drm_root_certificate_->public_key());
if (!drm_root_public_key_) {
LOG(ERROR) << "Failed to instiate DRM root public key.";
return INTERNAL_ERROR;
}
if (!VerifyAndExtractCertificate(root_public_key_.get(),
provisioning_drm_certificate,
&signed_provisioning_cert_, &drm_cert)) {
status = DrmServiceCertificate::AddDrmServiceCertificate(
drm_root_certificate_.get(), drm_service_certificate, service_private_key,
service_private_key_passphrase);
if (!status.ok()) {
LOG(ERROR) << status;
return INVALID_SERVICE_DRM_CERTIFICATE;
}
DrmCertificate drm_cert;
status = drm_root_certificate_->VerifyCertificate(
provisioning_drm_certificate, &signed_provisioning_cert_, &drm_cert);
if (!status.ok()) {
LOG(ERROR) << status;
return INVALID_PROVISIONER_DRM_CERTIFICATE;
}
if (drm_cert.type() != DrmDeviceCertificate::ROOT &&
drm_cert.type() != DrmDeviceCertificate::PROVISIONER) {
LOG(WARNING) << "Expecting ROOT or PROVISIONER certificate.";
if (drm_cert.type() != DrmCertificate::ROOT &&
drm_cert.type() != DrmCertificate::PROVISIONER) {
LOG(ERROR) << "Expecting ROOT or PROVISIONER certificate.";
return INVALID_PROVISIONER_DRM_CERTIFICATE;
}
@@ -191,12 +158,12 @@ ProvisioningStatus ProvisioningEngineImpl::Initialize(
if (!provisioning_private_key_) return INVALID_PROVISIONER_PRIVATE_KEY;
if (!provisioning_public_key_->MatchesPrivateKey(
*provisioning_private_key_)) {
LOG(WARNING) << "Provisioning public key and private key do not match.";
LOG(ERROR) << "Provisioning public key and private key do not match.";
return INVALID_PROVISIONER_PRIVATE_KEY;
}
if (secret_spoid_sauce.empty()) {
LOG(WARNING) << "SPOID secret sauce is empty!";
LOG(ERROR) << "SPOID secret sauce is empty!";
return INVALID_SPOID_SAUCE;
}
secret_spoid_sauce_ = secret_spoid_sauce;
@@ -212,12 +179,13 @@ ProvisioningStatus ProvisioningEngineImpl::SetCertificateStatusList(
return INVALID_STATUS_LIST;
}
SignedCertificateStatusList signed_cert_status_list;
SignedDeviceCertificateStatusList signed_cert_status_list;
if (!signed_cert_status_list.ParseFromString(certificate_status_list)) {
LOG(WARNING) << "Error parsing SignedCertificateStatusList.";
LOG(WARNING) << "Error parsing SignedDeviceCertificateStatusList.";
return INVALID_STATUS_LIST;
}
if (!root_public_key_->VerifySignature(
if (!drm_root_public_key_->VerifySignature(
signed_cert_status_list.certificate_status_list(),
signed_cert_status_list.signature())) {
LOG_WITH_PROTO("Signature verification failed", signed_cert_status_list);
@@ -232,7 +200,7 @@ ProvisioningStatus ProvisioningEngineImpl::SetCertificateStatusList(
return INVALID_STATUS_LIST;
}
WriterMutexLock writer_lock(&mutex_);
absl::WriterMutexLock writer_lock(&cert_status_mutex_);
if (expiration_period_seconds == 0) {
certificate_expiration_seconds_utc_ = std::numeric_limits<uint32_t>::max();
@@ -273,14 +241,14 @@ ProvisioningStatus ProvisioningEngineImpl::GenerateDrmIntermediateCertificate(
rsa_key_factory_->CreateFromPkcs1PublicKey(public_key);
if (!intermediate_public_key) return INVALID_INTERMEDIATE_PUBLIC_KEY;
const size_t kCertificateSerialNumberSize = 16;
const size_t RootCertificateSerialNumberSize = 16;
std::string serial_number;
if (!RandomBytes(kCertificateSerialNumberSize, &serial_number)) {
if (!RandomBytes(RootCertificateSerialNumberSize, &serial_number)) {
LOG(WARNING) << "Failed to generate serial_number.";
return INTERNAL_ERROR;
}
if (!GenerateCertificate(DrmDeviceCertificate::DRM_INTERMEDIATE,
system_id, std::string(), serial_number, public_key,
if (!GenerateCertificate(DrmCertificate::DEVICE_MODEL, system_id, std::string(),
serial_number, public_key,
*provisioning_private_key_,
signed_provisioning_cert_, certificate)) {
return INTERNAL_ERROR;
@@ -291,15 +259,16 @@ ProvisioningStatus ProvisioningEngineImpl::GenerateDrmIntermediateCertificate(
ProvisioningStatus ProvisioningEngineImpl::AddDrmIntermediateCertificate(
const std::string& intermediate_cert, const std::string& cert_private_key,
const std::string& cert_private_key_passphrase) {
SignedDrmDeviceCertificate intermediate_signed_cert;
DrmDeviceCertificate intermediate_drm_cert;
if (!VerifyAndExtractCertificate(provisioning_public_key_.get(),
intermediate_cert, &intermediate_signed_cert,
&intermediate_drm_cert)) {
SignedDrmCertificate intermediate_signed_cert;
DrmCertificate intermediate_drm_cert;
Status status = drm_root_certificate_->VerifyCertificate(
intermediate_cert, &intermediate_signed_cert, &intermediate_drm_cert);
if (!status.ok()) {
LOG(ERROR) << status;
return INVALID_INTERMEDIATE_DRM_CERTIFICATE;
}
if (intermediate_drm_cert.type() !=
DrmDeviceCertificate::DRM_INTERMEDIATE) {
if (intermediate_drm_cert.type() != DrmCertificate::DEVICE_MODEL) {
LOG_WITH_PROTO("Invalid device certificate type", intermediate_drm_cert);
return INVALID_INTERMEDIATE_DRM_CERTIFICATE;
}
@@ -309,9 +278,9 @@ ProvisioningStatus ProvisioningEngineImpl::AddDrmIntermediateCertificate(
}
const std::string empty_oem_ca_serial_number;
ProvisioningStatus status = CheckDeviceStatus(
ProvisioningStatus provisioning_status = CheckDeviceStatus(
intermediate_drm_cert.system_id(), empty_oem_ca_serial_number);
if (status != OK) return status;
if (provisioning_status != OK) return provisioning_status;
auto intermediate_public_key = rsa_key_factory_->CreateFromPkcs1PublicKey(
intermediate_drm_cert.public_key());
@@ -325,7 +294,7 @@ ProvisioningStatus ProvisioningEngineImpl::AddDrmIntermediateCertificate(
return INVALID_INTERMEDIATE_PRIVATE_KEY;
}
WriterMutexLock writer_lock(&mutex_);
absl::WriterMutexLock writer_lock(&cert_status_mutex_);
auto& certificate_info =
intermediate_certs_info_[intermediate_drm_cert.system_id()];
certificate_info.signed_drm_certificate.Swap(&intermediate_signed_cert);
@@ -359,25 +328,25 @@ ProvisioningStatus ProvisioningEngineImpl::GenerateProviderDeviceDrmCertificate(
if (status != OK) return status;
std::shared_ptr<RsaPrivateKey> intermediate_private_key;
const SignedDrmDeviceCertificate* intermediate_cert = nullptr;
const SignedDrmCertificate* intermediate_cert = nullptr;
{
ReaderMutexLock reader_lock(&mutex_);
absl::ReaderMutexLock reader_lock(&cert_status_mutex_);
auto info_it = intermediate_certs_info_.find(system_id);
if (info_it == intermediate_certs_info_.end() ||
!info_it->second.private_key) {
LOG(WARNING) << "Cannot find the intermediate certificate for system: "
<< system_id;
return MISSING_DRM_INTERMEDIATE_CERT;
return MISSING_DEVICE_MODEL_CERT;
}
intermediate_private_key = info_it->second.private_key;
intermediate_cert = &info_it->second.signed_drm_certificate;
}
if (!GenerateCertificate(DrmDeviceCertificate::DRM_USER_DEVICE,
system_id, provider_id, certificate_serial_number,
public_key, *intermediate_private_key,
*intermediate_cert, certificate)) {
if (!GenerateCertificate(DrmCertificate::DEVICE, system_id, provider_id,
certificate_serial_number, public_key,
*intermediate_private_key, *intermediate_cert,
certificate)) {
return INTERNAL_ERROR;
}
return OK;
@@ -385,7 +354,7 @@ ProvisioningStatus ProvisioningEngineImpl::GenerateProviderDeviceDrmCertificate(
std::shared_ptr<ProvisionedDeviceInfo> ProvisioningEngineImpl::GetDeviceInfo(
uint32_t system_id) const {
ReaderMutexLock reader_lock(&mutex_);
absl::ReaderMutexLock reader_lock(&cert_status_mutex_);
auto info_it = intermediate_certs_info_.find(system_id);
if (info_it == intermediate_certs_info_.end()) {
LOG(WARNING) << "Cannot find the system id in device certificate list: "
@@ -395,45 +364,71 @@ std::shared_ptr<ProvisionedDeviceInfo> ProvisioningEngineImpl::GetDeviceInfo(
return info_it->second.device_info;
}
bool ProvisioningEngineImpl::LoadDrmRootPublicKey(
CertificateType certificate_type) {
const std::string* root_cert_string = nullptr;
RootCertificates root_certificates;
switch (certificate_type) {
case kCertTesting:
root_cert_string = &root_certificates.drm_root_test_certificate();
break;
case kCertDevelopment:
root_cert_string = &root_certificates.drm_root_dev_certificate();
break;
case kCertProduction:
root_cert_string = &root_certificates.drm_root_prod_certificate();
break;
default:
LOG(WARNING) << "Invalid certificate type " << certificate_type;
return false;
}
ProvisioningStatus ProvisioningEngineImpl::StoreContext(
const std::string& context_data, ProvisioningContext* context) const {
DCHECK(context);
SignedDrmDeviceCertificate signed_root_cert;
DrmDeviceCertificate root_cert;
if (!VerifyAndExtractCertificate(nullptr /* self signed */, *root_cert_string,
&signed_root_cert, &root_cert)) {
LOG(WARNING) << "Failed to extract root certificate.";
return false;
ProvisioningContextKeyData key_data;
if (!RandomBytes(kContextEncryptionKeySize,
key_data.mutable_encryption_key()) ||
!RandomBytes(kContextEncryptionIvSize,
key_data.mutable_encryption_iv()) ||
!RandomBytes(kContextMacKeySize, key_data.mutable_mac_key())) {
LOG(ERROR) << "Failed to generate random context key data.";
return INTERNAL_ERROR;
}
if (root_cert.type() != DrmDeviceCertificate::ROOT) {
LOG(WARNING) << "Expecting ROOT certificate.";
return false;
context->set_context_data(crypto_util::EncryptAesCbc(
key_data.encryption_key(), key_data.encryption_iv(), context_data));
context->set_mac(crypto_util::CreateSignatureHmacSha256(
key_data.mac_key(), context->context_data()));
if (!DrmServiceCertificate::GetDefaultDrmServiceCertificateOrDie()
->public_key()
->Encrypt(key_data.SerializeAsString(),
context->mutable_key_data())) {
LOG(WARNING) << "Context key data encryption failed";
return INTERNAL_ERROR;
}
root_public_key_ =
rsa_key_factory_->CreateFromPkcs1PublicKey(root_cert.public_key());
CHECK(root_public_key_);
return true;
return OK;
}
ProvisioningStatus ProvisioningEngineImpl::RetrieveContext(
const ProvisioningContext& context, std::string* context_data) const {
DCHECK(context_data);
std::string serialized_key_data;
if (!DrmServiceCertificate::GetDefaultDrmServiceCertificateOrDie()
->private_key()
->Decrypt(context.key_data(), &serialized_key_data)) {
LOG(WARNING) << "Could not decrypt context key data";
return INVALID_CONTEXT_KEY_DATA;
}
if (serialized_key_data.empty()) {
LOG(WARNING) << "Context key data is missing.";
return INVALID_CONTEXT_KEY_DATA;
}
ProvisioningContextKeyData key_data;
if (!key_data.ParseFromString(serialized_key_data)) {
LOG(WARNING) << "Invalid context key data.";
return INVALID_CONTEXT_KEY_DATA;
}
if (!crypto_util::VerifySignatureHmacSha256(key_data.mac_key(), context.mac(),
context.context_data())) {
LOG(WARNING) << "Provisioning context MAC verification failed.";
return INVALID_CONTEXT;
}
*context_data = crypto_util::DecryptAesCbc(key_data.encryption_key(),
key_data.encryption_iv(),
context.context_data());
if (context_data->empty()) {
LOG(WARNING) << "Provisioning context decryption failed.";
return INVALID_CONTEXT;
}
return OK;
}
ProvisioningStatus ProvisioningEngineImpl::CheckDeviceStatus(
uint32_t system_id, const std::string& oem_ca_serial_number) const {
ReaderMutexLock reader_lock(&mutex_);
absl::ReaderMutexLock reader_lock(&cert_status_mutex_);
if (certificate_expiration_seconds_utc_ < time(nullptr))
return STATUS_LIST_EXPIRED;
@@ -451,8 +446,8 @@ ProvisioningStatus ProvisioningEngineImpl::CheckDeviceStatus(
<< system_id;
return DEVICE_REVOKED;
}
if (certificate_status_it->second.status() !=
DeviceCertificateStatus::VALID) {
if (certificate_status_it->second.status() ==
DeviceCertificateStatus::STATUS_REVOKED) {
LOG(WARNING) << "Device revoked " << system_id;
return DEVICE_REVOKED;
}

View File

@@ -1,5 +1,5 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
// 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
@@ -17,19 +17,25 @@
#include <string>
#include <utility>
#include "base/mutex.h"
#include <cstdint>
#include "base/thread_annotations.h"
#include "absl/synchronization/mutex.h"
#include "common/certificate_type.h"
#include "common/drm_root_certificate.h"
#include "common/rsa_key.h"
#include "provisioning_sdk/internal/oem_device_cert.h"
#include "provisioning_sdk/public/certificate_type.h"
#include "provisioning_sdk/public/provisioning_status.h"
#include "protos/public/device_certificate.pb.h"
#include "protos/public/certificate_provisioning.pb.h"
#include "protos/public/device_certificate_status.pb.h"
#include "protos/public/drm_certificate.pb.h"
#include "protos/public/provisioned_device_info.pb.h"
#include "protos/public/signed_device_certificate.pb.h"
#include "protos/public/signed_drm_certificate.pb.h"
namespace widevine {
class DrmRootCertificate;
class ProvisioningSession;
class RsaPublicKey;
class ProvisioningEngineImpl {
public:
@@ -55,8 +61,7 @@ class ProvisioningEngineImpl {
// 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& drm_service_certificate,
CertificateType certificate_type, const std::string& drm_service_certificate,
const std::string& service_private_key,
const std::string& service_private_key_passphrase,
const std::string& provisioning_drm_certificate,
@@ -128,24 +133,31 @@ class ProvisioningEngineImpl {
const std::string& certificate_serial_number, std::string* certificate) const;
// Get the device info for the given |system_id|.
std::shared_ptr<ProvisionedDeviceInfo> GetDeviceInfo(uint32_t system_id) const;
virtual std::shared_ptr<ProvisionedDeviceInfo> GetDeviceInfo(
uint32_t system_id) const;
// Returns the service private key.
const RsaPrivateKey* service_private_key() const {
return service_private_key_.get();
// Encrypt, store, and sign context/state data.
virtual ProvisioningStatus StoreContext(const std::string& context_data,
ProvisioningContext* context) const;
// Verify, decrypt, and retrieve context/state data.
virtual ProvisioningStatus RetrieveContext(const ProvisioningContext& context,
std::string* context_data) const;
const DrmRootCertificate* drm_root_certificate() const {
return drm_root_certificate_.get();
}
const OemDeviceCert& oem_device_cert() const { return oem_device_cert_; }
const std::string& secret_spoid_sauce() const { return secret_spoid_sauce_; }
private:
friend class ProvisioningEngineImplTest;
friend class ProvisioningEngineImplProvTest;
friend class Sigma101ProvisioningSessionImplTest;
ProvisioningEngineImpl(const ProvisioningEngineImpl&) = delete;
ProvisioningEngineImpl& operator=(const ProvisioningEngineImpl&) = delete;
// Load DRM root public key with type |certificate_type|.
bool LoadDrmRootPublicKey(CertificateType certificate_type);
// Check device status.
// If |oem_ca_serial_number| is empty, we do not care whether serial number
// matches or not.
@@ -153,29 +165,36 @@ class ProvisioningEngineImpl {
ProvisioningStatus CheckDeviceStatus(
uint32_t system_id, const std::string& oem_ca_serial_number) const;
// Inject DRM root certificate for testing.
void set_drm_root_certificate(
std::unique_ptr<DrmRootCertificate> drm_root_certificate) {
drm_root_certificate_ = std::move(drm_root_certificate);
}
// Inject rsa_key_factory for testing.
void set_rsa_key_factory(std::unique_ptr<RsaKeyFactory> rsa_key_factory) {
rsa_key_factory_ = std::move(rsa_key_factory);
}
std::unique_ptr<RsaKeyFactory> rsa_key_factory_;
std::unique_ptr<RsaPublicKey> root_public_key_;
std::unique_ptr<RsaPublicKey> service_public_key_;
std::unique_ptr<RsaPrivateKey> service_private_key_;
SignedDrmDeviceCertificate signed_provisioning_cert_;
std::unique_ptr<DrmRootCertificate> drm_root_certificate_;
std::unique_ptr<RsaPublicKey> drm_root_public_key_;
SignedDrmCertificate signed_provisioning_cert_;
std::unique_ptr<RsaPublicKey> provisioning_public_key_;
std::unique_ptr<RsaPrivateKey> provisioning_private_key_;
std::string secret_spoid_sauce_;
std::string context_encryption_key_;
std::string context_mac_key_;
OemDeviceCert oem_device_cert_;
mutable Mutex mutex_;
mutable absl::Mutex cert_status_mutex_;
// POSIX time, in seconds, when the list would be expired.
uint32_t certificate_expiration_seconds_utc_ GUARDED_BY(mutex_) = 0;
uint32_t certificate_expiration_seconds_utc_ GUARDED_BY(cert_status_mutex_);
// Maps with system_id as the key.
std::map<uint32_t, DeviceCertificateStatus> certificate_status_map_
GUARDED_BY(mutex_);
GUARDED_BY(cert_status_mutex_);
struct IntermediateCertificateInfo {
SignedDrmDeviceCertificate signed_drm_certificate;
SignedDrmCertificate signed_drm_certificate;
std::shared_ptr<ProvisionedDeviceInfo> device_info;
std::shared_ptr<RsaPrivateKey> private_key;
};

View File

@@ -1,5 +1,5 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
// 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
@@ -12,14 +12,18 @@
#include <memory>
#include "glog/logging.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "common/certificate_type.h"
#include "common/mock_rsa_key.h"
#include "provisioning_sdk/public/certificate_type.h"
#include "common/rsa_test_keys.h"
#include "common/rsa_util.h"
#include "common/test_drm_certificates.h"
using ::testing::_;
using ::testing::ByMove;
using ::testing::DoAll;
using ::testing::Invoke;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SetArgPointee;
@@ -31,7 +35,8 @@ const int kExpirationPeriodSeconds = 3600;
const int kInfiniteExpirationPeriodSeconds = 0;
const char kEmptyOemSerialNumber[] = "";
const char kSecretSauce[] = "Twas bryllyg, and ye slythy toves";
const char kCertificateSerialNumber[] = "certificate_serial_number";
const char RootCertificateSerialNumber[] = "certificate_serial_number";
const char kDrmRootPublicKey[] = "drm_root_public_key";
const char kOemSerialNumber0[] = "oem_serial_number_0";
const char kOemSerialNumber1[] = "oem_serial_number_1";
const char kDevicePublicKey[] = "device_public_key";
@@ -40,13 +45,11 @@ const char kIntermediatePrivateKey[] = "intermediate_private_key";
const char kIntermediatePrivateKeyPassphrase[] =
"intermediate_private_key_passphrase";
const char kIntermediatePublicKey[] = "intermediate_public_key";
const char kServicePrivateKey[] = "service_private_key";
const char kServicePrivateKeyPassphrase[] = "service_private_key_phassphrase";
const char kServiceDrmCertificate[] = "service_drm_certificate";
const char kServicePrivateKeyPassphrase[] = "service_private_key_passphrase";
const char kProvisioningDrmCertificate[] = "provisioning_drm_certificate";
const char kProvisioningPrivateKey[] = "provisioning_private_key";
const char kProvisioningPrivateKeyPassphrase[] =
"provisioning_private_key_phassphrase";
"provisioning_private_key_passphrase";
const char kProvisioningPublicKey[] = "provisioning_public_key";
const char kProvisioningSignature[] = "provisioning_signature";
@@ -63,12 +66,28 @@ std::string StrCat(const std::string& in, int i) {
namespace widevine {
class MockDrmRootCertificate : public DrmRootCertificate {
public:
MockDrmRootCertificate()
: DrmRootCertificate(kCertificateTypeTesting, std::string(), std::string(),
kDrmRootPublicKey,
std::unique_ptr<RsaKeyFactory>()) {}
MOCK_CONST_METHOD3(VerifyCertificate,
Status(const std::string& serialized_cert,
SignedDrmCertificate* signed_drm_cert,
DrmCertificate* drm_cert));
};
class ProvisioningEngineImplTest : public ::testing::Test {
protected:
ProvisioningEngineImplTest() {
mock_rsa_key_factory_ = new MockRsaKeyFactory;
engine_impl_.set_rsa_key_factory(
std::unique_ptr<RsaKeyFactory>(mock_rsa_key_factory_));
RsaTestKeys test_keys;
rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo(
test_keys.private_test_key_2_2048_bits(), kServicePrivateKeyPassphrase,
&service_private_key_);
TestDrmCertificates test_certificates;
service_certificate_ = test_certificates.test_service_certificate();
}
ProvisioningStatus CheckDeviceStatus(uint32_t system_id,
@@ -77,211 +96,111 @@ class ProvisioningEngineImplTest : public ::testing::Test {
}
ProvisioningEngineImpl engine_impl_;
MockRsaKeyFactory* mock_rsa_key_factory_ = nullptr;
std::string service_certificate_;
std::string service_private_key_;
};
TEST_F(ProvisioningEngineImplTest, InvalidCertType) {
CertificateType invalid_certificate = static_cast<CertificateType>(100);
EXPECT_EQ(
INVALID_CERTIFICATE_TYPE,
engine_impl_.Initialize(
invalid_certificate, kServiceDrmCertificate, kServicePrivateKey,
kServicePrivateKeyPassphrase, kProvisioningDrmCertificate,
kProvisioningPrivateKey, kProvisioningPrivateKeyPassphrase,
kSecretSauce));
TEST_F(ProvisioningEngineImplTest, InvalidDrmServiceCertificate) {
EXPECT_EQ(INVALID_SERVICE_DRM_CERTIFICATE,
engine_impl_.Initialize(
kCertificateTypeTesting, "bad-certificate",
service_private_key_, kServicePrivateKeyPassphrase,
kProvisioningDrmCertificate, kProvisioningPrivateKey,
kProvisioningPrivateKeyPassphrase, kSecretSauce));
}
class ProvisioningEngineImplServiceTest : public ProvisioningEngineImplTest {
TEST_F(ProvisioningEngineImplTest, InvalidServiceKey) {
EXPECT_EQ(INVALID_SERVICE_DRM_CERTIFICATE,
engine_impl_.Initialize(
kCertificateTypeTesting, service_certificate_, "bad_key",
kServicePrivateKeyPassphrase, kProvisioningDrmCertificate,
kProvisioningPrivateKey, kProvisioningPrivateKeyPassphrase,
kSecretSauce));
}
TEST_F(ProvisioningEngineImplTest, InvalidServiceKeyPassprase) {
EXPECT_EQ(INVALID_SERVICE_DRM_CERTIFICATE,
engine_impl_.Initialize(
kCertificateTypeTesting, service_certificate_,
service_private_key_, "bad-passphrase",
kProvisioningDrmCertificate, kProvisioningPrivateKey,
kProvisioningPrivateKeyPassphrase, kSecretSauce));
}
class ProvisioningEngineImplProvTest : public ProvisioningEngineImplTest {
protected:
void SetUp() override {
mock_root_public_key_ = new MockRsaPublicKey();
EXPECT_CALL(*mock_rsa_key_factory_, CreateFromPkcs1PublicKey(_))
.WillOnce(Return(
ByMove(std::unique_ptr<RsaPublicKey>(mock_root_public_key_))));
service_cert_.set_public_key("service_public_key");
service_cert_.set_type(DrmDeviceCertificate::SERVICE);
signed_service_cert_.set_drm_certificate(service_cert_.SerializeAsString());
signed_service_cert_.set_signature("service_signature");
}
ProvisioningStatus Initialize(const std::string& service_drm_certificate) {
return engine_impl_.Initialize(
kCertTesting, service_drm_certificate, kServicePrivateKey,
kServicePrivateKeyPassphrase, kProvisioningDrmCertificate,
kProvisioningPrivateKey, kProvisioningPrivateKeyPassphrase,
kSecretSauce);
}
DrmDeviceCertificate service_cert_;
SignedDrmDeviceCertificate signed_service_cert_;
MockRsaPublicKey* mock_root_public_key_;
};
TEST_F(ProvisioningEngineImplServiceTest, Empty) {
EXPECT_EQ(INVALID_SERVICE_DRM_CERTIFICATE, Initialize(""));
}
TEST_F(ProvisioningEngineImplServiceTest, MissingDeviceCert) {
signed_service_cert_.clear_drm_certificate();
EXPECT_EQ(INVALID_SERVICE_DRM_CERTIFICATE,
Initialize(signed_service_cert_.SerializeAsString()));
}
TEST_F(ProvisioningEngineImplServiceTest, MissingSignature) {
signed_service_cert_.clear_signature();
EXPECT_EQ(INVALID_SERVICE_DRM_CERTIFICATE,
Initialize(signed_service_cert_.SerializeAsString()));
}
TEST_F(ProvisioningEngineImplServiceTest, SignatureVerificationFailure) {
EXPECT_CALL(*mock_root_public_key_,
VerifySignature(StrEq(service_cert_.SerializeAsString()),
"service_signature"))
.WillOnce(Return(false));
EXPECT_EQ(INVALID_SERVICE_DRM_CERTIFICATE,
Initialize(signed_service_cert_.SerializeAsString()));
}
TEST_F(ProvisioningEngineImplServiceTest, InvalidDeviceCertType) {
service_cert_.set_type(DrmDeviceCertificate::PROVISIONER);
signed_service_cert_.set_drm_certificate(service_cert_.SerializeAsString());
EXPECT_CALL(*mock_root_public_key_,
VerifySignature(StrEq(service_cert_.SerializeAsString()),
"service_signature"))
.WillOnce(Return(true));
EXPECT_EQ(INVALID_SERVICE_DRM_CERTIFICATE,
Initialize(signed_service_cert_.SerializeAsString()));
}
TEST_F(ProvisioningEngineImplServiceTest, InvaidPublicKey) {
EXPECT_CALL(*mock_root_public_key_, VerifySignature(_, "service_signature"))
.WillOnce(Return(true));
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey("service_public_key"))
.WillOnce(Return(ByMove(nullptr)));
EXPECT_EQ(INVALID_SERVICE_DRM_CERTIFICATE,
Initialize(signed_service_cert_.SerializeAsString()));
}
TEST_F(ProvisioningEngineImplServiceTest, InvalidPrivateKey) {
EXPECT_CALL(*mock_root_public_key_, VerifySignature(_, "service_signature"))
.WillOnce(Return(true));
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey("service_public_key"))
.WillOnce(
Return(ByMove(std::unique_ptr<RsaPublicKey>(new MockRsaPublicKey))));
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs8PrivateKey(kServicePrivateKey,
kServicePrivateKeyPassphrase))
.WillOnce(Return(ByMove(nullptr)));
EXPECT_EQ(INVALID_SERVICE_PRIVATE_KEY,
Initialize(signed_service_cert_.SerializeAsString()));
}
TEST_F(ProvisioningEngineImplServiceTest, MismatchPublicKeyPrivateKey) {
EXPECT_CALL(*mock_root_public_key_, VerifySignature(_, "service_signature"))
.WillOnce(Return(true));
MockRsaPublicKey* mock_rsa_public_key = new MockRsaPublicKey;
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey("service_public_key"))
.WillOnce(
Return(ByMove(std::unique_ptr<RsaPublicKey>(mock_rsa_public_key))));
MockRsaPrivateKey* mock_rsa_private_key = new MockRsaPrivateKey;
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs8PrivateKey(kServicePrivateKey,
kServicePrivateKeyPassphrase))
.WillOnce(
Return(ByMove(std::unique_ptr<RsaPrivateKey>(mock_rsa_private_key))));
EXPECT_CALL(*mock_rsa_public_key, MatchesPrivateKey(_))
.WillOnce(Return(false));
EXPECT_EQ(INVALID_SERVICE_PRIVATE_KEY,
Initialize(signed_service_cert_.SerializeAsString()));
}
class ProvisioningEngineImplProvTest
: public ProvisioningEngineImplServiceTest {
protected:
void SetUp() override {
ProvisioningEngineImplServiceTest::SetUp();
// Service certificate expectations.
EXPECT_CALL(*mock_root_public_key_, VerifySignature(_, "service_signature"))
.WillOnce(Return(true));
mock_service_public_key_ = new MockRsaPublicKey;
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey("service_public_key"))
.WillOnce(Return(
ByMove(std::unique_ptr<RsaPublicKey>(mock_service_public_key_))));
mock_service_private_key_ = new MockRsaPrivateKey;
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs8PrivateKey(kServicePrivateKey,
kServicePrivateKeyPassphrase))
.WillOnce(Return(
ByMove(std::unique_ptr<RsaPrivateKey>(mock_service_private_key_))));
EXPECT_CALL(*mock_service_public_key_, MatchesPrivateKey(_))
.WillOnce(Return(true));
prov_cert_.set_public_key(kProvisioningPublicKey);
prov_cert_.set_type(DrmDeviceCertificate::PROVISIONER);
prov_cert_.set_type(DrmCertificate::PROVISIONER);
signed_prov_cert_.set_drm_certificate(prov_cert_.SerializeAsString());
signed_prov_cert_.set_signature(kProvisioningSignature);
SetUpMockDrmRootCertificateWithExpectations();
SetUpMockRsa();
SetUpMockRootPublicKey();
}
void SetUpMockDrmRootCertificateWithExpectations() {
mock_drm_root_certificate_ = new MockDrmRootCertificate;
engine_impl_.set_drm_root_certificate(
std::unique_ptr<DrmRootCertificate>(mock_drm_root_certificate_));
EXPECT_CALL(*mock_drm_root_certificate_, VerifyCertificate(_, _, _))
.WillRepeatedly(Invoke([](const std::string& serialized_cert,
SignedDrmCertificate* signed_drm_cert,
DrmCertificate* drm_cert) {
SignedDrmCertificate signed_cert;
if (!signed_cert.ParseFromString(serialized_cert)) {
return Status(error::INVALID_ARGUMENT,
"Invalid SignedDrmCertificate proto");
}
if (signed_drm_cert) *signed_drm_cert = signed_cert;
if (drm_cert) {
EXPECT_TRUE(
drm_cert->ParseFromString(signed_cert.drm_certificate()));
}
return OkStatus();
}));
}
void SetUpMockRsa() {
mock_rsa_key_factory_ = new MockRsaKeyFactory;
engine_impl_.set_rsa_key_factory(
std::unique_ptr<RsaKeyFactory>(mock_rsa_key_factory_));
}
void SetUpMockRootPublicKey() {
mock_root_public_key_ = new MockRsaPublicKey();
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey(kDrmRootPublicKey))
.WillOnce(Return(
ByMove(std::unique_ptr<RsaPublicKey>(mock_root_public_key_))));
}
ProvisioningStatus Initialize(const std::string& provisioning_drm_certificate) {
return engine_impl_.Initialize(
kCertTesting, signed_service_cert_.SerializeAsString(),
kServicePrivateKey, kServicePrivateKeyPassphrase,
provisioning_drm_certificate, kProvisioningPrivateKey,
kProvisioningPrivateKeyPassphrase, "spoid_secret_sauce");
kCertificateTypeTesting, service_certificate_, service_private_key_,
kServicePrivateKeyPassphrase, provisioning_drm_certificate,
kProvisioningPrivateKey, kProvisioningPrivateKeyPassphrase,
kSecretSauce);
}
DrmDeviceCertificate prov_cert_;
SignedDrmDeviceCertificate signed_prov_cert_;
MockRsaPublicKey* mock_service_public_key_ = nullptr;
MockRsaPrivateKey* mock_service_private_key_ = nullptr;
RsaTestKeys test_keys_;
MockRsaKeyFactory* mock_rsa_key_factory_ = nullptr;
MockDrmRootCertificate* mock_drm_root_certificate_ = nullptr;
MockRsaPublicKey* mock_root_public_key_ = nullptr;
DrmCertificate prov_cert_;
SignedDrmCertificate signed_prov_cert_;
};
TEST_F(ProvisioningEngineImplProvTest, Empty) {
EXPECT_EQ(INVALID_PROVISIONER_DRM_CERTIFICATE, Initialize(""));
}
TEST_F(ProvisioningEngineImplProvTest, MissingDeviceCert) {
signed_prov_cert_.clear_drm_certificate();
EXPECT_EQ(INVALID_PROVISIONER_DRM_CERTIFICATE,
Initialize(signed_prov_cert_.SerializeAsString()));
}
TEST_F(ProvisioningEngineImplProvTest, MissingSignature) {
signed_prov_cert_.clear_signature();
EXPECT_EQ(INVALID_PROVISIONER_DRM_CERTIFICATE,
Initialize(signed_prov_cert_.SerializeAsString()));
}
TEST_F(ProvisioningEngineImplProvTest, SignatureVerificationFailure) {
EXPECT_CALL(*mock_root_public_key_,
VerifySignature(StrEq(prov_cert_.SerializeAsString()),
kProvisioningSignature))
.WillOnce(Return(false));
EXPECT_EQ(INVALID_PROVISIONER_DRM_CERTIFICATE,
Initialize(signed_prov_cert_.SerializeAsString()));
}
TEST_F(ProvisioningEngineImplProvTest, InvalidDeviceCertType) {
prov_cert_.set_type(DrmDeviceCertificate::SERVICE);
prov_cert_.set_type(DrmCertificate::SERVICE);
signed_prov_cert_.set_drm_certificate(prov_cert_.SerializeAsString());
EXPECT_CALL(*mock_root_public_key_,
VerifySignature(StrEq(prov_cert_.SerializeAsString()),
kProvisioningSignature))
.WillOnce(Return(true));
EXPECT_EQ(INVALID_PROVISIONER_DRM_CERTIFICATE,
Initialize(signed_prov_cert_.SerializeAsString()));
}
TEST_F(ProvisioningEngineImplProvTest, InvaidPublicKey) {
EXPECT_CALL(*mock_root_public_key_,
VerifySignature(_, kProvisioningSignature))
.WillOnce(Return(true));
TEST_F(ProvisioningEngineImplProvTest, InvalidPublicKey) {
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey(kProvisioningPublicKey))
.WillOnce(Return(ByMove(nullptr)));
@@ -290,9 +209,6 @@ TEST_F(ProvisioningEngineImplProvTest, InvaidPublicKey) {
}
TEST_F(ProvisioningEngineImplProvTest, InvalidPrivateKey) {
EXPECT_CALL(*mock_root_public_key_,
VerifySignature(_, kProvisioningSignature))
.WillOnce(Return(true));
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey(kProvisioningPublicKey))
.WillOnce(
@@ -306,9 +222,6 @@ TEST_F(ProvisioningEngineImplProvTest, InvalidPrivateKey) {
}
TEST_F(ProvisioningEngineImplProvTest, MismatchPublicKeyPrivateKey) {
EXPECT_CALL(*mock_root_public_key_,
VerifySignature(_, kProvisioningSignature))
.WillOnce(Return(true));
MockRsaPublicKey* mock_rsa_public_key = new MockRsaPublicKey;
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey(kProvisioningPublicKey))
@@ -326,35 +239,113 @@ TEST_F(ProvisioningEngineImplProvTest, MismatchPublicKeyPrivateKey) {
Initialize(signed_prov_cert_.SerializeAsString()));
}
class ProvisioningEngineImplGeneralTest
class ProvisioningEngineImplContextTest
: public ProvisioningEngineImplProvTest {
protected:
void SetUp() override {
ProvisioningEngineImplProvTest::SetUp();
// Provisioning certificate expectations.
EXPECT_CALL(*mock_root_public_key_,
VerifySignature(_, kProvisioningSignature))
SetUpMockRsaExpectations();
ASSERT_EQ(OK, ProvisioningEngineImplProvTest::Initialize(
signed_prov_cert_.SerializeAsString()));
}
void SetUpMockRsaExpectations() {
MockRsaPublicKey* mock_prov_public_key(new MockRsaPublicKey);
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey(kProvisioningPublicKey))
.WillOnce(Return(
ByMove(std::unique_ptr<RsaPublicKey>(mock_prov_public_key))));
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs8PrivateKey(kProvisioningPrivateKey,
kProvisioningPrivateKeyPassphrase))
.WillOnce(Return(
ByMove(std::unique_ptr<RsaPrivateKey>(new MockRsaPrivateKey))));
EXPECT_CALL(*mock_prov_public_key, MatchesPrivateKey(_))
.WillOnce(Return(true));
mock_prov_public_key_ = new MockRsaPublicKey;
}
};
TEST_F(ProvisioningEngineImplContextTest, ContextStoreAndRetrieveSuccess) {
const char kContextData[] = "I dislike tacky orange things";
ProvisioningContext context;
ASSERT_EQ(OK, engine_impl_.StoreContext(kContextData, &context));
EXPECT_NE(kContextData, context.context_data());
EXPECT_FALSE(context.mac().empty());
std::string context_data;
ASSERT_EQ(OK, engine_impl_.RetrieveContext(context, &context_data));
EXPECT_EQ(kContextData, context_data);
}
TEST_F(ProvisioningEngineImplContextTest, ContextStoreAndRetrieveFailBadData) {
const char kContextData[] = "Climate change is not a hoax";
ProvisioningContext context;
ASSERT_EQ(OK, engine_impl_.StoreContext(kContextData, &context));
++(*context.mutable_context_data())[5];
std::string context_data;
ASSERT_EQ(INVALID_CONTEXT,
engine_impl_.RetrieveContext(context, &context_data));
}
TEST_F(ProvisioningEngineImplContextTest, ContextStoreAndRetrieveFailBadMac) {
const char kContextData[] = "No one wants coal anymore";
ProvisioningContext context;
ASSERT_EQ(OK, engine_impl_.StoreContext(kContextData, &context));
++(*context.mutable_mac())[5];
std::string context_data;
ASSERT_EQ(INVALID_CONTEXT,
engine_impl_.RetrieveContext(context, &context_data));
}
TEST_F(ProvisioningEngineImplContextTest,
ContextStoreAndRetrieveFailBadKeyData) {
const char kContextData[] = "No one wants coal anymore";
ProvisioningContext context;
ASSERT_EQ(OK, engine_impl_.StoreContext(kContextData, &context));
++(*context.mutable_key_data())[5];
std::string context_data;
ASSERT_EQ(INVALID_CONTEXT_KEY_DATA,
engine_impl_.RetrieveContext(context, &context_data));
}
class ProvisioningEngineImplGeneralTest
: public ProvisioningEngineImplProvTest {
protected:
void SetUp() override {
ProvisioningEngineImplProvTest::SetUp();
SetUpMockProvisionerKey();
// Set up a DrmCertificate to be used later.
intermediate_cert_.set_type(DrmCertificate::DEVICE_MODEL);
intermediate_cert_.set_system_id(kSystemId);
intermediate_cert_.set_public_key(kIntermediatePublicKey);
signed_intermediate_cert_.set_drm_certificate(
intermediate_cert_.SerializeAsString());
signed_intermediate_cert_.set_signature(kSignature);
ASSERT_EQ(OK, ProvisioningEngineImplProvTest::Initialize(
signed_prov_cert_.SerializeAsString()));
}
void SetUpMockProvisionerKey() {
mock_prov_public_key_ = new MockRsaPublicKey();
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey(kProvisioningPublicKey))
.WillOnce(Return(
ByMove(std::unique_ptr<RsaPublicKey>(mock_prov_public_key_))));
mock_prov_private_key_ = new MockRsaPrivateKey;
EXPECT_CALL(
*mock_rsa_key_factory_,
CreateFromPkcs8PrivateKey(kProvisioningPrivateKey,
kProvisioningPrivateKeyPassphrase))
.WillOnce(Return(
mock_prov_private_key_ = new MockRsaPrivateKey();
ON_CALL(*mock_rsa_key_factory_,
CreateFromPkcs8PrivateKey(kProvisioningPrivateKey,
kProvisioningPrivateKeyPassphrase))
.WillByDefault(Return(
ByMove(std::unique_ptr<RsaPrivateKey>(mock_prov_private_key_))));
EXPECT_CALL(*mock_prov_public_key_, MatchesPrivateKey(_))
.WillOnce(Return(true));
}
ASSERT_EQ(OK, ProvisioningEngineImplProvTest::Initialize(
signed_prov_cert_.SerializeAsString()));
// Setup certificate status list.
void SetUpDcsl() {
// SetUp certificate status list.
cert_status_list_.set_creation_time_seconds(time(nullptr));
for (int i = 0; i < 2; ++i) {
DeviceCertificateStatus* cert_status =
@@ -365,11 +356,11 @@ class ProvisioningEngineImplGeneralTest
device_info->set_model(StrCat("model_", i));
}
cert_status_list_.mutable_certificate_status(0)->set_status(
DeviceCertificateStatus::VALID);
DeviceCertificateStatus::STATUS_RELEASED);
cert_status_list_.mutable_certificate_status(1)->set_status(
DeviceCertificateStatus::REVOKED);
DeviceCertificateStatus::STATUS_REVOKED);
SignedCertificateStatusList signed_cert_status_list;
SignedDeviceCertificateStatusList signed_cert_status_list;
signed_cert_status_list.set_certificate_status_list(
cert_status_list_.SerializeAsString());
EXPECT_CALL(*mock_root_public_key_,
@@ -380,22 +371,14 @@ class ProvisioningEngineImplGeneralTest
signed_cert_status_list.set_signature("cert_status_list_signature");
ASSERT_EQ(OK, engine_impl_.SetCertificateStatusList(
signed_cert_status_list.SerializeAsString(),
kExpirationPeriodSeconds));
// Setup a DrmDeviceCertificate to be used later.
intermediate_cert_.set_type(DrmDeviceCertificate::DRM_INTERMEDIATE);
intermediate_cert_.set_system_id(kSystemId);
intermediate_cert_.set_public_key(kIntermediatePublicKey);
signed_intermediate_cert_.set_drm_certificate(
intermediate_cert_.SerializeAsString());
signed_intermediate_cert_.set_signature(kSignature);
kInfiniteExpirationPeriodSeconds));
}
MockRsaPublicKey* mock_prov_public_key_ = nullptr;
MockRsaPrivateKey* mock_prov_private_key_ = nullptr;
DeviceCertificateStatusList cert_status_list_;
DrmDeviceCertificate intermediate_cert_;
SignedDrmDeviceCertificate signed_intermediate_cert_;
DrmCertificate intermediate_cert_;
SignedDrmCertificate signed_intermediate_cert_;
};
TEST_F(ProvisioningEngineImplGeneralTest, InvalidCertificateStatusList) {
@@ -408,7 +391,7 @@ TEST_F(ProvisioningEngineImplGeneralTest, InvalidCertificateStatusList) {
TEST_F(ProvisioningEngineImplGeneralTest,
CertificateStatusListIncorrectSignature) {
SignedCertificateStatusList signed_cert_status_list;
SignedDeviceCertificateStatusList signed_cert_status_list;
signed_cert_status_list.set_certificate_status_list(
cert_status_list_.SerializeAsString());
EXPECT_CALL(*mock_root_public_key_,
@@ -422,6 +405,8 @@ TEST_F(ProvisioningEngineImplGeneralTest,
}
TEST_F(ProvisioningEngineImplGeneralTest, GetDeviceInfoAndCheckDeviceStatus) {
SetUpDcsl();
EXPECT_EQ(OK, CheckDeviceStatus(kSystemId, kEmptyOemSerialNumber));
auto device_info = engine_impl_.GetDeviceInfo(kSystemId);
ASSERT_NE(nullptr, device_info);
@@ -440,8 +425,10 @@ TEST_F(ProvisioningEngineImplGeneralTest, GetDeviceInfoAndCheckDeviceStatus) {
}
TEST_F(ProvisioningEngineImplGeneralTest, UpdateCertificateStatusList) {
SetUpDcsl();
cert_status_list_.mutable_certificate_status(0)->set_status(
DeviceCertificateStatus::REVOKED);
DeviceCertificateStatus::STATUS_REVOKED);
DeviceCertificateStatus* cert_status =
cert_status_list_.add_certificate_status();
@@ -449,7 +436,7 @@ TEST_F(ProvisioningEngineImplGeneralTest, UpdateCertificateStatusList) {
device_info->set_system_id(kSystemId + 2);
device_info->set_model("model_2");
SignedCertificateStatusList signed_cert_status_list;
SignedDeviceCertificateStatusList signed_cert_status_list;
signed_cert_status_list.set_certificate_status_list(
cert_status_list_.SerializeAsString());
EXPECT_CALL(*mock_root_public_key_,
@@ -496,16 +483,16 @@ TEST_F(ProvisioningEngineImplGeneralTest, GenerateDrmIntermediateCertificate) {
ASSERT_EQ(OK, engine_impl_.GenerateDrmIntermediateCertificate(
kSystemId, kIntermediatePublicKey, &certificate));
SignedDrmDeviceCertificate signed_drm_cert_proto;
SignedDrmCertificate signed_drm_cert_proto;
ASSERT_TRUE(signed_drm_cert_proto.ParseFromString(certificate));
EXPECT_EQ(drm_certificate, signed_drm_cert_proto.drm_certificate());
EXPECT_EQ(kSignature, signed_drm_cert_proto.signature());
EXPECT_EQ(signed_prov_cert_.SerializeAsString(),
signed_drm_cert_proto.signer().SerializeAsString());
DrmDeviceCertificate drm_cert_proto;
DrmCertificate drm_cert_proto;
ASSERT_TRUE(drm_cert_proto.ParseFromString(drm_certificate));
EXPECT_EQ(DrmDeviceCertificate::DRM_INTERMEDIATE, drm_cert_proto.type());
EXPECT_EQ(DrmCertificate::DEVICE_MODEL, drm_cert_proto.type());
EXPECT_NE("", drm_cert_proto.serial_number());
EXPECT_EQ(kSystemId, drm_cert_proto.system_id());
EXPECT_EQ(kIntermediatePublicKey, drm_cert_proto.public_key());
@@ -513,10 +500,10 @@ TEST_F(ProvisioningEngineImplGeneralTest, GenerateDrmIntermediateCertificate) {
TEST_F(ProvisioningEngineImplGeneralTest,
AddDrmIntermediateCertificateInvalidCert) {
EXPECT_EQ(INVALID_INTERMEDIATE_DRM_CERTIFICATE,
engine_impl_.AddDrmIntermediateCertificate(
"", kIntermediatePrivateKey,
kIntermediatePrivateKeyPassphrase));
EXPECT_EQ(
INVALID_INTERMEDIATE_DRM_CERTIFICATE,
engine_impl_.AddDrmIntermediateCertificate(
"", kIntermediatePrivateKey, kIntermediatePrivateKeyPassphrase));
EXPECT_EQ(INVALID_INTERMEDIATE_DRM_CERTIFICATE,
engine_impl_.AddDrmIntermediateCertificate(
"invalid_intermediate_cert", kIntermediatePrivateKey,
@@ -525,20 +512,14 @@ TEST_F(ProvisioningEngineImplGeneralTest,
TEST_F(ProvisioningEngineImplGeneralTest,
AddDrmIntermediateCertificateIncorrectCertType) {
intermediate_cert_.set_type(DrmDeviceCertificate::DRM_USER_DEVICE);
intermediate_cert_.set_type(DrmCertificate::DEVICE);
signed_intermediate_cert_.set_drm_certificate(
intermediate_cert_.SerializeAsString());
EXPECT_CALL(
*mock_prov_public_key_,
VerifySignature(StrEq(signed_intermediate_cert_.drm_certificate()),
StrEq(signed_intermediate_cert_.signature())))
.WillOnce(Return(true));
EXPECT_EQ(
INVALID_INTERMEDIATE_DRM_CERTIFICATE,
engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey, kIntermediatePrivateKeyPassphrase));
EXPECT_EQ(INVALID_INTERMEDIATE_DRM_CERTIFICATE,
engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey, kIntermediatePrivateKeyPassphrase));
}
TEST_F(ProvisioningEngineImplGeneralTest,
@@ -547,59 +528,42 @@ TEST_F(ProvisioningEngineImplGeneralTest,
signed_intermediate_cert_.set_drm_certificate(
intermediate_cert_.SerializeAsString());
EXPECT_CALL(
*mock_prov_public_key_,
VerifySignature(StrEq(signed_intermediate_cert_.drm_certificate()),
StrEq(signed_intermediate_cert_.signature())))
.WillOnce(Return(true));
EXPECT_EQ(
UNKNOWN_SYSTEM_ID,
engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey, kIntermediatePrivateKeyPassphrase));
EXPECT_EQ(UNKNOWN_SYSTEM_ID,
engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey, kIntermediatePrivateKeyPassphrase));
}
TEST_F(ProvisioningEngineImplGeneralTest,
AddDrmIntermediateCertificateRevokedCert) {
SetUpDcsl();
intermediate_cert_.set_system_id(kSystemId + 1);
signed_intermediate_cert_.set_drm_certificate(
intermediate_cert_.SerializeAsString());
EXPECT_CALL(
*mock_prov_public_key_,
VerifySignature(StrEq(signed_intermediate_cert_.drm_certificate()),
StrEq(signed_intermediate_cert_.signature())))
.WillOnce(Return(true));
EXPECT_EQ(DEVICE_REVOKED, engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey,
kIntermediatePrivateKeyPassphrase));
EXPECT_EQ(DEVICE_REVOKED,
engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey, kIntermediatePrivateKeyPassphrase));
}
TEST_F(ProvisioningEngineImplGeneralTest,
AddDrmIntermediateCertificateInvalidPublicKey) {
EXPECT_CALL(
*mock_prov_public_key_,
VerifySignature(StrEq(signed_intermediate_cert_.drm_certificate()),
StrEq(signed_intermediate_cert_.signature())))
.WillOnce(Return(true));
SetUpDcsl();
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey(kIntermediatePublicKey))
.WillOnce(Return(ByMove(nullptr)));
EXPECT_EQ(
INVALID_INTERMEDIATE_DRM_CERTIFICATE,
engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey, kIntermediatePrivateKeyPassphrase));
EXPECT_EQ(INVALID_INTERMEDIATE_DRM_CERTIFICATE,
engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey, kIntermediatePrivateKeyPassphrase));
}
TEST_F(ProvisioningEngineImplGeneralTest,
AddDrmIntermediateCertificateInvalidPrivateKey) {
EXPECT_CALL(
*mock_prov_public_key_,
VerifySignature(StrEq(signed_intermediate_cert_.drm_certificate()),
StrEq(signed_intermediate_cert_.signature())))
.WillOnce(Return(true));
SetUpDcsl();
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey(kIntermediatePublicKey))
@@ -610,20 +574,15 @@ TEST_F(ProvisioningEngineImplGeneralTest,
kIntermediatePrivateKeyPassphrase))
.WillOnce(Return(ByMove(nullptr)));
EXPECT_EQ(
INVALID_INTERMEDIATE_PRIVATE_KEY,
engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey, kIntermediatePrivateKeyPassphrase));
EXPECT_EQ(INVALID_INTERMEDIATE_PRIVATE_KEY,
engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey, kIntermediatePrivateKeyPassphrase));
}
TEST_F(ProvisioningEngineImplGeneralTest,
AddDrmIntermediateCertificateMismatchPublicPrivateKey) {
EXPECT_CALL(
*mock_prov_public_key_,
VerifySignature(StrEq(signed_intermediate_cert_.drm_certificate()),
StrEq(signed_intermediate_cert_.signature())))
.WillOnce(Return(true));
SetUpDcsl();
MockRsaPublicKey* mock_intermediate_public_key = new MockRsaPublicKey;
EXPECT_CALL(*mock_rsa_key_factory_,
@@ -638,20 +597,15 @@ TEST_F(ProvisioningEngineImplGeneralTest,
EXPECT_CALL(*mock_intermediate_public_key, MatchesPrivateKey(_))
.WillOnce(Return(false));
EXPECT_EQ(
INVALID_INTERMEDIATE_PRIVATE_KEY,
engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey, kIntermediatePrivateKeyPassphrase));
EXPECT_EQ(INVALID_INTERMEDIATE_PRIVATE_KEY,
engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey, kIntermediatePrivateKeyPassphrase));
}
TEST_F(ProvisioningEngineImplGeneralTest,
AddDrmIntermediateCertificateSuccess) {
EXPECT_CALL(
*mock_prov_public_key_,
VerifySignature(StrEq(signed_intermediate_cert_.drm_certificate()),
StrEq(signed_intermediate_cert_.signature())))
.WillOnce(Return(true));
SetUpDcsl();
MockRsaPublicKey* mock_intermediate_public_key = new MockRsaPublicKey;
EXPECT_CALL(*mock_rsa_key_factory_,
@@ -666,17 +620,17 @@ TEST_F(ProvisioningEngineImplGeneralTest,
EXPECT_CALL(*mock_intermediate_public_key, MatchesPrivateKey(_))
.WillOnce(Return(true));
EXPECT_EQ(OK, engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey,
kIntermediatePrivateKeyPassphrase));
EXPECT_EQ(OK,
engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey, kIntermediatePrivateKeyPassphrase));
}
TEST_F(ProvisioningEngineImplGeneralTest, ExpiredCertificateStatusList) {
cert_status_list_.set_creation_time_seconds(time(nullptr) -
kExpirationPeriodSeconds - 1);
SignedCertificateStatusList signed_cert_status_list;
SignedDeviceCertificateStatusList signed_cert_status_list;
signed_cert_status_list.set_certificate_status_list(
cert_status_list_.SerializeAsString());
EXPECT_CALL(*mock_root_public_key_,
@@ -687,54 +641,49 @@ TEST_F(ProvisioningEngineImplGeneralTest, ExpiredCertificateStatusList) {
signed_cert_status_list.SerializeAsString(),
kExpirationPeriodSeconds));
EXPECT_CALL(
*mock_prov_public_key_,
VerifySignature(StrEq(signed_intermediate_cert_.drm_certificate()),
StrEq(signed_intermediate_cert_.signature())))
.WillOnce(Return(true));
EXPECT_EQ(
STATUS_LIST_EXPIRED,
engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey, kIntermediatePrivateKeyPassphrase));
EXPECT_EQ(STATUS_LIST_EXPIRED,
engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey, kIntermediatePrivateKeyPassphrase));
}
TEST_F(ProvisioningEngineImplGeneralTest,
GenerateDeviceDrmCertificateRevokedDevice) {
SetUpDcsl();
std::string certificate;
EXPECT_EQ(DEVICE_REVOKED,
engine_impl_.GenerateDeviceDrmCertificate(
kSystemId + 1, kOemSerialNumber1, kDevicePublicKey,
kCertificateSerialNumber, &certificate));
RootCertificateSerialNumber, &certificate));
}
TEST_F(ProvisioningEngineImplGeneralTest,
GenerateDeviceDrmCertificateWithMismatchingOemSerialNumber) {
SetUpDcsl();
std::string certificate;
// If oem serial number does not match, consider as revoked.
EXPECT_EQ(DEVICE_REVOKED,
engine_impl_.GenerateDeviceDrmCertificate(
kSystemId, kOemSerialNumber1, kDevicePublicKey,
kCertificateSerialNumber, &certificate));
EXPECT_EQ(DEVICE_REVOKED, engine_impl_.GenerateDeviceDrmCertificate(
kSystemId, kOemSerialNumber1, kDevicePublicKey,
RootCertificateSerialNumber, &certificate));
}
TEST_F(ProvisioningEngineImplGeneralTest,
GenerateDeviceDrmCertificateWithoutIntermediateCert) {
SetUpDcsl();
std::string certificate;
EXPECT_EQ(MISSING_DRM_INTERMEDIATE_CERT,
EXPECT_EQ(MISSING_DEVICE_MODEL_CERT,
engine_impl_.GenerateDeviceDrmCertificate(
kSystemId, kOemSerialNumber0, kDevicePublicKey,
kCertificateSerialNumber, &certificate));
RootCertificateSerialNumber, &certificate));
}
TEST_F(ProvisioningEngineImplGeneralTest,
GenerateDeviceDrmCertificate) {
TEST_F(ProvisioningEngineImplGeneralTest, GenerateDeviceDrmCertificate) {
SetUpDcsl();
// Add Intermediate certificate.
EXPECT_CALL(
*mock_prov_public_key_,
VerifySignature(StrEq(signed_intermediate_cert_.drm_certificate()),
StrEq(signed_intermediate_cert_.signature())))
.WillOnce(Return(true));
MockRsaPublicKey* mock_intermediate_public_key = new MockRsaPublicKey;
EXPECT_CALL(*mock_rsa_key_factory_,
@@ -750,10 +699,10 @@ TEST_F(ProvisioningEngineImplGeneralTest,
EXPECT_CALL(*mock_intermediate_public_key, MatchesPrivateKey(_))
.WillOnce(Return(true));
EXPECT_EQ(OK, engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey,
kIntermediatePrivateKeyPassphrase));
EXPECT_EQ(OK,
engine_impl_.AddDrmIntermediateCertificate(
signed_intermediate_cert_.SerializeAsString(),
kIntermediatePrivateKey, kIntermediatePrivateKeyPassphrase));
// Intermediate private key expectation.
std::string drm_certificate;
@@ -763,19 +712,19 @@ TEST_F(ProvisioningEngineImplGeneralTest,
std::string certificate;
EXPECT_EQ(OK, engine_impl_.GenerateDeviceDrmCertificate(
kSystemId, kOemSerialNumber0, kDevicePublicKey,
kCertificateSerialNumber, &certificate));
RootCertificateSerialNumber, &certificate));
SignedDrmDeviceCertificate signed_drm_cert_proto;
SignedDrmCertificate signed_drm_cert_proto;
ASSERT_TRUE(signed_drm_cert_proto.ParseFromString(certificate));
EXPECT_EQ(drm_certificate, signed_drm_cert_proto.drm_certificate());
EXPECT_EQ(kSignature, signed_drm_cert_proto.signature());
EXPECT_THAT(signed_intermediate_cert_.SerializeAsString(),
signed_drm_cert_proto.signer().SerializeAsString());
DrmDeviceCertificate drm_cert_proto;
DrmCertificate drm_cert_proto;
ASSERT_TRUE(drm_cert_proto.ParseFromString(drm_certificate));
EXPECT_EQ(DrmDeviceCertificate::DRM_USER_DEVICE, drm_cert_proto.type());
EXPECT_EQ(kCertificateSerialNumber, drm_cert_proto.serial_number());
EXPECT_EQ(DrmCertificate::DEVICE, drm_cert_proto.type());
EXPECT_EQ(RootCertificateSerialNumber, drm_cert_proto.serial_number());
EXPECT_EQ(kSystemId, drm_cert_proto.system_id());
EXPECT_EQ(kDevicePublicKey, drm_cert_proto.public_key());
}

View File

@@ -1,5 +1,5 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
// 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
@@ -10,249 +10,53 @@
#include <stddef.h>
#include "gflags/gflags.h"
#include "glog/logging.h"
#include "common/aes_cbc_util.h"
#include "common/random_util.h"
#include "common/rsa_key.h"
#include "common/sha_util.h"
#include "provisioning_sdk/public/provisioning_status.h"
DEFINE_int32(prov_sdk_log_every_n, 1,
"parameter for LOG_EVERY_N to help abate log spamming.");
#define LOG_EVERY_N_WITH_PROTO(message, proto) \
LOG_EVERY_N(WARNING, FLAGS_prov_sdk_log_every_n) \
<< (message) << " [proto: " << (proto).ShortDebugString() << "]"
namespace widevine {
ProvisioningSessionImpl::ProvisioningSessionImpl(
const ProvisioningEngineImpl& engine, const OemDeviceCert& oem_device_cert,
const RsaPrivateKey& service_private_key)
const ProvisioningEngineImpl& engine)
: engine_(engine),
oem_device_cert_(oem_device_cert),
service_private_key_(service_private_key),
rsa_key_factory_(new RsaKeyFactory) {}
ProvisioningSessionImpl::~ProvisioningSessionImpl() {}
ProvisioningStatus ProvisioningSessionImpl::Initialize(
const std::string& device_public_key, const std::string& device_private_key) {
const std::string& device_drm_public_key, const std::string& device_drm_private_key) {
auto rsa_public_key =
rsa_key_factory_->CreateFromPkcs1PublicKey(device_public_key);
if (!rsa_public_key) return INVALID_DEVICE_PUBLIC_KEY;
rsa_key_factory_->CreateFromPkcs1PublicKey(device_drm_public_key);
if (!rsa_public_key) return INVALID_DRM_DEVICE_PUBLIC_KEY;
// Use empty std::string to indicate the private key is not encrypted.
const std::string kClearPkcs8PrivateKeyPassphrase;
auto rsa_private_key = rsa_key_factory_->CreateFromPkcs8PrivateKey(
device_private_key, kClearPkcs8PrivateKeyPassphrase);
if (!rsa_private_key) return INVALID_DEVICE_PRIVATE_KEY;
device_drm_private_key, kClearPkcs8PrivateKeyPassphrase);
if (!rsa_private_key) return INVALID_DRM_DEVICE_PRIVATE_KEY;
if (!rsa_public_key->MatchesPrivateKey(*rsa_private_key)) {
LOG(WARNING) << "Device public key and private key do not match.";
return INVALID_DEVICE_PRIVATE_KEY;
return INVALID_DRM_DEVICE_PRIVATE_KEY;
}
device_public_key_ = device_public_key;
device_private_key_ = device_private_key;
device_drm_public_key_ = device_drm_public_key;
device_drm_private_key_ = device_drm_private_key;
return OK;
}
ProvisioningStatus ProvisioningSessionImpl::ProcessMessage(
const std::string& message, std::string* response) {
SignedProvisioningMessage signed_request;
ProvisioningRequest request;
if (!ValidateAndDeserializeRequest(message, &signed_request, &request))
return INVALID_REQUEST_MESSAGE;
ClientIdentification client_id;
if (request.has_encrypted_client_id()) {
if (!DecryptClientIdentification(request.encrypted_client_id(), &client_id))
return INVALID_REQUEST_MESSAGE;
} else {
DCHECK(request.has_client_id());
client_id.Swap(request.mutable_client_id());
}
if (client_id.type() != ClientIdentification::OEM_DEVICE_CERTIFICATE) {
LOG_EVERY_N_WITH_PROTO("Invalid client_id type", client_id);
return INVALID_REQUEST_MESSAGE;
}
if (client_id.token().empty()) {
LOG_EVERY_N_WITH_PROTO("Missing client_id.token", client_id);
return INVALID_REQUEST_MESSAGE;
}
std::unique_ptr<RsaPublicKey> cert_public_key;
uint32_t system_id;
std::string oem_ca_serial_number;
if (!oem_device_cert_.VerifyCertificateChain(client_id.token(),
&cert_public_key, &system_id,
&oem_ca_serial_number)) {
LOG_EVERY_N_WITH_PROTO("Invalid token", client_id);
return INVALID_REQUEST_MESSAGE;
}
if (!cert_public_key->VerifySignature(signed_request.message(),
signed_request.signature())) {
LOG_EVERY_N_WITH_PROTO("Signature verification failed", client_id);
return INVALID_REQUEST_MESSAGE;
}
// Save device_info for query later.
device_info_ = engine_.GetDeviceInfo(system_id);
std::string certificate_serial_number;
if (request.has_spoid()) {
certificate_serial_number = request.spoid();
} else {
// Generate stable serial number.
const std::string stable_data(client_id.token() + request.stable_id() +
request.provider_id() +
engine_.secret_spoid_sauce());
const std::string hash = Sha256_Hash(stable_data);
const size_t kCertificateSerialNumberSize = 16;
certificate_serial_number = hash.substr(0, kCertificateSerialNumberSize);
}
ProvisioningResponse provisioning_response;
ProvisioningStatus status = GenerateProvisioningResponse(
system_id, oem_ca_serial_number, request.provider_id(),
certificate_serial_number, *cert_public_key, &provisioning_response);
if (status != OK) return status;
provisioning_response.set_nonce(request.nonce());
// Sign the response.
SignedProvisioningMessage signed_message;
if (!provisioning_response.SerializeToString(
signed_message.mutable_message())) {
LOG(WARNING) << "Error serializing ProvisioningResponse.";
return INTERNAL_ERROR;
}
if (!service_private_key_.GenerateSignature(
signed_message.message(), signed_message.mutable_signature())) {
LOG(WARNING) << "Failed to sign ProvisioningResponse.";
return INTERNAL_ERROR;
}
if (!signed_message.SerializeToString(response)) {
LOG(WARNING) << "Error serializing SignedProvisioningMessage.";
return INTERNAL_ERROR;
ProvisioningStatus ProvisioningSessionImpl::Initialize(
const std::string& keybox_device_key) {
if (keybox_device_key.empty()) {
LOG(WARNING) << "Keybox device key is empty.";
return INVALID_KEYBOX_DEVICE_KEY;
}
keybox_device_key_ = keybox_device_key;
return OK;
}
bool ProvisioningSessionImpl::ValidateAndDeserializeRequest(
const std::string& message, SignedProvisioningMessage* signed_request,
ProvisioningRequest* request) const {
if (!signed_request->ParseFromString(message)) {
LOG_EVERY_N(WARNING, FLAGS_prov_sdk_log_every_n)
<< "Failed to parse SignedProvisioningMessage.";
return false;
}
VLOG(1) << "signed_request: " << signed_request->ShortDebugString();
if (signed_request->message().empty()) {
LOG_EVERY_N_WITH_PROTO("Missing message", *signed_request);
return false;
}
if (signed_request->signature().empty()) {
LOG_EVERY_N_WITH_PROTO("Missing signature", *signed_request);
return false;
}
if (!request->ParseFromString(signed_request->message())) {
LOG_EVERY_N_WITH_PROTO("Failed to parse ProvisioningRequest",
*signed_request);
return false;
}
if (request->has_encrypted_client_id()) {
const EncryptedClientIdentification& encrypted_client_id =
request->encrypted_client_id();
if (encrypted_client_id.encrypted_client_id().empty()) {
LOG_EVERY_N_WITH_PROTO("Missing encrypted_client_id",
encrypted_client_id);
return false;
}
if (encrypted_client_id.encrypted_client_id_iv().empty()) {
LOG_EVERY_N_WITH_PROTO("Missing encrypted_client_id_iv",
encrypted_client_id);
return false;
}
if (encrypted_client_id.encrypted_privacy_key().empty()) {
LOG_EVERY_N_WITH_PROTO("Missing encrypted_privacy_key",
encrypted_client_id);
return false;
}
} else if (!request->has_client_id()) {
LOG_EVERY_N_WITH_PROTO("Missing clear_or_encrypted_client_id", *request);
return false;
}
const size_t kMinimumRequiredNonceLength = 4;
if (request->nonce().size() < kMinimumRequiredNonceLength) {
LOG_EVERY_N_WITH_PROTO("Missing or invalid nonce", *request);
return false;
}
return true;
}
bool ProvisioningSessionImpl::DecryptClientIdentification(
const EncryptedClientIdentification& encrypted_client_id,
ClientIdentification* client_id) {
std::string privacy_key;
if (!service_private_key_.Decrypt(encrypted_client_id.encrypted_privacy_key(),
&privacy_key)) {
LOG_EVERY_N_WITH_PROTO("Failed to decrypt encrypted_privacy_key",
encrypted_client_id);
return false;
}
std::string serialized_client_id(crypto_util::DecryptAesCbc(
privacy_key, encrypted_client_id.encrypted_client_id_iv(),
encrypted_client_id.encrypted_client_id()));
if (serialized_client_id.empty()) {
LOG_EVERY_N_WITH_PROTO("Failed to decrypt client_id", encrypted_client_id);
return false;
}
if (!client_id->ParseFromString(serialized_client_id)) {
LOG_EVERY_N_WITH_PROTO("Failed to parse client_id", encrypted_client_id);
return false;
}
return true;
}
ProvisioningStatus ProvisioningSessionImpl::GenerateProvisioningResponse(
uint32_t system_id, const std::string& oem_ca_serial_number,
const std::string& provider_id, const std::string& certificate_serial_number,
const RsaPublicKey& cert_public_key, ProvisioningResponse* response) {
ProvisioningStatus status = engine_.GenerateProviderDeviceDrmCertificate(
system_id, oem_ca_serial_number, provider_id, device_public_key_,
certificate_serial_number, response->mutable_device_certificate());
if (status != OK) return status;
const size_t kAesKeySize = 16;
const size_t kIvSize = 16;
// Encrypt private key.
std::string message_key;
if (!RandomBytes(kAesKeySize, &message_key)) {
LOG(WARNING) << "Failed to generate message_key.";
return INTERNAL_ERROR;
}
std::string iv;
if (!RandomBytes(kIvSize, &iv)) {
LOG(WARNING) << "Failed to generate iv.";
return INTERNAL_ERROR;
}
response->set_device_rsa_key_iv(iv);
response->set_device_rsa_key(
crypto_util::EncryptAesCbc(message_key, iv, device_private_key_));
if (response->device_rsa_key().empty()) {
LOG(WARNING) << "Failed to encrypt device_rsa_key";
return INTERNAL_ERROR;
}
if (!cert_public_key.Encrypt(message_key, response->mutable_wrapping_key())) {
LOG(WARNING) << "Failed to encrypt wrapping_key";
return INTERNAL_ERROR;
}
return OK;
const ProvisionedDeviceInfo* ProvisioningSessionImpl::GetDeviceInfo() const {
LOG(FATAL) << "Not implemented.";
}
} // namespace widevine

View File

@@ -1,5 +1,5 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
// 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
@@ -14,73 +14,62 @@
#include <stdint.h>
#include <memory>
#include <string>
#include <utility>
#include "gflags/gflags.h"
#include "common/rsa_key.h"
#include "provisioning_sdk/internal/oem_device_cert.h"
#include "provisioning_sdk/internal/provisioning_engine_impl.h"
#include "provisioning_sdk/public/provisioning_status.h"
#include "protos/public/certificate_provisioning.pb.h"
#include "protos/public/client_identification.pb.h"
#include "protos/public/device_certificate.pb.h"
#include "protos/public/provisioned_device_info.pb.h"
DECLARE_int32(prov_sdk_log_every_n);
namespace widevine {
class ProvisioningEngineImpl;
class ProvisionedDeviceInfo;
class ProvisioningSessionImpl {
public:
ProvisioningSessionImpl(const ProvisioningEngineImpl& engine,
const OemDeviceCert& oem_device_cert,
const RsaPrivateKey& service_private_key);
~ProvisioningSessionImpl();
explicit ProvisioningSessionImpl(const ProvisioningEngineImpl& engine);
virtual ~ProvisioningSessionImpl();
// Initialize provisioning session with given public key and private key.
ProvisioningStatus Initialize(const std::string& device_public_key,
const std::string& device_private_key);
// This is for certificate based provisioning protocol.
ProvisioningStatus Initialize(const std::string& device_drm_public_key,
const std::string& device_drm_private_key);
// Initialize provisioning session with keybox device key.
// This is for keybox based provisioning protocol.
ProvisioningStatus Initialize(const std::string& keybox_device_key);
// 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|.
// Returns OK if successful, or an appropriate error status code otherwise.
ProvisioningStatus ProcessMessage(const std::string& message, std::string* response);
virtual ProvisioningStatus ProcessMessage(const std::string& message,
std::string* response,
bool* done) = 0;
// * Returns a ProvisioneddeviceInfo message containing information about the
// type of device being provisioned. May return nullptr.
const ProvisionedDeviceInfo* GetDeviceInfo() const {
return device_info_.get();
}
virtual const ProvisionedDeviceInfo* GetDeviceInfo() const;
private:
protected:
friend class ProvisioningSessionImplTest;
friend class Provisioning30SessionImplTest;
ProvisioningSessionImpl(const ProvisioningSessionImpl&) = delete;
ProvisioningSessionImpl& operator=(const ProvisioningSessionImpl&) = delete;
bool ValidateAndDeserializeRequest(const std::string& message,
SignedProvisioningMessage* signed_request,
ProvisioningRequest* request) const;
bool DecryptClientIdentification(
const EncryptedClientIdentification& encrypted_client_id,
ClientIdentification* client_id);
ProvisioningStatus GenerateProvisioningResponse(
uint32_t system_id, const std::string& oem_ca_serial_number,
const std::string& provider_id, const std::string& certificate_serial_number,
const RsaPublicKey& cert_public_key, ProvisioningResponse* response);
// Inject rsa_key_factory for testing.
void set_rsa_key_factory(std::unique_ptr<RsaKeyFactory> rsa_key_factory) {
rsa_key_factory_ = std::move(rsa_key_factory);
}
const ProvisioningEngineImpl& engine_;
const OemDeviceCert& oem_device_cert_;
const RsaPrivateKey& service_private_key_;
std::unique_ptr<RsaKeyFactory> rsa_key_factory_;
std::string device_public_key_;
std::string device_private_key_;
std::shared_ptr<ProvisionedDeviceInfo> device_info_;
std::string device_drm_public_key_;
std::string device_drm_private_key_;
std::string keybox_device_key_;
};
} // namespace widevine

View File

@@ -1,5 +1,5 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
// 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
@@ -8,12 +8,9 @@
#include "provisioning_sdk/internal/provisioning_session_impl.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "common/aes_cbc_util.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "common/mock_rsa_key.h"
#include "common/sha_util.h"
#include "provisioning_sdk/internal/oem_device_cert.h"
#include "provisioning_sdk/internal/provisioning_engine_impl.h"
using ::testing::_;
@@ -21,82 +18,39 @@ using ::testing::ByMove;
using ::testing::DoAll;
using ::testing::IsEmpty;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SetArgPointee;
namespace {
const char kEncryptedClientIdIv[] = "sixteen_bytes_iv";
const char kPrivacyKey[] = "privacy_key_16B_";
const char kProviderId[] = "testing_provider";
const char kClientToken[] = "client_id_token";
const char kDevicePublicKey[] = "device_public_key";
const char kEncryptedPrivacyKey[] = "encrypted_privacy_key";
const char kDevicePrivateKey[] = "device_private_key";
const char kWrappingKey[] = "wrapping_key";
const char kDeviceCertificate[] = "device_certificate";
const char kNonce[] = "testing_nonce";
const char kSignature[] = "generated_signature";
// Derives Stable Per-Origin IDentifiers.
std::string DeriveSpoid(const std::string& client_token,
const std::string& provider_id,
const std::string& secret_sauce) {
return widevine::Sha256_Hash(client_token + provider_id + secret_sauce)
.substr(0, 16);
}
const char kDevicePublicKey[] = "device_public_key";
} // namespace
namespace widevine {
class MockProvisioningEngineImpl : public ProvisioningEngineImpl {
// Fake session impl to deal with abstract methods..
class FakeProvisioningSessionImpl : public ProvisioningSessionImpl {
public:
MOCK_CONST_METHOD6(GenerateProviderDeviceDrmCertificate,
ProvisioningStatus(uint32_t system_id,
const std::string& oem_ca_serial_number,
const std::string& provider_id,
const std::string& public_key,
const std::string& certificate_serial_number,
std::string* certificate));
};
explicit FakeProvisioningSessionImpl(const ProvisioningEngineImpl& engine) :
ProvisioningSessionImpl(engine) {}
class MockOemDeviceCert : public OemDeviceCert {
public:
// gmock does not support SetArgPointee on std::unique_ptr, so we have to
// workaround it with a trick.
MOCK_CONST_METHOD4(DoVerifyCertificateChain,
bool(const std::string& certificate_chain,
RsaPublicKey** leaf_public_key, uint32_t* system_id,
std::string* oem_ca_serial_number));
bool VerifyCertificateChain(const std::string& certificate_chain,
std::unique_ptr<RsaPublicKey>* leaf_public_key,
uint32_t* system_id,
std::string* oem_ca_serial_number) const override {
RsaPublicKey* raw_leaf_public_key = nullptr;
if (!DoVerifyCertificateChain(certificate_chain, &raw_leaf_public_key,
system_id, oem_ca_serial_number)) {
return false;
}
*leaf_public_key = std::unique_ptr<RsaPublicKey>(raw_leaf_public_key);
return true;
ProvisioningStatus ProcessMessage(const std::string& message,
std::string* response,
bool* done) override {
return INTERNAL_ERROR;
}
};
class ProvisioningSessionImplTest : public ::testing::Test {
protected:
ProvisioningSessionImplTest()
: session_impl_(mock_engine_impl_, mock_oem_device_cert_,
mock_service_private_key_) {
: session_impl_(engine_impl_) {
mock_rsa_key_factory_ = new MockRsaKeyFactory;
session_impl_.set_rsa_key_factory(
std::unique_ptr<RsaKeyFactory>(mock_rsa_key_factory_));
}
ProvisioningSessionImpl session_impl_;
ProvisioningEngineImpl engine_impl_;
FakeProvisioningSessionImpl session_impl_;
MockRsaKeyFactory* mock_rsa_key_factory_ = nullptr;
MockProvisioningEngineImpl mock_engine_impl_;
MockOemDeviceCert mock_oem_device_cert_;
MockRsaPrivateKey mock_service_private_key_;
};
TEST_F(ProvisioningSessionImplTest, InitializeWithInvalidPublicKey) {
@@ -104,7 +58,7 @@ TEST_F(ProvisioningSessionImplTest, InitializeWithInvalidPublicKey) {
CreateFromPkcs1PublicKey(kDevicePublicKey))
.WillOnce(Return(ByMove(nullptr)));
EXPECT_EQ(
INVALID_DEVICE_PUBLIC_KEY,
INVALID_DRM_DEVICE_PUBLIC_KEY,
session_impl_.Initialize(kDevicePublicKey, kDevicePrivateKey));
}
@@ -117,7 +71,7 @@ TEST_F(ProvisioningSessionImplTest, InitializeWithInvalidPrivateKey) {
CreateFromPkcs8PrivateKey(kDevicePrivateKey, IsEmpty()))
.WillOnce(Return(ByMove(nullptr)));
EXPECT_EQ(
INVALID_DEVICE_PRIVATE_KEY,
INVALID_DRM_DEVICE_PRIVATE_KEY,
session_impl_.Initialize(kDevicePublicKey, kDevicePrivateKey));
}
@@ -134,294 +88,9 @@ TEST_F(ProvisioningSessionImplTest, InitializeWithMismatchPublicPrivateKey) {
EXPECT_CALL(*mock_rsa_public_key, MatchesPrivateKey(_))
.WillOnce(Return(false));
EXPECT_EQ(
INVALID_DEVICE_PRIVATE_KEY,
INVALID_DRM_DEVICE_PRIVATE_KEY,
session_impl_.Initialize(kDevicePublicKey, kDevicePrivateKey));
}
class ProvisioningSessionImplProcessTest : public ProvisioningSessionImplTest {
public:
void SetUp() override {
MockRsaPublicKey* mock_rsa_public_key = new MockRsaPublicKey;
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs1PublicKey(kDevicePublicKey))
.WillOnce(
Return(ByMove(std::unique_ptr<RsaPublicKey>(mock_rsa_public_key))));
EXPECT_CALL(*mock_rsa_key_factory_,
CreateFromPkcs8PrivateKey(kDevicePrivateKey, IsEmpty()))
.WillOnce(Return(
ByMove(std::unique_ptr<RsaPrivateKey>(new MockRsaPrivateKey))));
EXPECT_CALL(*mock_rsa_public_key, MatchesPrivateKey(_))
.WillOnce(Return(true));
ASSERT_EQ(OK, session_impl_.Initialize(kDevicePublicKey,
kDevicePrivateKey));
// Setup Provisioning Message.
client_id_.set_type(ClientIdentification::OEM_DEVICE_CERTIFICATE);
client_id_.set_token(kClientToken);
EncryptedClientIdentification* encrypted_client_id =
prov_request_.mutable_encrypted_client_id();
encrypted_client_id->set_encrypted_client_id(crypto_util::EncryptAesCbc(
kPrivacyKey, kEncryptedClientIdIv, client_id_.SerializeAsString()));
encrypted_client_id->set_encrypted_client_id_iv(kEncryptedClientIdIv);
encrypted_client_id->set_encrypted_privacy_key(kEncryptedPrivacyKey);
prov_request_.set_provider_id(kProviderId);
prov_request_.set_nonce(kNonce);
signed_prov_message_.set_message(prov_request_.SerializeAsString());
signed_prov_message_.set_signature("testing_signature");
}
ClientIdentification client_id_;
ProvisioningRequest prov_request_;
SignedProvisioningMessage signed_prov_message_;
};
TEST_F(ProvisioningSessionImplProcessTest, InvalidMessage) {
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage("invalid_message", &response));
}
TEST_F(ProvisioningSessionImplProcessTest, EmptyMessage) {
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage("", &response));
}
TEST_F(ProvisioningSessionImplProcessTest, MissingMessage) {
signed_prov_message_.clear_message();
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, MissingSignature) {
signed_prov_message_.clear_signature();
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, MissingClientId) {
prov_request_.clear_encrypted_client_id();
signed_prov_message_.set_message(prov_request_.SerializeAsString());
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, MissingEncryptedClientId) {
prov_request_.mutable_encrypted_client_id()->clear_encrypted_client_id();
signed_prov_message_.set_message(prov_request_.SerializeAsString());
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, MissingEncryptedClientIdIv) {
prov_request_.mutable_encrypted_client_id()->clear_encrypted_client_id_iv();
signed_prov_message_.set_message(prov_request_.SerializeAsString());
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, MissingEncryptedPrivacyKey) {
prov_request_.mutable_encrypted_client_id()->clear_encrypted_privacy_key();
signed_prov_message_.set_message(prov_request_.SerializeAsString());
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, InvalidNonce) {
// Nonce should be at least 4 buytes.
const char kNonceWithLessThanFourBytes[] = "xx";
prov_request_.set_nonce(kNonceWithLessThanFourBytes);
signed_prov_message_.set_message(prov_request_.SerializeAsString());
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, PrivacyKeyDecryptionFailed) {
EXPECT_CALL(mock_service_private_key_, Decrypt(kEncryptedPrivacyKey, _))
.WillOnce(Return(false));
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, InvalidEncryptedClientId) {
prov_request_.mutable_encrypted_client_id()->set_encrypted_client_id(
"invalid_encrypted_client_id");
signed_prov_message_.set_message(prov_request_.SerializeAsString());
EXPECT_CALL(mock_service_private_key_, Decrypt(kEncryptedPrivacyKey, _))
.WillOnce(DoAll(SetArgPointee<1>(kPrivacyKey), Return(true)));
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, VerifyCertificateChainFailed) {
EXPECT_CALL(mock_service_private_key_, Decrypt(kEncryptedPrivacyKey, _))
.WillOnce(DoAll(SetArgPointee<1>(kPrivacyKey), Return(true)));
EXPECT_CALL(mock_oem_device_cert_,
DoVerifyCertificateChain(kClientToken, _, _, _))
.WillOnce(Return(false));
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest,
ClearClientIdVerifyCertificateChainFailed) {
*prov_request_.mutable_client_id() = client_id_;
prov_request_.clear_encrypted_client_id();
signed_prov_message_.set_message(prov_request_.SerializeAsString());
EXPECT_CALL(mock_oem_device_cert_,
DoVerifyCertificateChain(kClientToken, _, _, _))
.WillOnce(Return(false));
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, ClearClientIdInvalidClientIdType) {
client_id_.set_type(ClientIdentification::KEYBOX);
*prov_request_.mutable_client_id() = client_id_;
prov_request_.clear_encrypted_client_id();
signed_prov_message_.set_message(prov_request_.SerializeAsString());
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, ClearClientIdMissingToken) {
client_id_.clear_token();
*prov_request_.mutable_client_id() = client_id_;
prov_request_.clear_encrypted_client_id();
signed_prov_message_.set_message(prov_request_.SerializeAsString());
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, VerifySignatureFailed) {
EXPECT_CALL(mock_service_private_key_, Decrypt(kEncryptedPrivacyKey, _))
.WillOnce(DoAll(SetArgPointee<1>(kPrivacyKey), Return(true)));
MockRsaPublicKey* mock_cert_public_key = new MockRsaPublicKey;
EXPECT_CALL(mock_oem_device_cert_,
DoVerifyCertificateChain(kClientToken, _, _, _))
.WillOnce(DoAll(SetArgPointee<1>(mock_cert_public_key), Return(true)));
EXPECT_CALL(*mock_cert_public_key,
VerifySignature(signed_prov_message_.message(),
signed_prov_message_.signature()))
.WillOnce(Return(false));
std::string response;
EXPECT_EQ(INVALID_REQUEST_MESSAGE,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, GenerateDeviceCertificateFailed) {
const uint32_t kSystemId = 1234;
const char kExpectedOemSerialNumber[] = "test_oem_serial_number";
EXPECT_CALL(mock_service_private_key_, Decrypt(kEncryptedPrivacyKey, _))
.WillOnce(DoAll(SetArgPointee<1>(kPrivacyKey), Return(true)));
MockRsaPublicKey* mock_cert_public_key = new MockRsaPublicKey;
EXPECT_CALL(mock_oem_device_cert_,
DoVerifyCertificateChain(kClientToken, _, _, _))
.WillOnce(DoAll(
SetArgPointee<1>(mock_cert_public_key), SetArgPointee<2>(kSystemId),
SetArgPointee<3>(kExpectedOemSerialNumber), Return(true)));
EXPECT_CALL(*mock_cert_public_key,
VerifySignature(signed_prov_message_.message(),
signed_prov_message_.signature()))
.WillOnce(Return(true));
EXPECT_CALL(
mock_engine_impl_,
GenerateProviderDeviceDrmCertificate(
kSystemId, kExpectedOemSerialNumber, kProviderId, kDevicePublicKey,
DeriveSpoid(kClientToken, kProviderId, ""), _))
.WillOnce(Return(INTERNAL_ERROR));
std::string response;
EXPECT_EQ(INTERNAL_ERROR,
session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
}
TEST_F(ProvisioningSessionImplProcessTest, Success) {
const uint32_t kSystemId = 1234;
EXPECT_CALL(mock_service_private_key_, Decrypt(kEncryptedPrivacyKey, _))
.WillOnce(DoAll(SetArgPointee<1>(kPrivacyKey), Return(true)));
MockRsaPublicKey* mock_cert_public_key = new MockRsaPublicKey;
EXPECT_CALL(mock_oem_device_cert_,
DoVerifyCertificateChain(kClientToken, _, _, _))
.WillOnce(DoAll(SetArgPointee<1>(mock_cert_public_key),
SetArgPointee<2>(kSystemId), Return(true)));
EXPECT_CALL(*mock_cert_public_key,
VerifySignature(signed_prov_message_.message(),
signed_prov_message_.signature()))
.WillOnce(Return(true));
EXPECT_CALL(mock_engine_impl_,
GenerateProviderDeviceDrmCertificate(kSystemId, _, _,
kDevicePublicKey, _, _))
.WillOnce(DoAll(SetArgPointee<5>(kDeviceCertificate), Return(OK)));
std::string message_key;
EXPECT_CALL(*mock_cert_public_key, Encrypt(_, _))
.WillOnce(DoAll(SaveArg<0>(&message_key),
SetArgPointee<1>(kWrappingKey), Return(true)));
std::string message;
EXPECT_CALL(mock_service_private_key_, GenerateSignature(_, _))
.WillOnce(DoAll(SaveArg<0>(&message),
SetArgPointee<1>(kSignature), Return(true)));
std::string response;
ASSERT_EQ(OK, session_impl_.ProcessMessage(
signed_prov_message_.SerializeAsString(), &response));
// Verify the response.
SignedProvisioningMessage signed_prov_message;
ASSERT_TRUE(signed_prov_message.ParseFromString(response));
EXPECT_EQ(message, signed_prov_message.message());
EXPECT_EQ(kSignature, signed_prov_message.signature());
ProvisioningResponse prov_response;
ASSERT_TRUE(prov_response.ParseFromString(message));
EXPECT_EQ(
kDevicePrivateKey,
crypto_util::DecryptAesCbc(message_key, prov_response.device_rsa_key_iv(),
prov_response.device_rsa_key()));
EXPECT_EQ(kDeviceCertificate, prov_response.device_certificate());
EXPECT_EQ(kNonce, prov_response.nonce());
EXPECT_EQ(kWrappingKey, prov_response.wrapping_key());
}
} // namespace widevine

View File

@@ -1,5 +1,5 @@
################################################################################
# Copyright 2016 Google Inc.
# 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
@@ -33,7 +33,11 @@ cc_library(
name = "libprovisioning_sdk",
srcs = [":libprovisioning_sdk.so"],
hdrs = glob(["*.h"]),
deps = ["//base"],
deps = [
"//base",
"//common:certificate_type",
"//protos/public:certificate_provisioning_proto",
],
)
cc_library(
@@ -42,13 +46,17 @@ cc_library(
hdrs = ["provisioning_engine.h"],
copts = PUBLIC_COPTS,
deps = [
":certificate_type",
":provisioning_session",
":provisioning_status",
"//base",
"@abseil_repo//absl/memory",
"//common:certificate_type",
"//common:drm_service_certificate",
"//common:rsa_key",
"//provisioning_sdk/internal:provisioning30_session_impl",
"//provisioning_sdk/internal:provisioning_engine_impl",
"//provisioning_sdk/internal:provisioning_session_impl",
"//protos/public:certificate_provisioning_proto",
],
)
@@ -58,7 +66,7 @@ cc_test(
srcs = ["provisioning_engine_test.cc"],
deps = [
":provisioning_engine",
"//external:gtest_main",
"//testing:gunit_main",
],
)
@@ -71,7 +79,7 @@ cc_library(
":provisioning_status",
"//base",
"//provisioning_sdk/internal:provisioning_session_impl",
"//protos/public:device_certificate_proto",
"//protos/public:drm_certificate_proto",
],
)
@@ -82,9 +90,3 @@ cc_library(
copts = PUBLIC_COPTS,
deps = ["//base"],
)
cc_library(
name = "certificate_type",
hdrs = ["certificate_type.h"],
copts = PUBLIC_COPTS,
)

View File

@@ -1,22 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// 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_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_

View File

@@ -1,5 +1,5 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
// 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
@@ -11,7 +11,11 @@
#include <utility>
#include "glog/logging.h"
#include "absl/memory/memory.h"
#include "common/certificate_type.h"
#include "common/drm_service_certificate.h"
#include "common/rsa_key.h"
#include "provisioning_sdk/internal/provisioning30_session_impl.h"
#include "provisioning_sdk/internal/provisioning_engine_impl.h"
#include "provisioning_sdk/internal/provisioning_session_impl.h"
#include "provisioning_sdk/public/provisioning_session.h"
@@ -36,16 +40,35 @@ ProvisioningStatus ProvisioningEngine::Initialize(
}
std::unique_ptr<ProvisioningEngineImpl> impl(new ProvisioningEngineImpl);
ProvisioningStatus status = impl->Initialize(
certificate_type, service_drm_certificate, service_private_key,
service_private_key_passphrase, provisioning_drm_certificate,
provisioning_private_key, provisioning_private_key_passphrase,
secret_spoid_sauce);
ProvisioningStatus status =
impl->Initialize(certificate_type, service_drm_certificate,
service_private_key, service_private_key_passphrase,
provisioning_drm_certificate, provisioning_private_key,
provisioning_private_key_passphrase, secret_spoid_sauce);
if (status != OK) return status;
impl_ = std::move(impl);
// Register Provisioning 3.0 session factory.
RegisterProtocol(
SignedProvisioningMessage::PROVISIONING_30,
[](const ProvisioningEngineImpl& engine,
std::unique_ptr<ProvisioningSessionImpl>* new_session) {
*new_session = absl::make_unique<Provisioning30SessionImpl>(
engine, engine.oem_device_cert(),
*DrmServiceCertificate::GetDefaultDrmServiceCertificateOrDie()
->private_key());
return OK;
});
return OK;
}
void ProvisioningEngine::RegisterProtocol(
SignedProvisioningMessage::ProtocolVersion protocol,
SessionFactory session_factory) {
protocol_registry_[protocol] = std::move(session_factory);
}
ProvisioningStatus ProvisioningEngine::SetCertificateStatusList(
const std::string& certificate_status_list, uint32_t expiration_period_seconds) {
if (!impl_) return PROVISIONING_ENGINE_UNINITIALIZED;
@@ -74,6 +97,7 @@ ProvisioningStatus ProvisioningEngine::AddDrmIntermediateCertificate(
}
ProvisioningStatus ProvisioningEngine::NewProvisioningSession(
SignedProvisioningMessage::ProtocolVersion protocol,
const std::string& device_public_key, const std::string& device_private_key,
std::unique_ptr<ProvisioningSession>* new_session) const {
if (!impl_) return PROVISIONING_ENGINE_UNINITIALIZED;
@@ -82,12 +106,56 @@ ProvisioningStatus ProvisioningEngine::NewProvisioningSession(
return INTERNAL_ERROR;
}
std::unique_ptr<ProvisioningSessionImpl> session_impl(
new ProvisioningSessionImpl(*impl_, impl_->oem_device_cert(),
*impl_->service_private_key()));
ProvisioningStatus status =
session_impl->Initialize(device_public_key, device_private_key);
auto factory = protocol_registry_.find(protocol);
if (factory == protocol_registry_.end()) {
LOG(WARNING) << "Provisioning protocol not supported (" << protocol << ")";
return INVALID_PROTOCOL;
}
std::unique_ptr<ProvisioningSessionImpl> session_impl;
ProvisioningStatus status = (factory->second)(*impl_, &session_impl);
if (status != OK) return status;
status = session_impl->Initialize(device_public_key, device_private_key);
if (status != OK) return status;
*new_session = std::unique_ptr<ProvisioningSession>(
new ProvisioningSession(std::move(session_impl)));
return OK;
}
std::unique_ptr<ProvisioningSession> ProvisioningEngine::NewProvisioningSession(
SignedProvisioningMessage::ProtocolVersion protocol,
const std::string& device_public_key, const std::string& device_private_key,
ProvisioningStatus* status) const {
std::unique_ptr<ProvisioningSession> new_session;
*status = NewProvisioningSession(protocol, device_public_key,
device_private_key, &new_session);
return new_session;
}
ProvisioningStatus ProvisioningEngine::NewKeyboxProvisioningSession(
const std::string& keybox_device_key,
std::unique_ptr<ProvisioningSession>* new_session) const {
if (!impl_) return PROVISIONING_ENGINE_UNINITIALIZED;
if (!new_session) {
LOG(WARNING) << "|new_session| should not be a nullptr.";
return INTERNAL_ERROR;
}
SignedProvisioningMessage::ProtocolVersion protocol =
SignedProvisioningMessage::ARCPP_PROVISIONING;
auto factory = protocol_registry_.find(protocol);
if (factory == protocol_registry_.end()) {
LOG(WARNING) << "Provisioning protocol not supported (" << protocol << ")";
return INVALID_PROTOCOL;
}
std::unique_ptr<ProvisioningSessionImpl> session_impl;
ProvisioningStatus status = (factory->second)(*impl_, &session_impl);
if (status != OK) return status;
status = session_impl->Initialize(keybox_device_key);
if (status != OK) return status;
new_session->reset(new ProvisioningSession(std::move(session_impl)));
return OK;
}
@@ -106,7 +174,7 @@ ProvisioningStatus ProvisioningEngine::GenerateDeviceDrmCertificate(
// function which expect the input to be already validated.
std::unique_ptr<RsaPublicKey> rsa_public_key(
RsaPublicKey::Create(public_key));
if (!rsa_public_key) return INVALID_DEVICE_PUBLIC_KEY;
if (!rsa_public_key) return INVALID_DRM_DEVICE_PUBLIC_KEY;
if (serial_number.empty()) return INVALID_SERIAL_NUMBER;
const std::string empty_oem_ca_serial_number;

View File

@@ -1,5 +1,5 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
// 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
@@ -10,16 +10,31 @@
#define PROVISIONING_SDK_PUBLIC_PROVISIONING_ENGINE_H_
#include <cstdint>
#include <functional>
#include <map>
#include <memory>
#include <string>
#include "provisioning_sdk/public/certificate_type.h"
#include "common/certificate_type.h"
#include "provisioning_sdk/public/provisioning_status.h"
#include "protos/public/certificate_provisioning.pb.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
@@ -50,8 +65,7 @@ class ProvisioningEngine {
// 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,
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,
@@ -59,6 +73,14 @@ class ProvisioningEngine {
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(SignedProvisioningMessage::ProtocolVersion 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.
@@ -67,8 +89,7 @@ class ProvisioningEngine {
// (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);
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.
@@ -82,9 +103,7 @@ class ProvisioningEngine {
// 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;
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.
@@ -95,12 +114,13 @@ class ProvisioningEngine {
// 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& 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.
// 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.
@@ -114,8 +134,28 @@ class ProvisioningEngine {
// 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,
SignedProvisioningMessage::ProtocolVersion protocol,
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(
SignedProvisioningMessage::ProtocolVersion protocol,
const std::string& device_public_key, const std::string& device_private_key,
ProvisioningStatus* status) const;
// Create a session to handle a keybox provisioning exchange between
// a client device (e.g., ChromeOS) and the provisioning server.
// It would use ARCPP_PROVISIONING protocol.
// * |keybox_device_key| is the secret device key in the keybox.
// * |new_session| will point, on successful return, to the newly created
// ProvisioningSession.
// * Returns OK if successful, or an appropriate error status code otherwise.
// NOTE: All ProvisioningSession objects must be deleted before the
// ProvisioningEngine which created them.
virtual ProvisioningStatus NewKeyboxProvisioningSession(
const std::string& keybox_device_key,
std::unique_ptr<ProvisioningSession>* new_session) const;
// Generate a new device DRM certificate to be provisioned by means other than
@@ -133,13 +173,15 @@ class ProvisioningEngine {
// * |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;
ProvisioningStatus GenerateDeviceDrmCertificate(uint32_t system_id,
const std::string& public_key,
const std::string& serial_number,
std::string* certificate) const;
private:
std::map<SignedProvisioningMessage::ProtocolVersion, SessionFactory>
protocol_registry_;
#ifndef SWIGPYTHON
ProvisioningEngine(const ProvisioningEngine&) = delete;
ProvisioningEngine& operator=(const ProvisioningEngine&) = delete;

View File

@@ -1,5 +1,5 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
// 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
@@ -8,7 +8,7 @@
#include "provisioning_sdk/public/provisioning_engine.h"
#include "gtest/gtest.h"
#include "testing/gunit.h"
namespace {
const int kSystemId = 100;

View File

@@ -1,5 +1,5 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
// 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
@@ -12,10 +12,16 @@
#include "glog/logging.h"
#include "provisioning_sdk/internal/provisioning_session_impl.h"
#include "protos/public/device_certificate.pb.h"
#include "protos/public/drm_certificate.pb.h"
namespace widevine {
ProvisioningSession::ProvisioningSession(
std::unique_ptr<ProvisioningSessionImpl> impl)
: impl_(std::move(impl)) {
DCHECK(impl_);
}
ProvisioningSession::ProvisioningSession() {}
ProvisioningSession::~ProvisioningSession() {}
@@ -32,8 +38,7 @@ ProvisioningStatus ProvisioningSession::ProcessMessage(const std::string& messag
return INTERNAL_ERROR;
}
ProvisioningStatus status = impl_->ProcessMessage(message, response);
*done = true;
ProvisioningStatus status = impl_->ProcessMessage(message, response, done);
return status;
}
@@ -41,10 +46,4 @@ const ProvisionedDeviceInfo* ProvisioningSession::GetDeviceInfo() const {
return impl_->GetDeviceInfo();
}
ProvisioningSession::ProvisioningSession(
std::unique_ptr<ProvisioningSessionImpl> impl)
: impl_(std::move(impl)) {
DCHECK(impl_);
}
} // namespace widevine

View File

@@ -1,5 +1,5 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
// 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
@@ -29,7 +29,7 @@ class ProvisioningSession {
// * |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.
// exchange is complete.
// Returns OK if successful, or an appropriate error status code otherwise.
virtual ProvisioningStatus ProcessMessage(const std::string& message,
std::string* response,
@@ -49,6 +49,7 @@ class ProvisioningSession {
ProvisioningSession(const ProvisioningSession&) = delete;
ProvisioningSession& operator=(const ProvisioningSession&) = delete;
#endif
explicit ProvisioningSession(std::unique_ptr<ProvisioningSessionImpl> impl);
std::unique_ptr<ProvisioningSessionImpl> impl_;

View File

@@ -1,5 +1,5 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
// 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
@@ -26,8 +26,8 @@ static const char* kProvisioningStatusMessage[] = {
"Invalid status list",
"Status list expired",
"Unknown system id",
"Invalid device public key",
"Invalid device private key",
"Invalid DRM device public key",
"Invalid DRM device private key",
"Invalid request message",
"Invalid MAC",
"Missing DRM intermediate certificate",
@@ -35,10 +35,19 @@ static const char* kProvisioningStatusMessage[] = {
"Device revoked",
"Invalid serial number",
"Internal error",
"Invalid SPOID secret sauce"
"Invalid SPOID secret sauce",
"Unsupported provisioning protocol",
"Invalid context key data",
"Provisioning context verification failed",
"Protocol error",
"Invalid keybox device key",
"Invalid session keys",
"Invalid pre-provisioning key",
"Missing pre-provisioning key",
"Remote attestation verification failure",
};
const char* GetProvisioningStatusMessage(ProvisioningStatus status) {
std::string GetProvisioningStatusMessage(ProvisioningStatus status) {
static_assert(
arraysize(kProvisioningStatusMessage) == NUM_PROVISIONING_STATUS,
"mismatching provisioning status message and provisioning status.");

View File

@@ -1,5 +1,5 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
// 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
@@ -9,6 +9,8 @@
#ifndef PROVISIONING_SDK_PUBLIC_PROVISIONING_STATUS_H_
#define PROVISIONING_SDK_PUBLIC_PROVISIONING_STATUS_H_
#include <string>
namespace widevine {
enum ProvisioningStatus {
@@ -16,8 +18,6 @@ enum ProvisioningStatus {
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_PROVISIONER_DRM_CERTIFICATE = 5,
// Invalid provisioner private key or private key passphrase.
INVALID_PROVISIONER_PRIVATE_KEY = 6,
@@ -28,21 +28,30 @@ enum ProvisioningStatus {
INVALID_STATUS_LIST = 10,
STATUS_LIST_EXPIRED = 11,
UNKNOWN_SYSTEM_ID = 12,
INVALID_DEVICE_PUBLIC_KEY = 13,
INVALID_DEVICE_PRIVATE_KEY = 14,
INVALID_DRM_DEVICE_PUBLIC_KEY = 13,
INVALID_DRM_DEVICE_PRIVATE_KEY = 14,
INVALID_REQUEST_MESSAGE = 15,
INVALID_MAC = 16,
MISSING_DRM_INTERMEDIATE_CERT = 17,
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.
const char* GetProvisioningStatusMessage(ProvisioningStatus status);
std::string GetProvisioningStatusMessage(ProvisioningStatus status);
} // namespace widevine

View File

@@ -1,5 +1,5 @@
################################################################################
# Copyright 2016 Google Inc.
# 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
@@ -69,7 +69,7 @@ py_test(
deps = [
":crypto_utility",
":test_data_utility",
"//protos/public:signed_device_certificate_py_pb2",
"//protos/public:signed_drm_certificate_py_pb2",
],
)
@@ -81,6 +81,6 @@ py_test(
":crypto_utility",
":test_data_utility",
"//protos/public:certificate_provisioning_py_pb2",
"//protos/public:signed_device_certificate_py_pb2",
"//protos/public:signed_drm_certificate_py_pb2",
],
)

View File

@@ -1,27 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// 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 "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_t);
COPY_TYPEMAPS(unsigned int, uint32_t);

View File

@@ -1,28 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// 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.
////////////////////////////////////////////////////////////////////////////////
// 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::kCertTesting;
%unignore widevine::kCertDevelopment;
%include "provisioning_sdk/public/certificate_type.h"
%unignoreall

View File

@@ -0,0 +1,36 @@
################################################################################
# Copyright 2018 Google LLC.
#
# This software is licensed under the terms defined in the Widevine Master
# License Agreement. For a copy of this agreement, please contact
# widevine-licensing@google.com.
################################################################################
"""Installation file for the certificate_type module."""
import setup_common as common
import setuptools
if __name__ == '__main__':
setuptools.setup(
name='certificate_type',
ext_modules=[
setuptools.Extension(
name='certificate_type',
sources=[
'%s/certificate_type.cc' % common.WVCOMMON_SRC_DIR,
'%s/initcertificate_type.cc' % common.WVCOMMON_SRC_DIR,
'%s/clif/python/runtime.cc' % common.CLIF_PREFIX,
'%s/clif/python/slots.cc' % common.CLIF_PREFIX,
'%s/clif/python/types.cc' % common.CLIF_PREFIX,
],
include_dirs=[
common.SDK_ROOT_DIR, common.GEN_DIR, common.CLIF_PREFIX, '/'
],
extra_compile_args=['-std=c++11'],
library_dirs=[common.SDK_LIBRARY_DIR],
libraries=['provisioning_sdk'],
runtime_library_dirs=[common.SDK_LIBRARY_DIR],
install_requires=['enum34;python_version<"3.4"'],
),
],
)

View File

@@ -1,11 +1,10 @@
################################################################################
# Copyright 2016 Google Inc.
# 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

View File

@@ -1,5 +1,5 @@
################################################################################
# Copyright 2016 Google Inc.
# 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
@@ -8,15 +8,15 @@
import unittest
import pywrapprovisioning_engine
import pywrapprovisioning_status
import test_data_utility
from provisioning_engine import ProvisioningEngine
from provisioning_status import ProvisioningStatus
class AddDrmIntermediateTest(unittest.TestCase):
def setUp(self):
self._engine = pywrapprovisioning_engine.ProvisioningEngine()
self._engine = ProvisioningEngine()
test_data_utility.InitProvisionEngineWithTestData(
self._engine, verify_success=True)
@@ -30,7 +30,7 @@ class AddDrmIntermediateTest(unittest.TestCase):
def testSetCertificateStatusListInvalid(self):
set_cert_status_list = self._engine.SetCertificateStatusList(
'INVALID_STATUS_LIST', 0)
self.assertEqual(pywrapprovisioning_status.INVALID_STATUS_LIST,
self.assertEqual(ProvisioningStatus.INVALID_STATUS_LIST,
set_cert_status_list)
def testAddDrmIntermediateCertificateWithoutCertificateStatusList(self):
@@ -38,7 +38,7 @@ class AddDrmIntermediateTest(unittest.TestCase):
# certificate status list.
status = test_data_utility.AddDrmIntermediateCertificateWithTestData(
self._engine, 2001)
self.assertEqual(pywrapprovisioning_status.STATUS_LIST_EXPIRED, status)
self.assertEqual(ProvisioningStatus.STATUS_LIST_EXPIRED, status)
def testAddDrmIntermediateCertificateSystemIdInvalid(self):
test_data_utility.SetCertificateStatusListWithTestData(
@@ -47,7 +47,7 @@ class AddDrmIntermediateTest(unittest.TestCase):
# 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)
self.assertEqual(ProvisioningStatus.UNKNOWN_SYSTEM_ID, add_ca_status)
if __name__ == '__main__':

View File

@@ -1,5 +1,5 @@
################################################################################
# Copyright 2016 Google Inc.
# 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
@@ -8,19 +8,19 @@
import unittest
from certificate_type import CertificateType
import crypto_utility
import pywrapcertificate_type
import pywrapprovisioning_engine
import pywrapprovisioning_status
import test_data_provider
import test_data_utility
from protos.public import signed_device_certificate_pb2
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 = pywrapprovisioning_engine.ProvisioningEngine()
self._engine = ProvisioningEngine()
test_data_utility.InitProvisionEngineWithTestData(
self._engine, verify_success=True)
test_data_utility.SetCertificateStatusListWithTestData(
@@ -28,14 +28,14 @@ class EngineGenerateCertificateTest(unittest.TestCase):
test_data_utility.AddDrmIntermediateCertificateWithTestData(
self._engine, 2001, verify_success=True)
self._data_provider = test_data_provider.TestDataProvider(
pywrapcertificate_type.kCertTesting)
CertificateType.kCertificateTypeTesting)
def testSuccess(self):
status, signed_cert_string = self._engine.GenerateDeviceDrmCertificate(
2001, self._data_provider.device_public_key, 'DEVICE_SERIAL_NUMBER')
self.assertEqual(pywrapprovisioning_status.OK, status)
self.assertEqual(ProvisioningStatus.OK, status)
signed_cert = signed_device_certificate_pb2.SignedDrmDeviceCertificate()
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,
@@ -44,25 +44,24 @@ class EngineGenerateCertificateTest(unittest.TestCase):
def testEmptySerialNumber(self):
status, _ = self._engine.GenerateDeviceDrmCertificate(
2001, self._data_provider.device_public_key, '')
self.assertEqual(pywrapprovisioning_status.INVALID_SERIAL_NUMBER, status)
self.assertEqual(ProvisioningStatus.INVALID_SERIAL_NUMBER, status)
def testEmptyPublicKey(self):
status, _ = self._engine.GenerateDeviceDrmCertificate(
2001, '', 'DEVICE_SERIAL_NUMBER')
self.assertEqual(pywrapprovisioning_status.INVALID_DEVICE_PUBLIC_KEY,
status)
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(pywrapprovisioning_status.INVALID_DEVICE_PUBLIC_KEY,
status)
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(pywrapprovisioning_status.DEVICE_REVOKED, status)
self.assertEqual(ProvisioningStatus.UNKNOWN_SYSTEM_ID, status)
if __name__ == '__main__':
unittest.main()

View File

@@ -1,5 +1,5 @@
################################################################################
# Copyright 2016 Google Inc.
# 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
@@ -8,83 +8,85 @@
import unittest
import pywrapcertificate_type
import pywrapprovisioning_engine
import pywrapprovisioning_status
from certificate_type import CertificateType
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
class InitEngineTest(unittest.TestCase):
def setUp(self):
self._engine = pywrapprovisioning_engine.ProvisioningEngine()
self._engine = ProvisioningEngine()
self._data_provider = test_data_provider.TestDataProvider(
pywrapcertificate_type.kCertTesting)
CertificateType.kCertificateTypeTesting)
self._prov30 = (
certificate_provisioning_pb2.SignedProvisioningMessage.PROVISIONING_30)
def testInitEngineSucceed(self):
test_data_utility.InitProvisionEngineWithTestData(
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(
pywrapprovisioning_status.PROVISIONING_ENGINE_UNINITIALIZED, status)
self.assertEqual(ProvisioningStatus.PROVISIONING_ENGINE_UNINITIALIZED,
status)
def testGenerateDrmIntermediateCertificateWithoutInit(self):
status, _ = self._engine.GenerateDrmIntermediateCertificate(
100, 'INTERMEDIATE_PUBLIC_KEY')
self.assertEqual(
pywrapprovisioning_status.PROVISIONING_ENGINE_UNINITIALIZED, status)
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(
pywrapprovisioning_status.PROVISIONING_ENGINE_UNINITIALIZED, status)
self.assertEqual(ProvisioningStatus.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)
self.assertEqual(ProvisioningStatus.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)
session, status = self._engine.NewProvisioningSession(
self._prov30, 'DEVICE_PUBLIC_KEY', 'DEVICE_PRIVATE_KEY')
self.assertEqual(ProvisioningStatus.PROVISIONING_ENGINE_UNINITIALIZED,
status)
self.assertIsNone(session)
def testInitEngineInvalidServiceDrmCert(self):
status = self._engine.Initialize(
pywrapcertificate_type.kCertTesting, 'INVALID_CERT',
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(pywrapprovisioning_status.INVALID_SERVICE_DRM_CERTIFICATE,
status)
self.assertEqual(ProvisioningStatus.INVALID_SERVICE_DRM_CERTIFICATE, status)
def testInitEngineInvalidServicePrivateKey(self):
status = self._engine.Initialize(
pywrapcertificate_type.kCertTesting,
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(pywrapprovisioning_status.INVALID_SERVICE_PRIVATE_KEY,
status)
self.assertEqual(ProvisioningStatus.INVALID_SERVICE_DRM_CERTIFICATE, status)
def testInitEngineWrongServicePrivateKey(self):
status = self._engine.Initialize(
pywrapcertificate_type.kCertTesting,
CertificateType.kCertificateTypeTesting,
self._data_provider.service_drm_cert,
self._data_provider.provisioner_private_key,
self._data_provider.service_private_key_passphrase,
@@ -92,48 +94,45 @@ class InitEngineTest(unittest.TestCase):
self._data_provider.provisioner_private_key,
self._data_provider.provisioner_private_key_passphrase,
self._data_provider.provisioner_spoid_secret)
self.assertEqual(pywrapprovisioning_status.INVALID_SERVICE_PRIVATE_KEY,
status)
self.assertEqual(ProvisioningStatus.INVALID_SERVICE_DRM_CERTIFICATE, status)
def testInitEngineInvalidServicePrivateKeyPassphrase(self):
status = self._engine.Initialize(
pywrapcertificate_type.kCertTesting,
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(pywrapprovisioning_status.INVALID_SERVICE_PRIVATE_KEY,
status)
self.assertEqual(ProvisioningStatus.INVALID_SERVICE_DRM_CERTIFICATE, status)
def testInitEngineInvalidDrmCert(self):
status = self._engine.Initialize(
pywrapcertificate_type.kCertTesting,
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(
pywrapprovisioning_status.INVALID_PROVISIONER_DRM_CERTIFICATE, status)
self.assertEqual(ProvisioningStatus.INVALID_PROVISIONER_DRM_CERTIFICATE,
status)
def testInitEngineInvalidDrmPrivateKey(self):
status = self._engine.Initialize(
pywrapcertificate_type.kCertTesting,
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(pywrapprovisioning_status.INVALID_PROVISIONER_PRIVATE_KEY,
status)
self.assertEqual(ProvisioningStatus.INVALID_PROVISIONER_PRIVATE_KEY, status)
def testInitEngineWrongDrmPrivateKey(self):
status = self._engine.Initialize(
pywrapcertificate_type.kCertTesting,
CertificateType.kCertificateTypeTesting,
self._data_provider.service_drm_cert,
self._data_provider.service_private_key,
self._data_provider.service_private_key_passphrase,
@@ -141,32 +140,30 @@ class InitEngineTest(unittest.TestCase):
self._data_provider.service_private_key,
self._data_provider.provisioner_private_key_passphrase,
self._data_provider.provisioner_spoid_secret)
self.assertEqual(pywrapprovisioning_status.INVALID_PROVISIONER_PRIVATE_KEY,
status)
self.assertEqual(ProvisioningStatus.INVALID_PROVISIONER_PRIVATE_KEY, status)
def testInitEngineInvalidDrmPrivateKeyPassphrase(self):
status = self._engine.Initialize(
pywrapcertificate_type.kCertTesting,
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(pywrapprovisioning_status.INVALID_PROVISIONER_PRIVATE_KEY,
status)
'INVALID_PASSPHRASE', self._data_provider.provisioner_spoid_secret)
self.assertEqual(ProvisioningStatus.INVALID_PROVISIONER_PRIVATE_KEY, status)
def testInitEngineInvalidSpoidSecret(self):
status = self._engine.Initialize(
pywrapcertificate_type.kCertTesting,
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(pywrapprovisioning_status.INVALID_SPOID_SAUCE, status)
self.assertEqual(ProvisioningStatus.INVALID_SPOID_SAUCE, status)
if __name__ == '__main__':
unittest.main()

View File

@@ -1,5 +1,5 @@
################################################################################
# Copyright 2016 Google Inc.
# 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
@@ -8,36 +8,38 @@
import unittest
from certificate_type import CertificateType
import crypto_utility
import pywrapcertificate_type
import pywrapprovisioning_engine
import pywrapprovisioning_status
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_device_certificate_pb2
from protos.public import signed_drm_certificate_pb2
class NewSessionTest(unittest.TestCase):
def setUp(self):
self._engine = pywrapprovisioning_engine.ProvisioningEngine()
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(
pywrapcertificate_type.kCertTesting)
CertificateType.kCertificateTypeTesting)
self._prov30 = (
certificate_provisioning_pb2.SignedProvisioningMessage.PROVISIONING_30)
def testNewSessionSuccess(self):
test_data_utility.AddDrmIntermediateCertificateWithTestData(
self._engine, 2001, verify_success=True)
(_, new_session) = test_data_utility.NewProvisioningSessionWithTestData(
(new_session, _) = test_data_utility.NewProvisioningSessionWithTestData(
self._engine, verify_success=True)
(status, raw_response,
_) = new_session.ProcessMessage(self._data_provider.message)
test_data_utility.AssertSuccess(status, 'Failed to create session.')
(status, raw_response, _) = new_session.ProcessMessage(
self._data_provider.message)
assert ProvisioningStatus.OK == status
signed_request = test_data_utility.ConvertToSignedProvisioningMessage(
self._data_provider.message)
@@ -59,35 +61,44 @@ class NewSessionTest(unittest.TestCase):
def testProcessInvalidMessage(self):
test_data_utility.AddDrmIntermediateCertificateWithTestData(
self._engine, 2001, verify_success=True)
(_, new_session
) = test_data_utility.NewProvisioningSessionWithTestData(self._engine)
(new_session, _) = test_data_utility.NewProvisioningSessionWithTestData(
self._engine)
(status, _, _) = new_session.ProcessMessage('INVALID_MESSAGE')
self.assertEqual(pywrapprovisioning_status.INVALID_REQUEST_MESSAGE, status)
self.assertEqual(ProvisioningStatus.INVALID_REQUEST_MESSAGE, status)
def testNewSessionWithoutIntermediateCert(self):
(_, new_session) = test_data_utility.NewProvisioningSessionWithTestData(
(new_session, _) = test_data_utility.NewProvisioningSessionWithTestData(
self._engine, verify_success=True)
(status, _, _) = new_session.ProcessMessage(
self._data_provider.message)
self.assertEqual(pywrapprovisioning_status.MISSING_DRM_INTERMEDIATE_CERT,
(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(pywrapprovisioning_status.INVALID_DEVICE_PUBLIC_KEY,
(_, session_status) = self._engine.NewProvisioningSession(
self._prov30, '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(pywrapprovisioning_status.INVALID_DEVICE_PRIVATE_KEY,
(_, session_status) = self._engine.NewProvisioningSession(
self._prov30, self._data_provider.device_public_key,
'INVALID_PRIVATE_KEY')
self.assertEqual(ProvisioningStatus.INVALID_DRM_DEVICE_PRIVATE_KEY,
session_status)
def testNewSessionInvalidProtocol(self):
test_data_utility.AddDrmIntermediateCertificateWithTestData(
self._engine, 2001, verify_success=True)
(_, session_status) = self._engine.NewProvisioningSession(
1234, self._data_provider.device_public_key,
self._data_provider.device_private_key)
self.assertEqual(ProvisioningStatus.INVALID_PROTOCOL, session_status)
def _VerifyMessageSignature(self, public_key, signed_response):
crypto_utility.VerifySignature(public_key, signed_response.signature,
signed_response.message)
@@ -99,11 +110,11 @@ class NewSessionTest(unittest.TestCase):
def _VerifyProvisioningResponse(self, request, response):
self.assertEqual(request.nonce, response.nonce)
signed_cert = signed_device_certificate_pb2.SignedDrmDeviceCertificate()
signed_cert = signed_drm_certificate_pb2.SignedDrmCertificate()
signed_cert.ParseFromString(response.device_certificate)
self._VerifyCertSignature(self._data_provider.ca_public_key,
signed_cert)
self._VerifyCertSignature(self._data_provider.ca_public_key, signed_cert)
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,46 @@
################################################################################
# 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 "protos/public/certificate_provisioning_pyclif.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,
protocol: SignedProvisioningMessage.ProtocolVersion,
device_public_key: bytes,
device_private_key: bytes) -> (new_session: ProvisioningSession,
status: ProvisioningStatus)
def GenerateDeviceDrmCertificate(self,
system_id: int,
public_key: bytes,
serial_number: bytes) -> (status: ProvisioningStatus,
certificate: bytes)

View File

@@ -1,46 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// 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.
////////////////////////////////////////////////////////////////////////////////
// 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 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

View File

@@ -0,0 +1,47 @@
################################################################################
# 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,
'%s/certificate_provisioning_pyclif.cc' %
common.WVPROTO_SRC_DIR,
],
include_dirs=[
common.SDK_ROOT_DIR, common.GEN_DIR, common.CLIF_PREFIX, '/'
],
extra_compile_args=['-std=c++11'],
library_dirs=[common.SDK_LIBRARY_DIR],
libraries=['provisioning_sdk', 'protobuf'],
runtime_library_dirs=[common.SDK_LIBRARY_DIR],
install_requires=['enum34;python_version<"3.4"'],
extra_objects=[
certificate_type.__file__,
provisioning_status.__file__,
provisioning_session.__file__,
],
),
],
)

View File

@@ -0,0 +1,16 @@
################################################################################
# Copyright 2018 Google LLC.
#
# This software is licensed under the terms defined in the Widevine Master
# License Agreement. For a copy of this agreement, please contact
# widevine-licensing@google.com.
################################################################################
from "provisioning_sdk/public/python/provisioning_status.h" import *
from "provisioning_sdk/public/provisioning_session.h":
namespace `widevine`:
class ProvisioningSession:
def ProcessMessage(self, message: bytes) -> (status: ProvisioningStatus,
response: bytes,
done: bool)

View File

@@ -1,37 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// 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.
////////////////////////////////////////////////////////////////////////////////
// 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

View File

@@ -0,0 +1,38 @@
################################################################################
# Copyright 2018 Google LLC.
#
# This software is licensed under the terms defined in the Widevine Master
# License Agreement. For a copy of this agreement, please contact
# widevine-licensing@google.com.
################################################################################
"""Installation file for the provisioning_session module."""
import provisioning_status
import setup_common as common
import setuptools
if __name__ == '__main__':
setuptools.setup(
name='provisioning_session',
ext_modules=[
setuptools.Extension(
name='provisioning_session',
sources=[
'%s/provisioning_session.cc' % common.SDK_SRC_DIR,
'%s/initprovisioning_session.cc' % common.SDK_SRC_DIR,
'%s/clif/python/runtime.cc' % common.CLIF_PREFIX,
'%s/clif/python/slots.cc' % common.CLIF_PREFIX,
'%s/clif/python/types.cc' % common.CLIF_PREFIX,
],
include_dirs=[
common.SDK_ROOT_DIR, common.GEN_DIR, common.CLIF_PREFIX, '/'
],
extra_compile_args=['-std=c++11'],
library_dirs=[common.SDK_LIBRARY_DIR],
libraries=['provisioning_sdk'],
runtime_library_dirs=[common.SDK_LIBRARY_DIR],
install_requires=['enum34;python_version<"3.4"'],
extra_objects=[provisioning_status.__file__],
),
],
)

View File

@@ -0,0 +1,12 @@
################################################################################
# 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
def GetProvisioningStatusMessage(status: ProvisioningStatus) -> str

View File

@@ -1,44 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// 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.
////////////////////////////////////////////////////////////////////////////////
// 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_PROVISIONER_DRM_CERTIFICATE;
%unignore widevine::INVALID_PROVISIONER_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::INVALID_SERIAL_NUMBER;
%unignore widevine::INVALID_SPOID_SAUCE;
%unignore widevine::GetProvisioningStatusMessage;
%include "provisioning_sdk/public/provisioning_status.h"
%unignoreall

View File

@@ -0,0 +1,36 @@
################################################################################
# Copyright 2018 Google LLC.
#
# This software is licensed under the terms defined in the Widevine Master
# License Agreement. For a copy of this agreement, please contact
# widevine-licensing@google.com.
################################################################################
"""Installation file for the provisioning_status module."""
import setup_common as common
import setuptools
if __name__ == '__main__':
setuptools.setup(
name='provisioning_status',
ext_modules=[
setuptools.Extension(
name='provisioning_status',
sources=[
'%s/provisioning_status.cc' % common.SDK_SRC_DIR,
'%s/initprovisioning_status.cc' % common.SDK_SRC_DIR,
'%s/clif/python/runtime.cc' % common.CLIF_PREFIX,
'%s/clif/python/slots.cc' % common.CLIF_PREFIX,
'%s/clif/python/types.cc' % common.CLIF_PREFIX,
],
include_dirs=[
common.SDK_ROOT_DIR, common.GEN_DIR, common.CLIF_PREFIX, '/'
],
extra_compile_args=['-std=c++11'],
library_dirs=[common.SDK_LIBRARY_DIR],
libraries=['provisioning_sdk'],
runtime_library_dirs=[common.SDK_LIBRARY_DIR],
install_requires=['enum34;python_version<"3.4"'],
),
],
)

View File

@@ -1,5 +1,5 @@
################################################################################
# Copyright 2016 Google Inc.
# 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
@@ -8,15 +8,15 @@
import unittest
import pywrapprovisioning_engine
import pywrapprovisioning_status
import test_data_utility
from provisioning_engine import ProvisioningEngine
from provisioning_status import ProvisioningStatus
class SetCertificateStatusListTest(unittest.TestCase):
def setUp(self):
self._engine = pywrapprovisioning_engine.ProvisioningEngine()
self._engine = ProvisioningEngine()
test_data_utility.InitProvisionEngineWithTestData(
self._engine, verify_success=True)
@@ -27,7 +27,7 @@ class SetCertificateStatusListTest(unittest.TestCase):
def testSetCertificateStatusListInvalid(self):
set_cert_status_list = self._engine.SetCertificateStatusList(
'INVALID_STATUS_LIST', 0)
self.assertEqual(pywrapprovisioning_status.INVALID_STATUS_LIST,
self.assertEqual(ProvisioningStatus.INVALID_STATUS_LIST,
set_cert_status_list)

View File

@@ -1,62 +0,0 @@
################################################################################
# Copyright 2016 Google Inc.
#
# 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.
################################################################################
"""setup script to build Python wrappers using swig configurations."""
import os
from distutils import core
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 core.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)
core.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'
])

View File

@@ -0,0 +1,34 @@
################################################################################
# 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')
CLIF_PREFIX = os.environ['CLIF_PREFIX']
BUILD_DIR = os.environ['PYEXT_BUILD_DIR']
WVCOMMON_SRC_DIR = '%s/common/python' % GEN_DIR
WVPROTO_SRC_DIR = '%s/protos/public' % GEN_DIR
SDK_SRC_DIR = '%s/provisioning_sdk/public/python' % GEN_DIR

View File

@@ -1,16 +1,14 @@
################################################################################
# Copyright 2017 Google Inc.
# 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."""
import os
import pywrapcertificate_type
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')
@@ -21,24 +19,27 @@ class TestDataProvider(object):
def __init__(self, cert_type):
"""Initializes the TestData for Provisioning SDK tests."""
assert (cert_type in (
pywrapcertificate_type.kCertDevelopment,
pywrapcertificate_type.kCertTesting))
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 == pywrapcertificate_type.kCertDevelopment:
if self._cert_type == CertificateType.kCertificateTypeDevelopment:
subfolder_path = _DEV_CERT_DATA_FOLDER
elif self._cert_type == pywrapcertificate_type.kCertTesting:
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)
with open(filename, 'rb') as data_file:
data = data_file.read()
return data
try:
with open(filename, 'r') 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):
@@ -86,11 +87,11 @@ class TestDataProvider(object):
@property
def device_public_key(self):
return self._GetTestData('user.public')
return self._GetTestData('device.public')
@property
def device_private_key(self):
return self._GetTestData('user.private')
return self._GetTestData('device.private')
@property
def message(self):

View File

@@ -1,64 +1,69 @@
################################################################################
# Copyright 2016 Google Inc.
# 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
import pywrapcertificate_type
import pywrapprovisioning_status
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=pywrapcertificate_type.kCertTesting):
engine,
verify_success=False,
cert_type=CertificateType.kCertificateTypeTesting):
"""Initialize the provisioning engine with sample credentials.
Args:
engine: a pywrapprovisioning_engine.ProvisioningEngine instance
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 -
{kCertTesting/kCertDevelopment}
{kCertificateTypeTesting/kCertificateTypeDevelopment}
Returns:
OK on success, or an appropriate error status code otherwise.
"""
logging.info('Initializing provisioning engine with test data.')
data_provider = test_data_provider.TestDataProvider(cert_type)
status = engine.Initialize(cert_type,
data_provider.service_drm_cert,
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:
AssertSuccess(status, 'Failed to initialize.')
assert ProvisioningStatus.OK == status
return status
def SetCertificateStatusListWithTestData(
engine, expiration_period_seconds, verify_success=False,
cert_type=pywrapcertificate_type.kCertTesting):
engine,
expiration_period_seconds,
verify_success=False,
cert_type=CertificateType.kCertificateTypeTesting):
"""Set the certificate status list with sample certificate status list.
Args:
engine: a pywrapprovisioning_engine.ProvisioningEngine instance
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 -
{kCertTesting/kCertDevelopment}
{kCertificateTypeTesting/kCertificateTypeDevelopment}
Returns:
OK on success, or an appropriate error status code otherwise.
@@ -71,14 +76,16 @@ def SetCertificateStatusListWithTestData(
expiration_period_seconds)
if verify_success:
AssertSuccess(status, 'Failed to set certificate status list.')
assert ProvisioningStatus.OK == status
return status
def AddDrmIntermediateCertificateWithTestData(
engine, system_id, verify_success=False,
cert_type=pywrapcertificate_type.kCertTesting):
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
@@ -86,21 +93,21 @@ def AddDrmIntermediateCertificateWithTestData(
passphrase.
Args:
engine: a pywrapprovisioning_engine.ProvisioningEngine instance
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 -
{kCertTesting/kCertDevelopment}
{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)
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)
AssertSuccess(gen_status, 'Failed to generate intermediate certificate.')
assert ProvisioningStatus.OK == gen_status
logging.info('Adding DRM intermediate certificate.')
add_ca_status = engine.AddDrmIntermediateCertificate(
@@ -108,23 +115,26 @@ def AddDrmIntermediateCertificateWithTestData(
data_provider.ca_private_key_passphrase)
if verify_success:
AssertSuccess(add_ca_status, 'Failed to add intermediate certificate.')
assert ProvisioningStatus.OK == add_ca_status
return add_ca_status
def GenerateDeviceDrmCertificate(engine, system_id, serial_number,
verify_success=False,
cert_type=pywrapcertificate_type.kCertTesting):
def GenerateDeviceDrmCertificate(
engine,
system_id,
serial_number,
verify_success=False,
cert_type=CertificateType.kCertificateTypeTesting):
"""Generate a device DRM certificate.
Args:
engine: a pywrapprovisioning_engine.ProvisioningEngine instance
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 -
{kCertTesting/kCertDevelopment}
{kCertificateTypeTesting/kCertificateTypeDevelopment}
Returns:
OK on success, or an appropriate error status code otherwise.
@@ -136,39 +146,36 @@ def GenerateDeviceDrmCertificate(engine, system_id, serial_number,
gen_status, ca_certificate = engine.GenerateDeviceDrmCertificate(
system_id, data_provider.device_public_key, serial_number)
if verify_success:
AssertSuccess(gen_status, 'Failed to generate device DRM certificate.')
assert ProvisioningStatus.OK == gen_status
return ca_certificate
def NewProvisioningSessionWithTestData(
engine, verify_success=False,
cert_type=pywrapcertificate_type.kCertTesting):
engine,
verify_success=False,
cert_type=CertificateType.kCertificateTypeTesting):
"""Create a provisioning session with sample device public and private keys.
Args:
engine: a pywrapprovisioning_engine.ProvisioningEngine instance
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 -
{kCertTesting/kCertDevelopment}
{kCertificateTypeTesting/kCertificateTypeDevelopment}
Returns:
status: OK on success, or an appropriate error status code otherwise.
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)
status, new_session = engine.NewProvisioningSession(
new_session, status = engine.NewProvisioningSession(
certificate_provisioning_pb2.SignedProvisioningMessage.PROVISIONING_30,
data_provider.device_public_key, data_provider.device_private_key)
if verify_success:
AssertSuccess(status, 'Failed to create session.')
assert (ProvisioningStatus.OK == status), 'status = %r' % status
return status, new_session
def AssertSuccess(status, message=None):
"""Assert status equals OK."""
assert pywrapprovisioning_status.OK == status, message
return new_session, status
def ConvertToSignedProvisioningMessage(serialized_message):

View File

@@ -1,51 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// 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.
////////////////////////////////////////////////////////////////////////////////
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