Refactor and cleanup codes. No functional changes.

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

View File

@@ -1,5 +1,5 @@
################################################################################
# Copyright 2016 Google Inc.
# Copyright 2016 Google LLC.
#
# This software is licensed under the terms defined in the Widevine Master
# License Agreement. For a copy of this agreement, please contact
@@ -12,7 +12,9 @@
package_group(
name = "internal",
packages = [
"//arcpp_provisioning/...",
"//provisioning_sdk/...",
"//sigma101_provisioning/...",
],
)
@@ -27,14 +29,21 @@ cc_library(
deps = [
":oem_device_cert",
"//base",
"@abseil_repo//absl/synchronization",
"//common:aes_cbc_util",
"//common:certificate_type",
"//common:crypto_util",
"//common:drm_root_certificate",
"//common:drm_service_certificate",
"//common:random_util",
"//common:rsa_key",
"//provisioning_sdk/internal/certificates:root_certificates",
"//provisioning_sdk/public:certificate_type",
"//provisioning_sdk/internal/certificates:root_oem_certificates",
"//provisioning_sdk/public:provisioning_status",
"//protos/public:device_certificate_proto",
"//protos/public:certificate_provisioning_proto",
"//protos/public:device_certificate_status_proto",
"//protos/public:drm_certificate_proto",
"//protos/public:provisioned_device_info_proto",
"//protos/public:signed_device_certificate_proto",
"//protos/public:signed_drm_certificate_proto",
],
)
@@ -45,9 +54,15 @@ cc_test(
deps = [
":provisioning_engine_impl",
"//base",
"//external:gtest_main",
"//testing:gunit_main",
"//common:certificate_type",
"//common:drm_service_certificate",
"//common:mock_rsa_key",
"//provisioning_sdk/public:certificate_type",
"//common:rsa_test_keys",
"//common:rsa_util",
"//common:status",
"//common:test_drm_certificates",
"//protos/public:certificate_provisioning_proto",
],
)
@@ -56,18 +71,9 @@ cc_library(
srcs = ["provisioning_session_impl.cc"],
hdrs = ["provisioning_session_impl.h"],
deps = [
":oem_device_cert",
":provisioning_engine_impl",
"//base",
"//common:aes_cbc_util",
"//common:random_util",
"//common:rsa_key",
"//common:sha_util",
"//provisioning_sdk/public:provisioning_status",
"//protos/public:certificate_provisioning_proto",
"//protos/public:client_identification_proto",
"//protos/public:device_certificate_proto",
"//protos/public:provisioned_device_info_proto",
],
)
@@ -75,11 +81,46 @@ cc_test(
name = "provisioning_session_impl_test",
size = "small",
srcs = ["provisioning_session_impl_test.cc"],
deps = [
":provisioning_engine_impl",
":provisioning_session_impl",
"//testing:gunit_main",
"//common:mock_rsa_key",
],
)
cc_library(
name = "provisioning30_session_impl",
srcs = ["provisioning30_session_impl.cc"],
hdrs = ["provisioning30_session_impl.h"],
deps = [
":oem_device_cert",
":provisioning_engine_impl",
":provisioning_session_impl",
"//external:gtest_main",
"//base",
"//common:aes_cbc_util",
"//common:drm_service_certificate",
"//common:random_util",
"//common:rsa_key",
"//common:sha_util",
"//provisioning_sdk/public:provisioning_status",
"//protos/public:certificate_provisioning_proto",
"//protos/public:client_identification_proto",
"//protos/public:drm_certificate_proto",
"//protos/public:provisioned_device_info_proto",
],
)
cc_test(
name = "provisioning30_session_impl_test",
size = "small",
srcs = ["provisioning30_session_impl_test.cc"],
deps = [
":oem_device_cert",
":provisioning30_session_impl",
":provisioning_engine_impl",
":provisioning_session_impl",
"//testing:gunit_main",
"//common:aes_cbc_util",
"//common:mock_rsa_key",
"//common:sha_util",
@@ -92,11 +133,12 @@ cc_library(
hdrs = ["oem_device_cert.h"],
deps = [
"//base",
"@abseil_repo//absl/memory",
"//external:openssl",
"//common:certificate_type",
"//common:openssl_util",
"//common:rsa_key",
"//provisioning_sdk/internal/certificates:root_certificates",
"//provisioning_sdk/public:certificate_type",
"//provisioning_sdk/internal/certificates:root_oem_certificates",
],
)
@@ -106,7 +148,8 @@ cc_test(
srcs = ["oem_device_cert_test.cc"],
deps = [
":oem_device_cert",
"//external:gtest_main",
"//provisioning_sdk/internal/certificates:test_certificates",
"//testing:gunit_main",
"//common:rsa_key",
"//provisioning_sdk/internal/certificates:test_oem_certificates",
],
)

View File

@@ -1,5 +1,5 @@
################################################################################
# Copyright 2016 Google Inc.
# Copyright 2016 Google LLC.
#
# This software is licensed under the terms defined in the Widevine Master
# License Agreement. For a copy of this agreement, please contact
@@ -13,37 +13,13 @@ package(
)
cc_library(
name = "root_certificates",
name = "root_oem_certificates",
srcs = [
"root_certificates.cc",
":drm_ca_root_dev_cert",
":drm_ca_root_prod_cert",
":drm_ca_root_test_cert",
"root_oem_certificates.cc",
":oem_ca_root_dev_der",
":oem_ca_root_prod_der",
],
hdrs = ["root_certificates.h"],
)
genrule(
name = "drm_ca_root_test_cert",
srcs = ["drm_ca_root_test.cert"],
outs = ["drm_ca_root_test_cert.h"],
cmd = "cd $$(dirname $<) && xxd -i $$(basename $<) $$OLDPWD/$@",
)
genrule(
name = "drm_ca_root_dev_cert",
srcs = ["drm_ca_root_dev.cert"],
outs = ["drm_ca_root_dev_cert.h"],
cmd = "cd $$(dirname $<) && xxd -i $$(basename $<) $$OLDPWD/$@",
)
genrule(
name = "drm_ca_root_prod_cert",
srcs = ["drm_ca_root_prod.cert"],
outs = ["drm_ca_root_prod_cert.h"],
cmd = "cd $$(dirname $<) && xxd -i $$(basename $<) $$OLDPWD/$@",
hdrs = ["root_oem_certificates.h"],
)
genrule(
@@ -61,9 +37,9 @@ genrule(
)
cc_library(
name = "test_certificates",
name = "test_oem_certificates",
srcs = [
"test_certificates.cc",
"test_oem_certificates.cc",
":backwards_chain_der",
":expired_2000_chain_der",
":invalid_chain_der",
@@ -71,7 +47,7 @@ cc_library(
":sysid_2001_chain_der",
":sysid_2001_public_key_der",
],
hdrs = ["test_certificates.h"],
hdrs = ["test_oem_certificates.h"],
)
genrule(

View File

@@ -1,38 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "provisioning_sdk/internal/certificates/root_certificates.h"
#include "provisioning_sdk/internal/certificates/drm_ca_root_dev_cert.h"
#include "provisioning_sdk/internal/certificates/drm_ca_root_prod_cert.h"
#include "provisioning_sdk/internal/certificates/drm_ca_root_test_cert.h"
#include "provisioning_sdk/internal/certificates/oem_ca_root_dev_cert.h"
#include "provisioning_sdk/internal/certificates/oem_ca_root_prod_cert.h"
namespace widevine {
RootCertificates::RootCertificates()
: drm_root_test_certificate_(
drm_ca_root_test_cert,
drm_ca_root_test_cert + drm_ca_root_test_cert_len),
drm_root_dev_certificate_(
drm_ca_root_dev_cert,
drm_ca_root_dev_cert + drm_ca_root_dev_cert_len),
drm_root_prod_certificate_(
drm_ca_root_prod_cert,
drm_ca_root_prod_cert + drm_ca_root_prod_cert_len),
oem_root_dev_certificate_(
oem_ca_root_dev_cert_der,
oem_ca_root_dev_cert_der + oem_ca_root_dev_cert_der_len),
oem_root_prod_certificate_(
oem_ca_root_prod_cert_der,
oem_ca_root_prod_cert_der + oem_ca_root_prod_cert_der_len) {}
RootCertificates::~RootCertificates() {}
} // namespace widevine

View File

@@ -1,56 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#ifndef PROVISIONING_SDK_INTERNAL_CERTIFICATES_ROOT_CERTIFICATES_H_
#define PROVISIONING_SDK_INTERNAL_CERTIFICATES_ROOT_CERTIFICATES_H_
#include <string>
namespace widevine {
// This class contains DRM and OEM root certificates.
class RootCertificates {
public:
RootCertificates();
~RootCertificates();
const std::string& drm_root_test_certificate() const {
return drm_root_test_certificate_;
}
const std::string& drm_root_dev_certificate() const {
return drm_root_dev_certificate_;
}
const std::string& drm_root_prod_certificate() const {
return drm_root_prod_certificate_;
}
const std::string& oem_root_dev_certificate() const {
return oem_root_dev_certificate_;
}
const std::string& oem_root_prod_certificate() const {
return oem_root_prod_certificate_;
}
private:
RootCertificates(const RootCertificates&) = delete;
RootCertificates& operator=(const RootCertificates&) = delete;
std::string drm_root_test_certificate_;
std::string drm_root_dev_certificate_;
std::string drm_root_prod_certificate_;
std::string oem_root_dev_certificate_;
std::string oem_root_prod_certificate_;
};
} // namespace widevine
#endif // PROVISIONING_SDK_INTERNAL_CERTIFICATES_ROOT_CERTIFICATES_H_

View File

@@ -0,0 +1,26 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "provisioning_sdk/internal/certificates/root_oem_certificates.h"
#include "provisioning_sdk/internal/certificates/oem_ca_root_dev_cert.h"
#include "provisioning_sdk/internal/certificates/oem_ca_root_prod_cert.h"
namespace widevine {
RootOemCertificates::RootOemCertificates()
: oem_root_dev_certificate_(
oem_ca_root_dev_cert_der,
oem_ca_root_dev_cert_der + oem_ca_root_dev_cert_der_len),
oem_root_prod_certificate_(
oem_ca_root_prod_cert_der,
oem_ca_root_prod_cert_der + oem_ca_root_prod_cert_der_len) {}
RootOemCertificates::~RootOemCertificates() {}
} // namespace widevine

View File

@@ -0,0 +1,40 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#ifndef PROVISIONING_SDK_INTERNAL_CERTIFICATES_ROOT_OEM_CERTIFICATES_H_
#define PROVISIONING_SDK_INTERNAL_CERTIFICATES_ROOT_OEM_CERTIFICATES_H_
#include <string>
namespace widevine {
// This class contains development and production OEM root certificates.
class RootOemCertificates {
public:
RootOemCertificates();
~RootOemCertificates();
const std::string& oem_root_dev_certificate() const {
return oem_root_dev_certificate_;
}
const std::string& oem_root_prod_certificate() const {
return oem_root_prod_certificate_;
}
private:
RootOemCertificates(const RootOemCertificates&) = delete;
RootOemCertificates& operator=(const RootOemCertificates&) = delete;
std::string oem_root_dev_certificate_;
std::string oem_root_prod_certificate_;
};
} // namespace widevine
#endif // PROVISIONING_SDK_INTERNAL_CERTIFICATES_ROOT_OEM_CERTIFICATES_H_

View File

@@ -1,12 +1,12 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "provisioning_sdk/internal/certificates/test_certificates.h"
#include "provisioning_sdk/internal/certificates/test_oem_certificates.h"
#include "provisioning_sdk/internal/certificates/backwards_chain.h"
#include "provisioning_sdk/internal/certificates/expired_2000_chain.h"
@@ -17,7 +17,7 @@
namespace widevine {
TestCertificates::TestCertificates()
TestOemCertificates::TestOemCertificates()
: single_certificate_chain_der_(
single_cert_chain_der,
single_cert_chain_der + single_cert_chain_der_len),
@@ -35,6 +35,6 @@ TestCertificates::TestCertificates()
invalid_certificate_chain_der_(
invalid_chain_der, invalid_chain_der + invalid_chain_der_len) {}
TestCertificates::~TestCertificates() {}
TestOemCertificates::~TestOemCertificates() {}
} // namespace widevine

View File

@@ -1,24 +1,24 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#ifndef PROVISIONING_SDK_INTERNAL_CERTIFICATES_TEST_CERTIFICATES_H_
#define PROVISIONING_SDK_INTERNAL_CERTIFICATES_TEST_CERTIFICATES_H_
#ifndef PROVISIONING_SDK_INTERNAL_CERTIFICATES_TEST_OEM_CERTIFICATES_H_
#define PROVISIONING_SDK_INTERNAL_CERTIFICATES_TEST_OEM_CERTIFICATES_H_
#include <string>
namespace widevine {
// This class contains DER-encoded test certificates. The keys for these
// This class contains DER-encoded test OEM certificates. The keys for these
// certificates came from common/rsa_test_keys.h.
class TestCertificates {
class TestOemCertificates {
public:
TestCertificates();
~TestCertificates();
TestOemCertificates();
~TestOemCertificates();
const std::string& single_certificate_chain_der() const {
return single_certificate_chain_der_;
@@ -45,8 +45,8 @@ class TestCertificates {
}
private:
TestCertificates(const TestCertificates&) = delete;
TestCertificates& operator=(const TestCertificates&) = delete;
TestOemCertificates(const TestOemCertificates&) = delete;
TestOemCertificates& operator=(const TestOemCertificates&) = delete;
std::string single_certificate_chain_der_;
// leaf + intermediate certificates.
@@ -60,4 +60,4 @@ class TestCertificates {
} // namespace widevine
#endif // PROVISIONING_SDK_INTERNAL_CERTIFICATES_TEST_CERTIFICATES_H_
#endif // PROVISIONING_SDK_INTERNAL_CERTIFICATES_TEST_OEM_CERTIFICATES_H_

View File

@@ -1,5 +1,5 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
@@ -11,10 +11,12 @@
#include <string.h>
#include "glog/logging.h"
#include "absl/memory/memory.h"
#include "openssl/asn1.h"
#include "openssl/pkcs7.h"
#include "openssl/x509.h"
#include "openssl/x509v3.h"
#include "provisioning_sdk/internal/certificates/root_certificates.h"
#include "provisioning_sdk/internal/certificates/root_oem_certificates.h"
namespace widevine {
namespace {
@@ -29,7 +31,7 @@ bool ExtractPublicKey(X509* x509, std::unique_ptr<RsaPublicKey>* public_key) {
LOG(WARNING) << "X509_get_pubkey failed.";
return false;
}
public_key->reset(new RsaPublicKey(EVP_PKEY_get1_RSA(pkey.get())));
*public_key = absl::make_unique<RsaPublicKey>(EVP_PKEY_get1_RSA(pkey.get()));
return true;
}
@@ -105,12 +107,12 @@ OemDeviceCert::OemDeviceCert() {}
OemDeviceCert::~OemDeviceCert() {}
bool OemDeviceCert::Initialize(CertificateType certificate_type) {
RootCertificates root_certificates;
RootOemCertificates root_certificates;
switch (certificate_type) {
case kCertTesting:
case kCertDevelopment:
case kCertificateTypeTesting:
case kCertificateTypeDevelopment:
return Initialize(root_certificates.oem_root_dev_certificate());
case kCertProduction:
case kCertificateTypeProduction:
return Initialize(root_certificates.oem_root_prod_certificate());
default:
LOG(WARNING) << "Invalid certificate type " << certificate_type;

View File

@@ -1,5 +1,5 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
@@ -14,9 +14,9 @@
#include <memory>
#include <string>
#include "common/certificate_type.h"
#include "common/openssl_util.h"
#include "common/rsa_key.h"
#include "provisioning_sdk/public/certificate_type.h"
namespace widevine {

View File

@@ -1,5 +1,5 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google Inc.
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
@@ -8,19 +8,20 @@
#include "provisioning_sdk/internal/oem_device_cert.h"
#include "gtest/gtest.h"
#include "provisioning_sdk/internal/certificates/test_certificates.h"
#include "testing/gunit.h"
#include "common/rsa_key.h"
#include "provisioning_sdk/internal/certificates/test_oem_certificates.h"
namespace widevine {
class OemDeviceCertTest : public ::testing::Test {
protected:
void SetUp() override {
ASSERT_TRUE(oem_device_cert_.Initialize(kCertTesting));
ASSERT_TRUE(oem_device_cert_.Initialize(kCertificateTypeTesting));
}
OemDeviceCert oem_device_cert_;
TestCertificates test_certificates_;
TestOemCertificates test_oem_certificates_;
};
TEST_F(OemDeviceCertTest, EmptyCertificateChain) {
@@ -45,7 +46,7 @@ TEST_F(OemDeviceCertTest, OnlyOneCertificateInCertificateChain) {
uint32_t system_id;
std::string oem_ca_serial_number;
EXPECT_FALSE(oem_device_cert_.VerifyCertificateChain(
test_certificates_.single_certificate_chain_der(), &leaf_public_key,
test_oem_certificates_.single_certificate_chain_der(), &leaf_public_key,
&system_id, &oem_ca_serial_number));
}
@@ -54,11 +55,11 @@ TEST_F(OemDeviceCertTest, ValidCertificateChain) {
uint32_t system_id;
std::string oem_ca_serial_number;
ASSERT_TRUE(oem_device_cert_.VerifyCertificateChain(
test_certificates_.valid_certificate_chain_der(), &leaf_public_key,
test_oem_certificates_.valid_certificate_chain_der(), &leaf_public_key,
&system_id, &oem_ca_serial_number));
std::unique_ptr<RsaPublicKey> public_key(RsaPublicKey::Create(
test_certificates_.valid_certificate_public_key_der()));
test_oem_certificates_.valid_certificate_public_key_der()));
ASSERT_TRUE(public_key);
EXPECT_TRUE(leaf_public_key->MatchesPublicKey(*public_key));
EXPECT_EQ(2001u, system_id);
@@ -70,7 +71,7 @@ TEST_F(OemDeviceCertTest, ExpiredCertificateChain) {
uint32_t system_id;
std::string oem_ca_serial_number;
ASSERT_FALSE(oem_device_cert_.VerifyCertificateChain(
test_certificates_.expired_certificate_chain_der(), &leaf_public_key,
test_oem_certificates_.expired_certificate_chain_der(), &leaf_public_key,
&system_id, &oem_ca_serial_number));
}
@@ -79,8 +80,8 @@ TEST_F(OemDeviceCertTest, OutOfOrderCertificateChain) {
uint32_t system_id;
std::string oem_ca_serial_number;
ASSERT_FALSE(oem_device_cert_.VerifyCertificateChain(
test_certificates_.backwards_certificate_chain_der(), &leaf_public_key,
&system_id, &oem_ca_serial_number));
test_oem_certificates_.backwards_certificate_chain_der(),
&leaf_public_key, &system_id, &oem_ca_serial_number));
}
TEST_F(OemDeviceCertTest, CertificateChainNotSignedByRoot) {
@@ -88,7 +89,7 @@ TEST_F(OemDeviceCertTest, CertificateChainNotSignedByRoot) {
uint32_t system_id;
std::string oem_ca_serial_number;
ASSERT_FALSE(oem_device_cert_.VerifyCertificateChain(
test_certificates_.invalid_certificate_chain_der(), &leaf_public_key,
test_oem_certificates_.invalid_certificate_chain_der(), &leaf_public_key,
&system_id, &oem_ca_serial_number));
}

View File

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

View File

@@ -0,0 +1,78 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
// ProvisioningSession internal implementation.
#ifndef PROVISIONING_SDK_INTERNAL_PROVISIONING30_SESSION_IMPL_H_
#define PROVISIONING_SDK_INTERNAL_PROVISIONING30_SESSION_IMPL_H_
#include <stdint.h>
#include <memory>
#include <string>
#include <utility>
#include "common/rsa_key.h"
#include "provisioning_sdk/internal/oem_device_cert.h"
#include "provisioning_sdk/internal/provisioning_session_impl.h"
#include "provisioning_sdk/public/provisioning_status.h"
#include "protos/public/certificate_provisioning.pb.h"
#include "protos/public/client_identification.pb.h"
#include "protos/public/drm_certificate.pb.h"
#include "protos/public/provisioned_device_info.pb.h"
namespace widevine {
class ProvisioningEngineImpl;
class Provisioning30SessionImpl : public ProvisioningSessionImpl {
public:
Provisioning30SessionImpl(const ProvisioningEngineImpl& engine,
const OemDeviceCert& oem_device_cert,
const RsaPrivateKey& service_private_key);
// Process a message from the client device.
// * |message| is the message received from the client device.
// * |response| will contain, upon successful return, a message to be sent
// back to the client device as a response to |message|.
// * |done| will indicate, upon successful return, whether the provisioning
// exchange is complete.
// Returns OK if successful, or an appropriate error status code otherwise.
ProvisioningStatus ProcessMessage(const std::string& message,
std::string* response,
bool* done) override;
// * Returns a ProvisioneddeviceInfo message containing information about the
// type of device being provisioned. May return nullptr.
const ProvisionedDeviceInfo* GetDeviceInfo() const override {
return device_info_.get();
}
private:
Provisioning30SessionImpl(const Provisioning30SessionImpl&) = delete;
Provisioning30SessionImpl& operator=(const Provisioning30SessionImpl&) =
delete;
bool ValidateAndDeserializeRequest(const std::string& message,
SignedProvisioningMessage* signed_request,
ProvisioningRequest* request) const;
bool DecryptClientIdentification(
const EncryptedClientIdentification& encrypted_client_id,
ClientIdentification* client_id);
ProvisioningStatus GenerateProvisioningResponse(
uint32_t system_id, const std::string& oem_ca_serial_number,
const std::string& provider_id, const std::string& certificate_serial_number,
const RsaPublicKey& cert_public_key, ProvisioningResponse* response);
const OemDeviceCert& oem_device_cert_;
const RsaPrivateKey& service_private_key_;
std::shared_ptr<ProvisionedDeviceInfo> device_info_;
};
} // namespace widevine
#endif // PROVISIONING_SDK_INTERNAL_PROVISIONING30_SESSION_IMPL_H_

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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