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
|
||||
|
||||
Reference in New Issue
Block a user