Refactor and cleanup codes. No functional changes.
This commit is contained in:
@@ -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",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -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(
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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
|
||||
@@ -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_
|
||||
|
||||
@@ -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
|
||||
@@ -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_
|
||||
Binary file not shown.
Binary file not shown.
@@ -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
|
||||
@@ -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_
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
235
provisioning_sdk/internal/provisioning30_session_impl.cc
Normal file
235
provisioning_sdk/internal/provisioning30_session_impl.cc
Normal 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
|
||||
78
provisioning_sdk/internal/provisioning30_session_impl.h
Normal file
78
provisioning_sdk/internal/provisioning30_session_impl.h
Normal 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_
|
||||
406
provisioning_sdk/internal/provisioning30_session_impl_test.cc
Normal file
406
provisioning_sdk/internal/provisioning30_session_impl_test.cc
Normal 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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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_
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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.");
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -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);
|
||||
@@ -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
|
||||
36
provisioning_sdk/public/python/certificate_type_setup.py
Normal file
36
provisioning_sdk/public/python/certificate_type_setup.py
Normal file
@@ -0,0 +1,36 @@
|
||||
################################################################################
|
||||
# Copyright 2018 Google LLC.
|
||||
#
|
||||
# This software is licensed under the terms defined in the Widevine Master
|
||||
# License Agreement. For a copy of this agreement, please contact
|
||||
# widevine-licensing@google.com.
|
||||
################################################################################
|
||||
"""Installation file for the certificate_type module."""
|
||||
|
||||
import setup_common as common
|
||||
import setuptools
|
||||
|
||||
if __name__ == '__main__':
|
||||
setuptools.setup(
|
||||
name='certificate_type',
|
||||
ext_modules=[
|
||||
setuptools.Extension(
|
||||
name='certificate_type',
|
||||
sources=[
|
||||
'%s/certificate_type.cc' % common.WVCOMMON_SRC_DIR,
|
||||
'%s/initcertificate_type.cc' % common.WVCOMMON_SRC_DIR,
|
||||
'%s/clif/python/runtime.cc' % common.CLIF_PREFIX,
|
||||
'%s/clif/python/slots.cc' % common.CLIF_PREFIX,
|
||||
'%s/clif/python/types.cc' % common.CLIF_PREFIX,
|
||||
],
|
||||
include_dirs=[
|
||||
common.SDK_ROOT_DIR, common.GEN_DIR, common.CLIF_PREFIX, '/'
|
||||
],
|
||||
extra_compile_args=['-std=c++11'],
|
||||
library_dirs=[common.SDK_LIBRARY_DIR],
|
||||
libraries=['provisioning_sdk'],
|
||||
runtime_library_dirs=[common.SDK_LIBRARY_DIR],
|
||||
install_requires=['enum34;python_version<"3.4"'],
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -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
|
||||
|
||||
@@ -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__':
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
46
provisioning_sdk/public/python/provisioning_engine.clif
Normal file
46
provisioning_sdk/public/python/provisioning_engine.clif
Normal 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)
|
||||
@@ -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
|
||||
47
provisioning_sdk/public/python/provisioning_engine_setup.py
Normal file
47
provisioning_sdk/public/python/provisioning_engine_setup.py
Normal 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__,
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
16
provisioning_sdk/public/python/provisioning_session.clif
Normal file
16
provisioning_sdk/public/python/provisioning_session.clif
Normal file
@@ -0,0 +1,16 @@
|
||||
################################################################################
|
||||
# Copyright 2018 Google LLC.
|
||||
#
|
||||
# This software is licensed under the terms defined in the Widevine Master
|
||||
# License Agreement. For a copy of this agreement, please contact
|
||||
# widevine-licensing@google.com.
|
||||
################################################################################
|
||||
|
||||
from "provisioning_sdk/public/python/provisioning_status.h" import *
|
||||
|
||||
from "provisioning_sdk/public/provisioning_session.h":
|
||||
namespace `widevine`:
|
||||
class ProvisioningSession:
|
||||
def ProcessMessage(self, message: bytes) -> (status: ProvisioningStatus,
|
||||
response: bytes,
|
||||
done: bool)
|
||||
@@ -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
|
||||
38
provisioning_sdk/public/python/provisioning_session_setup.py
Normal file
38
provisioning_sdk/public/python/provisioning_session_setup.py
Normal file
@@ -0,0 +1,38 @@
|
||||
################################################################################
|
||||
# Copyright 2018 Google LLC.
|
||||
#
|
||||
# This software is licensed under the terms defined in the Widevine Master
|
||||
# License Agreement. For a copy of this agreement, please contact
|
||||
# widevine-licensing@google.com.
|
||||
################################################################################
|
||||
"""Installation file for the provisioning_session module."""
|
||||
|
||||
import provisioning_status
|
||||
import setup_common as common
|
||||
import setuptools
|
||||
|
||||
if __name__ == '__main__':
|
||||
setuptools.setup(
|
||||
name='provisioning_session',
|
||||
ext_modules=[
|
||||
setuptools.Extension(
|
||||
name='provisioning_session',
|
||||
sources=[
|
||||
'%s/provisioning_session.cc' % common.SDK_SRC_DIR,
|
||||
'%s/initprovisioning_session.cc' % common.SDK_SRC_DIR,
|
||||
'%s/clif/python/runtime.cc' % common.CLIF_PREFIX,
|
||||
'%s/clif/python/slots.cc' % common.CLIF_PREFIX,
|
||||
'%s/clif/python/types.cc' % common.CLIF_PREFIX,
|
||||
],
|
||||
include_dirs=[
|
||||
common.SDK_ROOT_DIR, common.GEN_DIR, common.CLIF_PREFIX, '/'
|
||||
],
|
||||
extra_compile_args=['-std=c++11'],
|
||||
library_dirs=[common.SDK_LIBRARY_DIR],
|
||||
libraries=['provisioning_sdk'],
|
||||
runtime_library_dirs=[common.SDK_LIBRARY_DIR],
|
||||
install_requires=['enum34;python_version<"3.4"'],
|
||||
extra_objects=[provisioning_status.__file__],
|
||||
),
|
||||
],
|
||||
)
|
||||
12
provisioning_sdk/public/python/provisioning_status.clif
Normal file
12
provisioning_sdk/public/python/provisioning_status.clif
Normal 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
|
||||
@@ -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
|
||||
36
provisioning_sdk/public/python/provisioning_status_setup.py
Normal file
36
provisioning_sdk/public/python/provisioning_status_setup.py
Normal file
@@ -0,0 +1,36 @@
|
||||
################################################################################
|
||||
# Copyright 2018 Google LLC.
|
||||
#
|
||||
# This software is licensed under the terms defined in the Widevine Master
|
||||
# License Agreement. For a copy of this agreement, please contact
|
||||
# widevine-licensing@google.com.
|
||||
################################################################################
|
||||
"""Installation file for the provisioning_status module."""
|
||||
|
||||
import setup_common as common
|
||||
import setuptools
|
||||
|
||||
if __name__ == '__main__':
|
||||
setuptools.setup(
|
||||
name='provisioning_status',
|
||||
ext_modules=[
|
||||
setuptools.Extension(
|
||||
name='provisioning_status',
|
||||
sources=[
|
||||
'%s/provisioning_status.cc' % common.SDK_SRC_DIR,
|
||||
'%s/initprovisioning_status.cc' % common.SDK_SRC_DIR,
|
||||
'%s/clif/python/runtime.cc' % common.CLIF_PREFIX,
|
||||
'%s/clif/python/slots.cc' % common.CLIF_PREFIX,
|
||||
'%s/clif/python/types.cc' % common.CLIF_PREFIX,
|
||||
],
|
||||
include_dirs=[
|
||||
common.SDK_ROOT_DIR, common.GEN_DIR, common.CLIF_PREFIX, '/'
|
||||
],
|
||||
extra_compile_args=['-std=c++11'],
|
||||
library_dirs=[common.SDK_LIBRARY_DIR],
|
||||
libraries=['provisioning_sdk'],
|
||||
runtime_library_dirs=[common.SDK_LIBRARY_DIR],
|
||||
install_requires=['enum34;python_version<"3.4"'],
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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'
|
||||
])
|
||||
34
provisioning_sdk/public/python/setup_common.py
Normal file
34
provisioning_sdk/public/python/setup_common.py
Normal 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
|
||||
@@ -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):
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user