Rollback
Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=224206719
This commit is contained in:
committed by
Fang Yu
parent
df7566c0c1
commit
7f649cf826
15
WORKSPACE
15
WORKSPACE
@@ -1,4 +1,5 @@
|
|||||||
workspace(name = "media_cas_proxy_sdk")
|
workspace(name = "media_cas_proxy_sdk")
|
||||||
|
load("@bazel_tools//tools/build_defs/repo:git.bzl", "new_git_repository", "git_repository")
|
||||||
|
|
||||||
# CCTZ (Time-zone framework), needed by abseil.
|
# CCTZ (Time-zone framework), needed by abseil.
|
||||||
git_repository(
|
git_repository(
|
||||||
@@ -24,7 +25,7 @@ git_repository(
|
|||||||
|
|
||||||
git_repository(
|
git_repository(
|
||||||
name = "boringssl_repo",
|
name = "boringssl_repo",
|
||||||
commit = "27ae6cadd74fd054208730827a8de3fe9bc648f0", # 2017-12-07
|
commit = "14164f6fef47b7ebd97cdb0cea1624eabd6fe6b8", # 2018-11-26
|
||||||
remote = "https://github.com/google/boringssl.git",
|
remote = "https://github.com/google/boringssl.git",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -48,7 +49,7 @@ maven_jar(
|
|||||||
|
|
||||||
new_git_repository(
|
new_git_repository(
|
||||||
name = "glog_repo",
|
name = "glog_repo",
|
||||||
build_file = "glog.BUILD",
|
build_file = "@//:glog.BUILD",
|
||||||
commit = "0472b91c5defdf90cff7292e3bf7bd86770a9a0a", # 2016-07-13
|
commit = "0472b91c5defdf90cff7292e3bf7bd86770a9a0a", # 2016-07-13
|
||||||
remote = "https://github.com/google/glog.git",
|
remote = "https://github.com/google/glog.git",
|
||||||
)
|
)
|
||||||
@@ -58,21 +59,11 @@ bind(
|
|||||||
actual = "@com_google_protobuf//:protobuf",
|
actual = "@com_google_protobuf//:protobuf",
|
||||||
)
|
)
|
||||||
|
|
||||||
bind(
|
|
||||||
name = "com_google_protobuf_cc",
|
|
||||||
actual = "@com_google_protobuf//:protobuf",
|
|
||||||
)
|
|
||||||
|
|
||||||
bind(
|
bind(
|
||||||
name = "protobuf_java",
|
name = "protobuf_java",
|
||||||
actual = "@com_google_protobuf//:protobuf_java",
|
actual = "@com_google_protobuf//:protobuf_java",
|
||||||
)
|
)
|
||||||
|
|
||||||
bind(
|
|
||||||
name = "com_google_protobuf_java",
|
|
||||||
actual = "@com_google_protobuf//:protobuf_java",
|
|
||||||
)
|
|
||||||
|
|
||||||
bind(
|
bind(
|
||||||
name = "openssl",
|
name = "openssl",
|
||||||
actual = "@boringssl_repo//:crypto",
|
actual = "@boringssl_repo//:crypto",
|
||||||
|
|||||||
123
common/BUILD
123
common/BUILD
@@ -31,6 +31,98 @@ cc_library(
|
|||||||
hdrs = ["certificate_type.h"],
|
hdrs = ["certificate_type.h"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cc_library(
|
||||||
|
name = "client_cert",
|
||||||
|
srcs = ["client_cert.cc"],
|
||||||
|
hdrs = ["client_cert.h"],
|
||||||
|
deps = [
|
||||||
|
":crypto_util",
|
||||||
|
":drm_root_certificate",
|
||||||
|
":error_space",
|
||||||
|
":random_util",
|
||||||
|
":rsa_key",
|
||||||
|
":signing_key_util",
|
||||||
|
":wvm_token_handler",
|
||||||
|
"//base",
|
||||||
|
"//strings",
|
||||||
|
"@abseil_repo//absl/strings",
|
||||||
|
"@abseil_repo//absl/synchronization",
|
||||||
|
"@abseil_repo//absl/time",
|
||||||
|
"//util/gtl:map_util",
|
||||||
|
"//util:status",
|
||||||
|
"//protos/public:client_identification_proto",
|
||||||
|
"//protos/public:drm_certificate_proto",
|
||||||
|
"//protos/public:errors_proto",
|
||||||
|
"//protos/public:license_protocol_proto",
|
||||||
|
"//protos/public:signed_drm_certificate_proto",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc_test(
|
||||||
|
name = "client_cert_test",
|
||||||
|
srcs = ["client_cert_test.cc"],
|
||||||
|
deps = [
|
||||||
|
":client_cert",
|
||||||
|
":drm_root_certificate",
|
||||||
|
":error_space",
|
||||||
|
":wvm_test_keys",
|
||||||
|
"//base",
|
||||||
|
"//strings",
|
||||||
|
"//testing:gunit_main",
|
||||||
|
"@abseil_repo//absl/strings",
|
||||||
|
"@abseil_repo//absl/synchronization",
|
||||||
|
"@abseil_repo//absl/time",
|
||||||
|
"//common:rsa_key",
|
||||||
|
"//common:rsa_test_keys",
|
||||||
|
"//protos/public:drm_certificate_proto",
|
||||||
|
"//protos/public:errors_proto",
|
||||||
|
"//protos/public:signed_drm_certificate_proto",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc_library(
|
||||||
|
name = "device_status_list",
|
||||||
|
srcs = ["device_status_list.cc"],
|
||||||
|
hdrs = ["device_status_list.h"],
|
||||||
|
deps = [
|
||||||
|
":client_cert",
|
||||||
|
":crypto_util",
|
||||||
|
":drm_root_certificate",
|
||||||
|
":error_space",
|
||||||
|
":random_util",
|
||||||
|
":rsa_key",
|
||||||
|
":signing_key_util",
|
||||||
|
"//base",
|
||||||
|
"@abseil_repo//absl/strings",
|
||||||
|
"@abseil_repo//absl/synchronization",
|
||||||
|
"//util/gtl:map_util",
|
||||||
|
"//util:status",
|
||||||
|
"//protos/public:client_identification_proto",
|
||||||
|
"//protos/public:device_certificate_status_proto",
|
||||||
|
"//protos/public:errors_proto",
|
||||||
|
"//protos/public:provisioned_device_info_proto",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc_test(
|
||||||
|
name = "device_status_list_test",
|
||||||
|
timeout = "short",
|
||||||
|
srcs = ["device_status_list_test.cc"],
|
||||||
|
deps = [
|
||||||
|
":client_cert",
|
||||||
|
":device_status_list",
|
||||||
|
"//base",
|
||||||
|
"//testing:gunit_main",
|
||||||
|
"@abseil_repo//absl/strings",
|
||||||
|
"//common:rsa_key",
|
||||||
|
"//common:rsa_test_keys",
|
||||||
|
"//protos/public:client_identification_proto",
|
||||||
|
"//protos/public:errors_proto",
|
||||||
|
"//protos/public:provisioned_device_info_proto",
|
||||||
|
"//protos/public:signed_drm_certificate_proto",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
cc_library(
|
cc_library(
|
||||||
name = "drm_root_certificate",
|
name = "drm_root_certificate",
|
||||||
srcs = ["drm_root_certificate.cc"],
|
srcs = ["drm_root_certificate.cc"],
|
||||||
@@ -39,8 +131,11 @@ cc_library(
|
|||||||
":certificate_type",
|
":certificate_type",
|
||||||
":error_space",
|
":error_space",
|
||||||
":rsa_key",
|
":rsa_key",
|
||||||
|
":sha_util",
|
||||||
"//base",
|
"//base",
|
||||||
|
"@abseil_repo//absl/memory",
|
||||||
"@abseil_repo//absl/strings",
|
"@abseil_repo//absl/strings",
|
||||||
|
"@abseil_repo//absl/synchronization",
|
||||||
"//external:openssl",
|
"//external:openssl",
|
||||||
"//util:status",
|
"//util:status",
|
||||||
"//protos/public:drm_certificate_proto",
|
"//protos/public:drm_certificate_proto",
|
||||||
@@ -55,9 +150,12 @@ cc_test(
|
|||||||
srcs = ["drm_root_certificate_test.cc"],
|
srcs = ["drm_root_certificate_test.cc"],
|
||||||
deps = [
|
deps = [
|
||||||
":drm_root_certificate",
|
":drm_root_certificate",
|
||||||
|
":error_space",
|
||||||
":rsa_key",
|
":rsa_key",
|
||||||
":rsa_test_keys",
|
":rsa_test_keys",
|
||||||
|
":test_drm_certificates",
|
||||||
"//base",
|
"//base",
|
||||||
|
"//external:protobuf",
|
||||||
"//testing:gunit_main",
|
"//testing:gunit_main",
|
||||||
"//protos/public:drm_certificate_proto",
|
"//protos/public:drm_certificate_proto",
|
||||||
"//protos/public:errors_proto",
|
"//protos/public:errors_proto",
|
||||||
@@ -65,22 +163,6 @@ cc_test(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
cc_library(
|
|
||||||
name = "certificate_util",
|
|
||||||
srcs = ["certificate_util.cc"],
|
|
||||||
hdrs = ["certificate_util.h"],
|
|
||||||
deps = [
|
|
||||||
":certificate_type",
|
|
||||||
":drm_root_certificate",
|
|
||||||
":drm_service_certificate",
|
|
||||||
":verified_media_pipeline",
|
|
||||||
":vmp_checker",
|
|
||||||
"//base",
|
|
||||||
"//util:status",
|
|
||||||
"//license_server_sdk/internal:sdk",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
cc_library(
|
cc_library(
|
||||||
name = "client_id_util",
|
name = "client_id_util",
|
||||||
srcs = ["client_id_util.cc"],
|
srcs = ["client_id_util.cc"],
|
||||||
@@ -342,10 +424,10 @@ cc_test(
|
|||||||
)
|
)
|
||||||
|
|
||||||
cc_library(
|
cc_library(
|
||||||
name = "test_certificates",
|
name = "test_drm_certificates",
|
||||||
testonly = 1,
|
testonly = 1,
|
||||||
srcs = ["test_certificates.cc"],
|
srcs = ["test_drm_certificates.cc"],
|
||||||
hdrs = ["test_certificates.h"],
|
hdrs = ["test_drm_certificates.h"],
|
||||||
deps = [
|
deps = [
|
||||||
"//base",
|
"//base",
|
||||||
"@abseil_repo//absl/strings",
|
"@abseil_repo//absl/strings",
|
||||||
@@ -454,11 +536,12 @@ cc_test(
|
|||||||
srcs = ["drm_service_certificate_test.cc"],
|
srcs = ["drm_service_certificate_test.cc"],
|
||||||
deps = [
|
deps = [
|
||||||
":aes_cbc_util",
|
":aes_cbc_util",
|
||||||
|
":drm_root_certificate",
|
||||||
":drm_service_certificate",
|
":drm_service_certificate",
|
||||||
":rsa_key",
|
":rsa_key",
|
||||||
":rsa_test_keys",
|
":rsa_test_keys",
|
||||||
":rsa_util",
|
":rsa_util",
|
||||||
":test_certificates",
|
":test_drm_certificates",
|
||||||
"//base",
|
"//base",
|
||||||
"//external:protobuf",
|
"//external:protobuf",
|
||||||
"//testing:gunit_main",
|
"//testing:gunit_main",
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Copyright 2018 Google LLC.
|
|
||||||
//
|
|
||||||
// This software is licensed under the terms defined in the Widevine Master
|
|
||||||
// License Agreement. For a copy of this agreement, please contact
|
|
||||||
// widevine-licensing@google.com.
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#include "common/certificate_util.h"
|
|
||||||
|
|
||||||
#include "common/certificate_type.h"
|
|
||||||
#include "common/drm_root_certificate.h"
|
|
||||||
#include "common/drm_service_certificate.h"
|
|
||||||
#include "common/verified_media_pipeline.h"
|
|
||||||
#include "common/vmp_checker.h"
|
|
||||||
#include "license_server_sdk/internal/client_cert.h"
|
|
||||||
#include "license_server_sdk/internal/device_status_list.h"
|
|
||||||
|
|
||||||
namespace widevine {
|
|
||||||
util::Status SetCertificateStatusList(
|
|
||||||
CertificateType cert_type, const std::string& signed_certificate_status_list,
|
|
||||||
uint32_t expiration_period_seconds, bool allow_unknown_devices) {
|
|
||||||
util::Status status =
|
|
||||||
VmpChecker::Instance()->SelectDrmCertificateType(cert_type);
|
|
||||||
if (!status.ok()) return status;
|
|
||||||
|
|
||||||
std::unique_ptr<DrmRootCertificate> root_cert;
|
|
||||||
status = DrmRootCertificate::CreateByType(cert_type, &root_cert);
|
|
||||||
if (!status.ok()) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
status = CertificateClientCert::SetDrmRootCertificatePublicKey(
|
|
||||||
root_cert->public_key());
|
|
||||||
if (!status.ok()) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
DeviceStatusList::Instance()->set_allow_unknown_devices(
|
|
||||||
allow_unknown_devices);
|
|
||||||
return DeviceStatusList::Instance()->UpdateStatusList(
|
|
||||||
root_cert->public_key(), signed_certificate_status_list,
|
|
||||||
expiration_period_seconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
util::Status AddDrmServiceCertificate(
|
|
||||||
CertificateType cert_type, const std::string& service_certificate,
|
|
||||||
const std::string& service_private_key,
|
|
||||||
const std::string& service_private_key_passphrase) {
|
|
||||||
util::Status status =
|
|
||||||
VmpChecker::Instance()->SelectDrmCertificateType(cert_type);
|
|
||||||
if (!status.ok()) return status;
|
|
||||||
return DrmServiceCertificate::AddDrmServiceCertificate(
|
|
||||||
cert_type, service_certificate, service_private_key,
|
|
||||||
service_private_key_passphrase);
|
|
||||||
}
|
|
||||||
} // namespace widevine
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Copyright 2018 Google LLC.
|
|
||||||
//
|
|
||||||
// This software is licensed under the terms defined in the Widevine Master
|
|
||||||
// License Agreement. For a copy of this agreement, please contact
|
|
||||||
// widevine-licensing@google.com.
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#ifndef COMMON_CERTIFICATE_UTIL_H_
|
|
||||||
#define COMMON_CERTIFICATE_UTIL_H_
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "util/status.h"
|
|
||||||
#include "common/certificate_type.h"
|
|
||||||
|
|
||||||
namespace widevine {
|
|
||||||
// Set the certificate status list system-wide. |cert_type| specifies
|
|
||||||
// whether to use development or production root certificates.
|
|
||||||
// |expiration_period| is the number of seconds until the
|
|
||||||
// certificate_status_list expires after its creation time
|
|
||||||
// (creation_time_seconds). If |allow_unknown_devices| is false, an error is
|
|
||||||
// returned if the device does not appear in the certificate_status_list.
|
|
||||||
util::Status SetCertificateStatusList(CertificateType cert_type,
|
|
||||||
const std::string& certificate_status_list,
|
|
||||||
uint32_t expiration_period_seconds,
|
|
||||||
bool allow_unknown_devices);
|
|
||||||
|
|
||||||
// Add a service certificate system-wide. |cert_type| indicates the type of
|
|
||||||
// root certificate used to sign the service certificate;
|
|
||||||
// |service_certificate| is a Google-generated certificate used to
|
|
||||||
// authenticate the service provider for purposes of device privacy;
|
|
||||||
// |service_private_key| is the encrypted PKCS#8 private RSA key corresponding
|
|
||||||
// to the service certificate; and |service_private_key_passphrase| is the
|
|
||||||
// password required to decrypt |service_private_key|.
|
|
||||||
util::Status AddDrmServiceCertificate(
|
|
||||||
CertificateType cert_type, const std::string& service_certificate,
|
|
||||||
const std::string& service_private_key,
|
|
||||||
const std::string& service_private_key_passphrase);
|
|
||||||
} // namespace widevine
|
|
||||||
|
|
||||||
#endif // COMMON_CERTIFICATE_UTIL_H_
|
|
||||||
260
common/client_cert.cc
Normal file
260
common/client_cert.cc
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright 2017 Google LLC.
|
||||||
|
//
|
||||||
|
// This software is licensed under the terms defined in the Widevine Master
|
||||||
|
// License Agreement. For a copy of this agreement, please contact
|
||||||
|
// widevine-licensing@google.com.
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "common/client_cert.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "glog/logging.h"
|
||||||
|
#include "strings/serialize.h"
|
||||||
|
#include "absl/strings/escaping.h"
|
||||||
|
#include "absl/synchronization/mutex.h"
|
||||||
|
#include "util/gtl/map_util.h"
|
||||||
|
#include "util/status.h"
|
||||||
|
#include "common/crypto_util.h"
|
||||||
|
#include "common/drm_root_certificate.h"
|
||||||
|
#include "common/error_space.h"
|
||||||
|
#include "common/random_util.h"
|
||||||
|
#include "common/signing_key_util.h"
|
||||||
|
#include "common/wvm_token_handler.h"
|
||||||
|
#include "protos/public/drm_certificate.pb.h"
|
||||||
|
#include "protos/public/errors.pb.h"
|
||||||
|
#include "protos/public/signed_drm_certificate.pb.h"
|
||||||
|
|
||||||
|
// TODO(user): Get rid of this horror.
|
||||||
|
|
||||||
|
namespace widevine {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const int kKeyboxSizeBytes = 72;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// TODO(user): change to util::StatusOr<std::unique_ptr<ClientCert>>
|
||||||
|
// instead of ClientCert** to explicitly assigning ownership of the created
|
||||||
|
// object to the caller.
|
||||||
|
|
||||||
|
util::Status ClientCert::Create(const DrmRootCertificate* root_certificate,
|
||||||
|
ClientIdentification::TokenType token_type,
|
||||||
|
const std::string& token, ClientCert** client_cert) {
|
||||||
|
DCHECK(client_cert);
|
||||||
|
if (token_type == ClientIdentification::KEYBOX) {
|
||||||
|
*client_cert = nullptr;
|
||||||
|
if (token.size() < kKeyboxSizeBytes) {
|
||||||
|
return util::Status(error_space, INVALID_KEYBOX_TOKEN,
|
||||||
|
"keybox-token-is-too-short");
|
||||||
|
}
|
||||||
|
return ClientCert::CreateWithKeybox(token, client_cert);
|
||||||
|
} else if (token_type == ClientIdentification::DRM_DEVICE_CERTIFICATE) {
|
||||||
|
return CreateWithDrmCertificate(root_certificate, token, client_cert);
|
||||||
|
} else {
|
||||||
|
return util::Status(error_space, util::error::UNIMPLEMENTED,
|
||||||
|
"client-type-not-implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
util::Status ClientCert::CreateWithKeybox(const std::string& keybox_token,
|
||||||
|
ClientCert** client_cert) {
|
||||||
|
CHECK(client_cert);
|
||||||
|
*client_cert = nullptr;
|
||||||
|
|
||||||
|
std::unique_ptr<KeyboxClientCert> new_client_cert(new KeyboxClientCert);
|
||||||
|
util::Status status = new_client_cert->Initialize(keybox_token);
|
||||||
|
if (!status.ok()) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
*client_cert = new_client_cert.release();
|
||||||
|
return util::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
util::Status ClientCert::CreateWithDrmCertificate(
|
||||||
|
const DrmRootCertificate* root_certificate, const std::string& drm_certificate,
|
||||||
|
ClientCert** client_cert) {
|
||||||
|
CHECK(client_cert);
|
||||||
|
*client_cert = nullptr;
|
||||||
|
|
||||||
|
std::unique_ptr<CertificateClientCert> new_client_cert(
|
||||||
|
new CertificateClientCert);
|
||||||
|
util::Status status =
|
||||||
|
new_client_cert->Initialize(root_certificate, drm_certificate);
|
||||||
|
if (!status.ok()) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
*client_cert = new_client_cert.release();
|
||||||
|
return util::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientCert::CreateSignature(const std::string& message, std::string* signature) {
|
||||||
|
DCHECK(signature);
|
||||||
|
DCHECK(!signing_key().empty());
|
||||||
|
if (signature == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
using crypto_util::CreateSignatureHmacSha256;
|
||||||
|
*signature =
|
||||||
|
CreateSignatureHmacSha256(GetServerSigningKey(signing_key()), message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientCert::GenerateSigningKey(const std::string& message,
|
||||||
|
ProtocolVersion protocol_version) {
|
||||||
|
if (!signing_key_.empty()) return;
|
||||||
|
DCHECK(!key().empty());
|
||||||
|
using crypto_util::DeriveKey;
|
||||||
|
using crypto_util::kSigningKeyLabel;
|
||||||
|
set_signing_key(DeriveKey(key(), kSigningKeyLabel, message,
|
||||||
|
SigningKeyMaterialSize(protocol_version)));
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyboxClientCert::KeyboxClientCert() {}
|
||||||
|
|
||||||
|
KeyboxClientCert::~KeyboxClientCert() {}
|
||||||
|
|
||||||
|
void KeyboxClientCert::SetPreProvisioningKeys(
|
||||||
|
const std::multimap<uint32_t, std::string>& keymap) {
|
||||||
|
std::vector<WvmTokenHandler::PreprovKey> keyvector;
|
||||||
|
keyvector.reserve(keymap.size());
|
||||||
|
for (std::multimap<uint32_t, std::string>::const_iterator it = keymap.begin();
|
||||||
|
it != keymap.end(); ++it) {
|
||||||
|
std::string key = absl::HexStringToBytes(it->second);
|
||||||
|
DCHECK_EQ(key.size(), 16);
|
||||||
|
keyvector.push_back(WvmTokenHandler::PreprovKey(it->first, key));
|
||||||
|
}
|
||||||
|
WvmTokenHandler::SetPreprovKeys(keyvector);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KeyboxClientCert::IsSystemIdKnown(const uint32_t system_id) {
|
||||||
|
return WvmTokenHandler::IsSystemIdKnown(system_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t KeyboxClientCert::GetSystemId(const std::string& keybox_bytes) {
|
||||||
|
return WvmTokenHandler::GetSystemId(keybox_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
util::Status KeyboxClientCert::Initialize(const std::string& keybox_bytes) {
|
||||||
|
if (keybox_bytes.size() < kKeyboxSizeBytes) {
|
||||||
|
return util::Status(error_space, INVALID_KEYBOX_TOKEN,
|
||||||
|
"keybox-token-is-too-short");
|
||||||
|
}
|
||||||
|
|
||||||
|
set_system_id(WvmTokenHandler::GetSystemId(keybox_bytes));
|
||||||
|
set_serial_number(WvmTokenHandler::GetEncryptedUniqueId(keybox_bytes));
|
||||||
|
bool insecure_keybox = false;
|
||||||
|
util::Status status = WvmTokenHandler::DecryptDeviceKey(
|
||||||
|
keybox_bytes, &device_key_, nullptr, &insecure_keybox);
|
||||||
|
if (!status.ok()) {
|
||||||
|
Errors new_code = status.error_code() == util::error::NOT_FOUND
|
||||||
|
? MISSING_PRE_PROV_KEY
|
||||||
|
: KEYBOX_DECRYPT_ERROR;
|
||||||
|
return util::Status(error_space, new_code, status.error_message());
|
||||||
|
}
|
||||||
|
return util::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
util::Status KeyboxClientCert::VerifySignature(
|
||||||
|
const std::string& message, const std::string& signature,
|
||||||
|
ProtocolVersion protocol_version) {
|
||||||
|
DCHECK(!signing_key().empty());
|
||||||
|
using crypto_util::VerifySignatureHmacSha256;
|
||||||
|
if (!VerifySignatureHmacSha256(
|
||||||
|
GetClientSigningKey(signing_key(), protocol_version), signature,
|
||||||
|
message)) {
|
||||||
|
return util::Status(error_space, INVALID_SIGNATURE, "invalid-keybox-mac");
|
||||||
|
}
|
||||||
|
return util::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
CertificateClientCert::CertificateClientCert() {}
|
||||||
|
|
||||||
|
CertificateClientCert::~CertificateClientCert() {}
|
||||||
|
|
||||||
|
util::Status CertificateClientCert::Initialize(
|
||||||
|
const DrmRootCertificate* drm_root_certificate,
|
||||||
|
const std::string& serialized_certificate) {
|
||||||
|
CHECK(drm_root_certificate);
|
||||||
|
|
||||||
|
SignedDrmCertificate signed_device_cert;
|
||||||
|
DrmCertificate device_cert;
|
||||||
|
util::Status status = drm_root_certificate->VerifyCertificate(
|
||||||
|
serialized_certificate, &signed_device_cert, &device_cert);
|
||||||
|
if (!status.ok()) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SignedDrmCertificate& signer = signed_device_cert.signer();
|
||||||
|
DrmCertificate model_certificate;
|
||||||
|
if (!model_certificate.ParseFromString(signer.drm_certificate())) {
|
||||||
|
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
|
"drm-certificate-invalid-signer");
|
||||||
|
}
|
||||||
|
if (!model_certificate.has_serial_number()) {
|
||||||
|
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
|
"missing-signer-serial-number");
|
||||||
|
}
|
||||||
|
// Check to see if this model certificate is signed by a
|
||||||
|
// provisioner (entity using Widevine Provisioning Server SDK).
|
||||||
|
if (signer.has_signer()) {
|
||||||
|
DrmCertificate provisioner_certificate;
|
||||||
|
if (!provisioner_certificate.ParseFromString(
|
||||||
|
signer.signer().drm_certificate())) {
|
||||||
|
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
|
"model-certificate-invalid-signer");
|
||||||
|
}
|
||||||
|
if (provisioner_certificate.type() == DrmCertificate::PROVISIONER) {
|
||||||
|
set_signed_by_provisioner(true);
|
||||||
|
} else {
|
||||||
|
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
|
"expected-provisioning-provider-certificate-type");
|
||||||
|
}
|
||||||
|
if (!provisioner_certificate.has_provider_id() ||
|
||||||
|
provisioner_certificate.provider_id().empty()) {
|
||||||
|
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
|
"missing-provisioning-service-id");
|
||||||
|
}
|
||||||
|
set_service_id(provisioner_certificate.provider_id());
|
||||||
|
}
|
||||||
|
set_signer_serial_number(model_certificate.serial_number());
|
||||||
|
set_signer_creation_time_seconds(model_certificate.creation_time_seconds());
|
||||||
|
if (!model_certificate.has_system_id()) {
|
||||||
|
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
|
"model-certificate-missing-system-id");
|
||||||
|
}
|
||||||
|
set_system_id(model_certificate.system_id());
|
||||||
|
set_serial_number(device_cert.serial_number());
|
||||||
|
set_public_key(device_cert.public_key());
|
||||||
|
rsa_public_key_.reset(RsaPublicKey::Create(public_key()));
|
||||||
|
if (rsa_public_key_ == nullptr) {
|
||||||
|
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
|
"drm-certificate-public-key-failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(user): Move this somewhere else. It is license protocol.
|
||||||
|
set_key(Random16Bytes());
|
||||||
|
if (!rsa_public_key_->Encrypt(key(), &encrypted_session_key_)) {
|
||||||
|
return util::Status(error_space, ENCRYPT_ERROR,
|
||||||
|
"drm-certificate-failed-encrypt-session-key");
|
||||||
|
}
|
||||||
|
|
||||||
|
return util::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
util::Status CertificateClientCert::VerifySignature(
|
||||||
|
const std::string& message, const std::string& signature,
|
||||||
|
ProtocolVersion protocol_version) {
|
||||||
|
CHECK(rsa_public_key_);
|
||||||
|
|
||||||
|
if (!rsa_public_key_->VerifySignature(message, signature)) {
|
||||||
|
return util::Status(error_space, INVALID_SIGNATURE, "");
|
||||||
|
}
|
||||||
|
return util::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace widevine
|
||||||
@@ -6,8 +6,8 @@
|
|||||||
// widevine-licensing@google.com.
|
// widevine-licensing@google.com.
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifndef LICENSE_SERVER_SDK_INTERNAL_CLIENT_CERT_H__
|
#ifndef COMMON_CLIENT_CERT_H__
|
||||||
#define LICENSE_SERVER_SDK_INTERNAL_CLIENT_CERT_H__
|
#define COMMON_CLIENT_CERT_H__
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
|
|
||||||
|
class DrmRootCertificate;
|
||||||
class SignedDrmCertificate;
|
class SignedDrmCertificate;
|
||||||
|
|
||||||
// Handler class for LicenseRequests; validates requests and encrypts licenses.
|
// Handler class for LicenseRequests; validates requests and encrypts licenses.
|
||||||
@@ -29,22 +30,25 @@ class ClientCert {
|
|||||||
public:
|
public:
|
||||||
virtual ~ClientCert() {}
|
virtual ~ClientCert() {}
|
||||||
static util::Status Create(
|
static util::Status Create(
|
||||||
|
const DrmRootCertificate* root_certificate,
|
||||||
widevine::ClientIdentification::TokenType token_type,
|
widevine::ClientIdentification::TokenType token_type,
|
||||||
const std::string& token, ClientCert** client_cert);
|
const std::string& token, ClientCert** client_cert);
|
||||||
// Creates a Keybox based ClientCert.
|
// Creates a Keybox based ClientCert.
|
||||||
static util::Status CreateWithToken(const std::string& keybox_token,
|
static util::Status CreateWithKeybox(const std::string& keybox_token,
|
||||||
ClientCert** client_cert);
|
ClientCert** client_cert);
|
||||||
// Creates a Device Certificate based ClientCert.
|
// Creates a Device Certificate based ClientCert.
|
||||||
static util::Status CreateCertificateClientCert(const std::string& drm_certificate,
|
static util::Status CreateWithDrmCertificate(
|
||||||
ClientCert** client_cert);
|
const DrmRootCertificate* root_certificate, const std::string& drm_certificate,
|
||||||
|
ClientCert** client_cert);
|
||||||
// Creates a HMAC SHA256 signature based on the message and the key().
|
// Creates a HMAC SHA256 signature based on the message and the key().
|
||||||
// signature is owned by the caller and can not be NULL.
|
// signature is owned by the caller and can not be NULL.
|
||||||
virtual void CreateSignature(const std::string& message, std::string* signature);
|
virtual void CreateSignature(const std::string& message, std::string* signature);
|
||||||
// Checks the passed in signature against a signature created used the
|
// Checks the passed in signature against a signature created used the
|
||||||
// classes information and the passed in message. Returns true if signature
|
// classes information and the passed in message. Returns OK if signature
|
||||||
// is valid.
|
// is valid.
|
||||||
virtual bool VerifySignature(const std::string& message, const std::string& signature,
|
virtual util::Status VerifySignature(const std::string& message,
|
||||||
ProtocolVersion protocol_version) = 0;
|
const std::string& signature,
|
||||||
|
ProtocolVersion protocol_version) = 0;
|
||||||
// Creates a signing_key that is accessible using signing_key(). Signing_key
|
// Creates a signing_key that is accessible using signing_key(). Signing_key
|
||||||
// is constructed by doing a key derivation using the key() and message.
|
// is constructed by doing a key derivation using the key() and message.
|
||||||
virtual void GenerateSigningKey(const std::string& message,
|
virtual void GenerateSigningKey(const std::string& message,
|
||||||
@@ -67,7 +71,6 @@ class ClientCert {
|
|||||||
virtual uint32_t signer_creation_time_seconds() const {
|
virtual uint32_t signer_creation_time_seconds() const {
|
||||||
return signer_creation_time_seconds_;
|
return signer_creation_time_seconds_;
|
||||||
}
|
}
|
||||||
virtual const util::Status& status() const { return status_; }
|
|
||||||
virtual widevine::ClientIdentification::TokenType type() const = 0;
|
virtual widevine::ClientIdentification::TokenType type() const = 0;
|
||||||
virtual std::string service_id() const { return service_id_; }
|
virtual std::string service_id() const { return service_id_; }
|
||||||
virtual bool signed_by_provisioner() const { return signed_by_provisioner_; }
|
virtual bool signed_by_provisioner() const { return signed_by_provisioner_; }
|
||||||
@@ -79,7 +82,6 @@ class ClientCert {
|
|||||||
virtual void set_signing_key(const std::string& signing_key) {
|
virtual void set_signing_key(const std::string& signing_key) {
|
||||||
signing_key_ = signing_key;
|
signing_key_ = signing_key;
|
||||||
}
|
}
|
||||||
virtual void set_status(const util::Status& status) { status_ = status; }
|
|
||||||
virtual void set_service_id(const std::string& service_id) {
|
virtual void set_service_id(const std::string& service_id) {
|
||||||
service_id_ = service_id;
|
service_id_ = service_id;
|
||||||
}
|
}
|
||||||
@@ -96,7 +98,6 @@ class ClientCert {
|
|||||||
private:
|
private:
|
||||||
uint32_t system_id_ = 0;
|
uint32_t system_id_ = 0;
|
||||||
std::string signing_key_;
|
std::string signing_key_;
|
||||||
util::Status status_;
|
|
||||||
std::string service_id_;
|
std::string service_id_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(ClientCert);
|
DISALLOW_COPY_AND_ASSIGN(ClientCert);
|
||||||
@@ -117,8 +118,10 @@ class KeyboxClientCert : public ClientCert {
|
|||||||
static bool IsSystemIdKnown(const uint32_t system_id);
|
static bool IsSystemIdKnown(const uint32_t system_id);
|
||||||
static uint32_t GetSystemId(const std::string& keybox_bytes);
|
static uint32_t GetSystemId(const std::string& keybox_bytes);
|
||||||
|
|
||||||
bool VerifySignature(const std::string& message, const std::string& signature,
|
util::Status Initialize(const std::string& keybox_bytes);
|
||||||
ProtocolVersion protocol_version) override;
|
|
||||||
|
util::Status VerifySignature(const std::string& message, const std::string& signature,
|
||||||
|
ProtocolVersion protocol_version) override;
|
||||||
const std::string& key() const override { return device_key_; }
|
const std::string& key() const override { return device_key_; }
|
||||||
void set_key(const std::string& key) override { device_key_ = key; }
|
void set_key(const std::string& key) override { device_key_ = key; }
|
||||||
const std::string& encrypted_key() const override { return encrypted_device_key_; }
|
const std::string& encrypted_key() const override { return encrypted_device_key_; }
|
||||||
@@ -127,14 +130,15 @@ class KeyboxClientCert : public ClientCert {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
KeyboxClientCert();
|
||||||
|
|
||||||
friend class ClientCert;
|
friend class ClientCert;
|
||||||
friend class MockKeyboxClientCert;
|
friend class MockKeyboxClientCert;
|
||||||
explicit KeyboxClientCert(const std::string& keybox_bytes);
|
|
||||||
|
|
||||||
std::string device_key_;
|
std::string device_key_;
|
||||||
std::string encrypted_device_key_;
|
std::string encrypted_device_key_;
|
||||||
|
|
||||||
DISALLOW_IMPLICIT_CONSTRUCTORS(KeyboxClientCert);
|
DISALLOW_COPY_AND_ASSIGN(KeyboxClientCert);
|
||||||
};
|
};
|
||||||
// This class implements the device certificate operations based on RSA keys.
|
// This class implements the device certificate operations based on RSA keys.
|
||||||
// It will unpack token and perform all the crypto operations for securing
|
// It will unpack token and perform all the crypto operations for securing
|
||||||
@@ -143,11 +147,9 @@ using widevine::RsaPublicKey;
|
|||||||
class CertificateClientCert : public ClientCert {
|
class CertificateClientCert : public ClientCert {
|
||||||
public:
|
public:
|
||||||
~CertificateClientCert() override;
|
~CertificateClientCert() override;
|
||||||
// Sets the root certificate for certificate validation.
|
|
||||||
static util::Status SetDrmRootCertificatePublicKey(
|
util::Status VerifySignature(const std::string& message, const std::string& signature,
|
||||||
const std::string& root_public_key);
|
ProtocolVersion protocol_version) override;
|
||||||
bool VerifySignature(const std::string& message, const std::string& signature,
|
|
||||||
ProtocolVersion protocol_version) override;
|
|
||||||
const std::string& key() const override { return session_key_; }
|
const std::string& key() const override { return session_key_; }
|
||||||
void set_key(const std::string& key) override { session_key_ = key; }
|
void set_key(const std::string& key) override { session_key_ = key; }
|
||||||
const std::string& encrypted_key() const override {
|
const std::string& encrypted_key() const override {
|
||||||
@@ -160,9 +162,8 @@ class CertificateClientCert : public ClientCert {
|
|||||||
protected:
|
protected:
|
||||||
friend class ClientCert;
|
friend class ClientCert;
|
||||||
friend class MockCertificateClientCert;
|
friend class MockCertificateClientCert;
|
||||||
explicit CertificateClientCert(const std::string& signed_drm_certificate_bytes);
|
util::Status Initialize(const DrmRootCertificate* drm_root_certificate,
|
||||||
util::Status ValidateCertificate(
|
const std::string& serialized_certificate);
|
||||||
const SignedDrmCertificate& signed_drm_certificate);
|
|
||||||
virtual void set_public_key(const std::string& public_key) {
|
virtual void set_public_key(const std::string& public_key) {
|
||||||
public_key_ = public_key;
|
public_key_ = public_key;
|
||||||
}
|
}
|
||||||
@@ -172,45 +173,16 @@ class CertificateClientCert : public ClientCert {
|
|||||||
virtual void set_signer_creation_time_seconds(uint32_t creation_time_seconds) {
|
virtual void set_signer_creation_time_seconds(uint32_t creation_time_seconds) {
|
||||||
signer_creation_time_seconds_ = creation_time_seconds;
|
signer_creation_time_seconds_ = creation_time_seconds;
|
||||||
}
|
}
|
||||||
// This method checks to see if a cached signature for the signer certificate
|
|
||||||
// exists. The cache is populated by the ValidateSignature method, below.
|
|
||||||
// - serial_number is the signer (intermediate) certificate serial number.
|
|
||||||
// This method does a cached signature lookup using this value as the key.
|
|
||||||
// - certificate is the serialized signer certificate. This method compares
|
|
||||||
// this value to the value cached to determine whether there is a match.
|
|
||||||
// - signature is the signature for the serialized signer certificate. This
|
|
||||||
// method compares this value to the value cached to determine whether
|
|
||||||
// there is a match.
|
|
||||||
// Returns true if there exists a matching cached signature for the signer
|
|
||||||
// certificate with the specified serial number, serialized
|
|
||||||
// DrmCertificate, and serialized DrmCertificate signature.
|
|
||||||
// Returns false otherwise.
|
|
||||||
virtual bool CheckSignerCache(const std::string& serial_number,
|
|
||||||
const std::string& certificate,
|
|
||||||
const std::string& signature) const;
|
|
||||||
// This method verifies the signature of a signer (intermediate) certificate,
|
|
||||||
// caching it in the signer cache if verification succeeds.
|
|
||||||
// - serial_number is the signer (intermediate) certificate serial number.
|
|
||||||
// - certificate is the serialized signer certificate.
|
|
||||||
// - signature is the signature for the serialized signer certificate, signed
|
|
||||||
// with the root certificate private key.
|
|
||||||
// Returns util::Status::OK and caches the validated signer information in
|
|
||||||
// the signer cache if signature validation succeeds. Otherwise, returns
|
|
||||||
virtual util::Status ValidateSigner(const std::string& serial_number,
|
|
||||||
const std::string& certificate,
|
|
||||||
const std::string& signature);
|
|
||||||
|
|
||||||
// The below two functions are only used for testing.
|
|
||||||
static void ResetSignerCache();
|
|
||||||
static size_t SignerCacheSize();
|
|
||||||
|
|
||||||
std::string session_key_;
|
std::string session_key_;
|
||||||
std::string encrypted_session_key_;
|
std::string encrypted_session_key_;
|
||||||
std::unique_ptr<RsaPublicKey> rsa_public_key_;
|
std::unique_ptr<RsaPublicKey> rsa_public_key_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DISALLOW_IMPLICIT_CONSTRUCTORS(CertificateClientCert);
|
CertificateClientCert();
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(CertificateClientCert);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
#endif // LICENSE_SERVER_SDK_INTERNAL_CLIENT_CERT_H__
|
#endif // COMMON_CLIENT_CERT_H__
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
// widevine-licensing@google.com.
|
// widevine-licensing@google.com.
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include "license_server_sdk/internal/client_cert.h"
|
#include "common/client_cert.h"
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -47,8 +47,8 @@ class ClientCertTest : public ::testing::Test {
|
|||||||
wvm_test_keys::GetPreprovKeyMultimap());
|
wvm_test_keys::GetPreprovKeyMultimap());
|
||||||
setup_preprov_keys_ = true;
|
setup_preprov_keys_ = true;
|
||||||
}
|
}
|
||||||
CHECK_OK(CertificateClientCert::SetDrmRootCertificatePublicKey(
|
ASSERT_OK(
|
||||||
test_keys_.public_test_key_1_3072_bits()));
|
DrmRootCertificate::CreateByType(kCertificateTypeTesting, &root_cert_));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -112,6 +112,7 @@ class ClientCertTest : public ::testing::Test {
|
|||||||
const std::string& serial_number);
|
const std::string& serial_number);
|
||||||
|
|
||||||
RsaTestKeys test_keys_;
|
RsaTestKeys test_keys_;
|
||||||
|
std::unique_ptr<DrmRootCertificate> root_cert_;
|
||||||
static bool setup_preprov_keys_;
|
static bool setup_preprov_keys_;
|
||||||
};
|
};
|
||||||
bool ClientCertTest::setup_preprov_keys_(false);
|
bool ClientCertTest::setup_preprov_keys_(false);
|
||||||
@@ -126,11 +127,12 @@ void ClientCertTest::TestBasicValidation(const TestTokenAndKeys& expectation,
|
|||||||
// Two ways to create a client cert object, test both.
|
// Two ways to create a client cert object, test both.
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
status = ClientCert::Create(ClientIdentification::KEYBOX,
|
status =
|
||||||
expectation.token_, &client_cert_ptr);
|
ClientCert::Create(root_cert_.get(), ClientIdentification::KEYBOX,
|
||||||
|
expectation.token_, &client_cert_ptr);
|
||||||
} else {
|
} else {
|
||||||
status =
|
status =
|
||||||
ClientCert::CreateWithToken(expectation.token_, &client_cert_ptr);
|
ClientCert::CreateWithKeybox(expectation.token_, &client_cert_ptr);
|
||||||
}
|
}
|
||||||
std::unique_ptr<ClientCert> keybox_cert(client_cert_ptr);
|
std::unique_ptr<ClientCert> keybox_cert(client_cert_ptr);
|
||||||
if (expect_success) {
|
if (expect_success) {
|
||||||
@@ -151,10 +153,16 @@ void ClientCertTest::TestBasicValidation(const TestTokenAndKeys& expectation,
|
|||||||
|
|
||||||
void ClientCertTest::TestBasicValidationDrmCertificate(
|
void ClientCertTest::TestBasicValidationDrmCertificate(
|
||||||
const TestCertificateAndData& expectation, const bool compare_data) {
|
const TestCertificateAndData& expectation, const bool compare_data) {
|
||||||
|
// Reset DRM certificate signature cache since some certificates get
|
||||||
|
// re-generated.
|
||||||
|
ASSERT_OK(
|
||||||
|
DrmRootCertificate::CreateByType(kCertificateTypeTesting, &root_cert_));
|
||||||
|
|
||||||
// Test validation of a valid request.
|
// Test validation of a valid request.
|
||||||
util::Status status;
|
util::Status status;
|
||||||
ClientCert* client_cert_ptr = nullptr;
|
ClientCert* client_cert_ptr = nullptr;
|
||||||
status = ClientCert::Create(ClientIdentification::DRM_DEVICE_CERTIFICATE,
|
status = ClientCert::Create(root_cert_.get(),
|
||||||
|
ClientIdentification::DRM_DEVICE_CERTIFICATE,
|
||||||
expectation.certificate_, &client_cert_ptr);
|
expectation.certificate_, &client_cert_ptr);
|
||||||
std::unique_ptr<ClientCert> drm_certificate_cert(client_cert_ptr);
|
std::unique_ptr<ClientCert> drm_certificate_cert(client_cert_ptr);
|
||||||
ASSERT_EQ(expectation.expected_status_, status);
|
ASSERT_EQ(expectation.expected_status_, status);
|
||||||
@@ -244,7 +252,7 @@ DrmCertificate* ClientCertTest::GenerateProvisionerCertificate(
|
|||||||
provisioner_certificate->set_serial_number(serial_number);
|
provisioner_certificate->set_serial_number(serial_number);
|
||||||
// TODO(user): Need to generate 3072 bit test for provisioner certificates.
|
// TODO(user): Need to generate 3072 bit test for provisioner certificates.
|
||||||
provisioner_certificate->set_public_key(
|
provisioner_certificate->set_public_key(
|
||||||
test_keys_.public_test_key_2_2048_bits());
|
test_keys_.public_test_key_1_3072_bits());
|
||||||
provisioner_certificate->set_system_id(system_id);
|
provisioner_certificate->set_system_id(system_id);
|
||||||
provisioner_certificate->set_provider_id(provider_id);
|
provisioner_certificate->set_provider_id(provider_id);
|
||||||
provisioner_certificate->set_creation_time_seconds(1234);
|
provisioner_certificate->set_creation_time_seconds(1234);
|
||||||
@@ -343,13 +351,6 @@ TEST_F(ClientCertTest, InvalidCertificate) {
|
|||||||
invalid_drm_cert->mutable_signature());
|
invalid_drm_cert->mutable_signature());
|
||||||
invalid_drm_cert->set_allocated_signer(
|
invalid_drm_cert->set_allocated_signer(
|
||||||
GenerateSignedIntermediateCertificate(nullptr, system_id, signer_sn));
|
GenerateSignedIntermediateCertificate(nullptr, system_id, signer_sn));
|
||||||
// Missing system ID.
|
|
||||||
dev_cert.reset(GenerateDrmCertificate(system_id, device_sn));
|
|
||||||
dev_cert->clear_system_id();
|
|
||||||
std::unique_ptr<SignedDrmCertificate> no_system_id(SignCertificate(
|
|
||||||
*dev_cert.get(),
|
|
||||||
GenerateSignedIntermediateCertificate(nullptr, system_id, signer_sn),
|
|
||||||
test_keys_.private_test_key_2_2048_bits()));
|
|
||||||
// Invalid device public key.
|
// Invalid device public key.
|
||||||
dev_cert.reset(GenerateDrmCertificate(system_id, device_sn));
|
dev_cert.reset(GenerateDrmCertificate(system_id, device_sn));
|
||||||
dev_cert->set_public_key("bad-device-public-key");
|
dev_cert->set_public_key("bad-device-public-key");
|
||||||
@@ -383,6 +384,15 @@ TEST_F(ClientCertTest, InvalidCertificate) {
|
|||||||
GenerateSignedIntermediateCertificate(nullptr, system_id, signer_sn),
|
GenerateSignedIntermediateCertificate(nullptr, system_id, signer_sn),
|
||||||
system_id, device_sn));
|
system_id, device_sn));
|
||||||
bad_device_signature->set_signature("bad-signature");
|
bad_device_signature->set_signature("bad-signature");
|
||||||
|
// Missing model system ID.
|
||||||
|
dev_cert.reset(GenerateDrmCertificate(system_id, device_sn));
|
||||||
|
signer_cert.reset(GenerateIntermediateCertificate(system_id, signer_sn));
|
||||||
|
signer_cert->clear_system_id();
|
||||||
|
std::unique_ptr<SignedDrmCertificate> missing_model_sn(SignCertificate(
|
||||||
|
*dev_cert,
|
||||||
|
SignCertificate(*signer_cert, nullptr,
|
||||||
|
test_keys_.private_test_key_1_3072_bits()),
|
||||||
|
test_keys_.private_test_key_2_2048_bits()));
|
||||||
// Missing signer serial number.
|
// Missing signer serial number.
|
||||||
dev_cert.reset(GenerateDrmCertificate(system_id, device_sn));
|
dev_cert.reset(GenerateDrmCertificate(system_id, device_sn));
|
||||||
signer_cert.reset(GenerateIntermediateCertificate(system_id, signer_sn));
|
signer_cert.reset(GenerateIntermediateCertificate(system_id, signer_sn));
|
||||||
@@ -404,36 +414,32 @@ TEST_F(ClientCertTest, InvalidCertificate) {
|
|||||||
const TestCertificateAndData kInvalidCertificate[] = {
|
const TestCertificateAndData kInvalidCertificate[] = {
|
||||||
TestCertificateAndData("f", "", 0,
|
TestCertificateAndData("f", "", 0,
|
||||||
util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"device-certificate-invalid-token")),
|
"invalid-signed-drm-certificate")),
|
||||||
TestCertificateAndData(invalid_drm_cert->SerializeAsString(), "", 0,
|
TestCertificateAndData(invalid_drm_cert->SerializeAsString(), "", 0,
|
||||||
util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"device-certificate-invalid")),
|
"invalid-drm-certificate")),
|
||||||
TestCertificateAndData(
|
TestCertificateAndData(bad_device_public_key->SerializeAsString(), "", 0,
|
||||||
no_system_id->SerializeAsString(), "", 0,
|
util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
"drm-certificate-public-key-failed")),
|
||||||
"device-certificate-missing-system-id")),
|
|
||||||
TestCertificateAndData(
|
|
||||||
bad_device_public_key->SerializeAsString(), "", 0,
|
|
||||||
util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
|
||||||
"device-certificate-public-key-failed")),
|
|
||||||
TestCertificateAndData(invalid_signer->SerializeAsString(), "", 0,
|
TestCertificateAndData(invalid_signer->SerializeAsString(), "", 0,
|
||||||
util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"device-certificate-invalid-signer")),
|
"invalid-signer-certificate")),
|
||||||
|
TestCertificateAndData(bad_signer_public_key->SerializeAsString(), "", 0,
|
||||||
|
util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
|
"invalid-leaf-signer-public-key")),
|
||||||
|
TestCertificateAndData(bad_device_signature->SerializeAsString(), "", 0,
|
||||||
|
util::Status(error_space, INVALID_SIGNATURE,
|
||||||
|
"cache-miss-invalid-signature")),
|
||||||
TestCertificateAndData(
|
TestCertificateAndData(
|
||||||
bad_signer_public_key->SerializeAsString(), "", 0,
|
missing_model_sn->SerializeAsString(), "", 0,
|
||||||
util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"signer-certificate-public-key-failed")),
|
"model-certificate-missing-system-id")),
|
||||||
TestCertificateAndData(
|
|
||||||
bad_device_signature->SerializeAsString(), "", 0,
|
|
||||||
util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
|
||||||
"device-certificate-verification-failed")),
|
|
||||||
TestCertificateAndData(missing_signer_sn->SerializeAsString(), "", 0,
|
TestCertificateAndData(missing_signer_sn->SerializeAsString(), "", 0,
|
||||||
util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"missing-signer-serial-number")),
|
"missing-signer-serial-number")),
|
||||||
TestCertificateAndData(
|
TestCertificateAndData(bad_signer_signature->SerializeAsString(), "", 0,
|
||||||
bad_signer_signature->SerializeAsString(), "", 0,
|
util::Status(error_space, INVALID_SIGNATURE,
|
||||||
util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
"cache-miss-invalid-signature")),
|
||||||
"signer-certificate-verification-failed")),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for (size_t i = 0; i < ABSL_ARRAYSIZE(kInvalidCertificate); ++i) {
|
for (size_t i = 0; i < ABSL_ARRAYSIZE(kInvalidCertificate); ++i) {
|
||||||
@@ -441,41 +447,6 @@ TEST_F(ClientCertTest, InvalidCertificate) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MockCertificateClientCert : public CertificateClientCert {
|
|
||||||
public:
|
|
||||||
using CertificateClientCert::ResetSignerCache;
|
|
||||||
using CertificateClientCert::SignerCacheSize;
|
|
||||||
|
|
||||||
explicit MockCertificateClientCert(const std::string& cert_bytes)
|
|
||||||
: CertificateClientCert(cert_bytes) {}
|
|
||||||
MOCK_METHOD3(ValidateSigner, util::Status(const std::string& serial_number,
|
|
||||||
const std::string& certificate,
|
|
||||||
const std::string& signature));
|
|
||||||
util::Status CallValidateCertificate(
|
|
||||||
const SignedDrmCertificate& signed_drm_certificate) {
|
|
||||||
return ValidateCertificate(signed_drm_certificate);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(ClientCertTest, SignerCache) {
|
|
||||||
const uint32_t system_id = 1234;
|
|
||||||
const std::string serial_number("serial-number");
|
|
||||||
std::unique_ptr<SignedDrmCertificate> signed_cert(
|
|
||||||
GenerateSignedDrmCertificate(GenerateSignedIntermediateCertificate(
|
|
||||||
nullptr, system_id, serial_number),
|
|
||||||
system_id, serial_number + "-device"));
|
|
||||||
// TODO(user): Remove work from the ClientCert constructors to make it
|
|
||||||
// more testable, and because it's just bad practice.
|
|
||||||
MockCertificateClientCert::ResetSignerCache();
|
|
||||||
MockCertificateClientCert client_cert(signed_cert->SerializeAsString());
|
|
||||||
EXPECT_EQ(1, MockCertificateClientCert::SignerCacheSize());
|
|
||||||
EXPECT_CALL(client_cert, ValidateSigner(_, _, _))
|
|
||||||
.Times(0)
|
|
||||||
.WillRepeatedly(Return(util::OkStatus()));
|
|
||||||
EXPECT_EQ(util::OkStatus(),
|
|
||||||
client_cert.CallValidateCertificate(*signed_cert));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ClientCertTest, MissingPreProvKey) {
|
TEST_F(ClientCertTest, MissingPreProvKey) {
|
||||||
// system ID in token is 0x01234567
|
// system ID in token is 0x01234567
|
||||||
const std::string token(absl::HexStringToBytes(
|
const std::string token(absl::HexStringToBytes(
|
||||||
@@ -483,12 +454,12 @@ TEST_F(ClientCertTest, MissingPreProvKey) {
|
|||||||
"beaa24924907e128f9ff49b54a165cd9c33e6547537eb4d29fb7e8df3c2c1cd9"
|
"beaa24924907e128f9ff49b54a165cd9c33e6547537eb4d29fb7e8df3c2c1cd9"
|
||||||
"2517a12f4922953e"));
|
"2517a12f4922953e"));
|
||||||
ClientCert* client_cert_ptr = nullptr;
|
ClientCert* client_cert_ptr = nullptr;
|
||||||
util::Status status = ClientCert::CreateWithToken(token, &client_cert_ptr);
|
util::Status status = ClientCert::CreateWithKeybox(token, &client_cert_ptr);
|
||||||
ASSERT_EQ(MISSING_PRE_PROV_KEY, status.error_code());
|
ASSERT_EQ(MISSING_PRE_PROV_KEY, status.error_code());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ClientCertTest, ValidProvisionerDeviceCert) {
|
TEST_F(ClientCertTest, ValidProvisionerDeviceCert) {
|
||||||
const uint32_t system_id = 4890;
|
const uint32_t system_id = 5000;
|
||||||
const std::string service_id("widevine_test.com");
|
const std::string service_id("widevine_test.com");
|
||||||
const std::string device_serial_number("device-serial-number");
|
const std::string device_serial_number("device-serial-number");
|
||||||
const std::string intermediate_serial_number("intermediate-serial-number");
|
const std::string intermediate_serial_number("intermediate-serial-number");
|
||||||
@@ -511,7 +482,8 @@ TEST_F(ClientCertTest, ValidProvisionerDeviceCert) {
|
|||||||
signed_device_cert->SerializeToString(&serialized_cert);
|
signed_device_cert->SerializeToString(&serialized_cert);
|
||||||
ClientCert* client_cert_ptr = nullptr;
|
ClientCert* client_cert_ptr = nullptr;
|
||||||
|
|
||||||
EXPECT_OK(ClientCert::Create(ClientIdentification::DRM_DEVICE_CERTIFICATE,
|
EXPECT_OK(ClientCert::Create(root_cert_.get(),
|
||||||
|
ClientIdentification::DRM_DEVICE_CERTIFICATE,
|
||||||
serialized_cert, &client_cert_ptr));
|
serialized_cert, &client_cert_ptr));
|
||||||
ASSERT_TRUE(client_cert_ptr != nullptr);
|
ASSERT_TRUE(client_cert_ptr != nullptr);
|
||||||
std::unique_ptr<ClientCert> drm_cert(client_cert_ptr);
|
std::unique_ptr<ClientCert> drm_cert(client_cert_ptr);
|
||||||
@@ -522,7 +494,7 @@ TEST_F(ClientCertTest, ValidProvisionerDeviceCert) {
|
|||||||
EXPECT_EQ(system_id, drm_cert->system_id());
|
EXPECT_EQ(system_id, drm_cert->system_id());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ClientCertTest, InValidProvisionerDeviceCertEmptyServiceId) {
|
TEST_F(ClientCertTest, InvalidProvisionerDeviceCertEmptyServiceId) {
|
||||||
const uint32_t system_id = 4890;
|
const uint32_t system_id = 4890;
|
||||||
const std::string service_id("");
|
const std::string service_id("");
|
||||||
const std::string device_serial_number("device-serial-number");
|
const std::string device_serial_number("device-serial-number");
|
||||||
@@ -547,13 +519,14 @@ TEST_F(ClientCertTest, InValidProvisionerDeviceCertEmptyServiceId) {
|
|||||||
ClientCert* client_cert_ptr = nullptr;
|
ClientCert* client_cert_ptr = nullptr;
|
||||||
|
|
||||||
EXPECT_EQ("missing-provisioning-service-id",
|
EXPECT_EQ("missing-provisioning-service-id",
|
||||||
ClientCert::Create(ClientIdentification::DRM_DEVICE_CERTIFICATE,
|
ClientCert::Create(root_cert_.get(),
|
||||||
|
ClientIdentification::DRM_DEVICE_CERTIFICATE,
|
||||||
serialized_cert, &client_cert_ptr)
|
serialized_cert, &client_cert_ptr)
|
||||||
.error_message());
|
.error_message());
|
||||||
EXPECT_FALSE(client_cert_ptr);
|
EXPECT_FALSE(client_cert_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ClientCertTest, InValidProvisionerDeviceCertChain) {
|
TEST_F(ClientCertTest, InvalidProvisionerDeviceCertChain) {
|
||||||
const uint32_t system_id = 4890;
|
const uint32_t system_id = 4890;
|
||||||
const uint32_t system_id2 = 4892;
|
const uint32_t system_id2 = 4892;
|
||||||
const std::string service_id("widevine_test.com");
|
const std::string service_id("widevine_test.com");
|
||||||
@@ -580,28 +553,14 @@ TEST_F(ClientCertTest, InValidProvisionerDeviceCertChain) {
|
|||||||
signed_device_cert->SerializeToString(&serialized_cert);
|
signed_device_cert->SerializeToString(&serialized_cert);
|
||||||
ClientCert* client_cert_ptr = nullptr;
|
ClientCert* client_cert_ptr = nullptr;
|
||||||
|
|
||||||
ASSERT_EQ("expected-provisioning-provider-certificate-type",
|
// TODO(user): Fix this test. It is failing for the right reasons, but the
|
||||||
ClientCert::Create(ClientIdentification::DRM_DEVICE_CERTIFICATE,
|
// certificate chain is broken (intermediate signature does not match signer).
|
||||||
|
ASSERT_EQ("cache-miss-invalid-signature",
|
||||||
|
ClientCert::Create(root_cert_.get(),
|
||||||
|
ClientIdentification::DRM_DEVICE_CERTIFICATE,
|
||||||
serialized_cert, &client_cert_ptr)
|
serialized_cert, &client_cert_ptr)
|
||||||
.error_message());
|
.error_message());
|
||||||
EXPECT_FALSE(client_cert_ptr);
|
EXPECT_FALSE(client_cert_ptr);
|
||||||
|
|
||||||
// Make a normal intermediate certificate.
|
|
||||||
signed_intermediate_cert.reset(GenerateSignedIntermediateCertificate(
|
|
||||||
nullptr, system_id, intermediate_serial_number));
|
|
||||||
signed_device_cert.reset(GenerateSignedDrmCertificate(
|
|
||||||
signed_intermediate_cert.release(), system_id, device_serial_number));
|
|
||||||
|
|
||||||
signed_device_cert->SerializeToString(&serialized_cert);
|
|
||||||
EXPECT_OK(ClientCert::Create(ClientIdentification::DRM_DEVICE_CERTIFICATE,
|
|
||||||
serialized_cert, &client_cert_ptr));
|
|
||||||
|
|
||||||
// The service Id should only get set if a provisioning cert exist.
|
|
||||||
std::unique_ptr<ClientCert> drm_cert(client_cert_ptr);
|
|
||||||
EXPECT_TRUE(drm_cert->service_id().empty());
|
|
||||||
EXPECT_EQ(device_serial_number, drm_cert->serial_number());
|
|
||||||
EXPECT_EQ(intermediate_serial_number, drm_cert->signer_serial_number());
|
|
||||||
EXPECT_EQ(system_id, drm_cert->system_id());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
@@ -8,24 +8,32 @@
|
|||||||
|
|
||||||
// Implements the DeviceStatusList class.
|
// Implements the DeviceStatusList class.
|
||||||
|
|
||||||
#include "license_server_sdk/internal/device_status_list.h"
|
#include "common/device_status_list.h"
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "glog/logging.h"
|
#include "glog/logging.h"
|
||||||
|
#include "absl/strings/escaping.h"
|
||||||
|
#include "absl/strings/numbers.h"
|
||||||
#include "absl/strings/str_split.h"
|
#include "absl/strings/str_split.h"
|
||||||
#include "absl/strings/string_view.h"
|
#include "absl/strings/string_view.h"
|
||||||
#include "absl/synchronization/mutex.h"
|
#include "absl/synchronization/mutex.h"
|
||||||
#include "util/gtl/map_util.h"
|
#include "util/gtl/map_util.h"
|
||||||
|
#include "common/client_cert.h"
|
||||||
#include "common/error_space.h"
|
#include "common/error_space.h"
|
||||||
#include "common/rsa_key.h"
|
#include "common/rsa_key.h"
|
||||||
#include "license_server_sdk/internal/client_cert.h"
|
|
||||||
#include "protos/public/client_identification.pb.h"
|
#include "protos/public/client_identification.pb.h"
|
||||||
#include "protos/public/errors.pb.h"
|
#include "protos/public/errors.pb.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const char kSignedListTerminator[] = "}";
|
||||||
|
const char kSignedList[] = "signedList\":";
|
||||||
|
const std::size_t kSignedListLen = strlen(kSignedList);
|
||||||
|
} // namespace
|
||||||
|
|
||||||
DeviceStatusList* DeviceStatusList::Instance() {
|
DeviceStatusList* DeviceStatusList::Instance() {
|
||||||
// TODO(user): This is "ok" according to Google's Coding for Dummies, but
|
// TODO(user): This is "ok" according to Google's Coding for Dummies, but
|
||||||
// we should inject the status list into the sessions. This will require
|
// we should inject the status list into the sessions. This will require
|
||||||
@@ -238,4 +246,76 @@ bool DeviceStatusList::IsRevokedSystemIdAllowed(uint32_t system_id) {
|
|||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
util::Status DeviceStatusList::ExtractFromProvisioningServiceResponse(
|
||||||
|
const std::string& certificate_provisioning_service_response,
|
||||||
|
std::string* signed_certificate_status_list, std::string* certificate_status_list) {
|
||||||
|
util::Status status = util::OkStatus();
|
||||||
|
size_t signed_list_start =
|
||||||
|
certificate_provisioning_service_response.find(kSignedList);
|
||||||
|
if (signed_list_start != std::string::npos) {
|
||||||
|
size_t signed_list_end = certificate_provisioning_service_response.find(
|
||||||
|
kSignedListTerminator, signed_list_start);
|
||||||
|
if (signed_list_end == std::string::npos) {
|
||||||
|
return util::Status(
|
||||||
|
error_space, util::error::INVALID_ARGUMENT,
|
||||||
|
"Unable to parse the certificate_provisioning_service_response. "
|
||||||
|
"SignedList not terminated.");
|
||||||
|
}
|
||||||
|
std::string signed_list(
|
||||||
|
certificate_provisioning_service_response.begin() + signed_list_start +
|
||||||
|
kSignedListLen,
|
||||||
|
certificate_provisioning_service_response.begin() + signed_list_end);
|
||||||
|
|
||||||
|
// Strip off quotes.
|
||||||
|
signed_list.erase(std::remove(signed_list.begin(), signed_list.end(), '\"'),
|
||||||
|
signed_list.end());
|
||||||
|
// Strip off spaces.
|
||||||
|
signed_list.erase(std::remove(signed_list.begin(), signed_list.end(), ' '),
|
||||||
|
signed_list.end());
|
||||||
|
|
||||||
|
// Strip off newlines.
|
||||||
|
signed_list.erase(std::remove(signed_list.begin(), signed_list.end(), '\n'),
|
||||||
|
signed_list.end());
|
||||||
|
|
||||||
|
// Strip off carriage return (the control-M character)
|
||||||
|
signed_list.erase(std::remove(signed_list.begin(), signed_list.end(), '\r'),
|
||||||
|
signed_list.end());
|
||||||
|
if (!absl::WebSafeBase64Unescape(signed_list,
|
||||||
|
signed_certificate_status_list)) {
|
||||||
|
if (!absl::Base64Unescape(signed_list, signed_certificate_status_list)) {
|
||||||
|
return util::Status(error_space, util::error::INVALID_ARGUMENT,
|
||||||
|
"Base64 decode of signedlist failed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// certificate_provisioning_service_response is the signed list and not a
|
||||||
|
// JSON message.
|
||||||
|
if (!absl::WebSafeBase64Unescape(certificate_provisioning_service_response,
|
||||||
|
signed_certificate_status_list)) {
|
||||||
|
if (!absl::Base64Unescape(certificate_provisioning_service_response,
|
||||||
|
signed_certificate_status_list)) {
|
||||||
|
return util::Status(error_space, util::error::INVALID_ARGUMENT,
|
||||||
|
"Base64 decode of certList failed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SignedDeviceCertificateStatusList signed_status_list;
|
||||||
|
if (!signed_status_list.ParseFromString(*signed_certificate_status_list)) {
|
||||||
|
return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
|
||||||
|
"signed-certificate-status-list-parse-error");
|
||||||
|
}
|
||||||
|
if (!signed_status_list.has_certificate_status_list()) {
|
||||||
|
return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
|
||||||
|
"missing-status-list");
|
||||||
|
}
|
||||||
|
DeviceCertificateStatusList device_certificate_status_list;
|
||||||
|
if (!device_certificate_status_list.ParseFromString(
|
||||||
|
signed_status_list.certificate_status_list())) {
|
||||||
|
return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
|
||||||
|
"certificate-status-list-parse-error");
|
||||||
|
}
|
||||||
|
*certificate_status_list = signed_status_list.certificate_status_list();
|
||||||
|
return util::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
@@ -8,8 +8,8 @@
|
|||||||
|
|
||||||
// DeviceStatusList class header.
|
// DeviceStatusList class header.
|
||||||
|
|
||||||
#ifndef LICENSE_SERVER_SDK_INTERNAL_DEVICE_STATUS_LIST_H__
|
#ifndef COMMON_DEVICE_STATUS_LIST_H__
|
||||||
#define LICENSE_SERVER_SDK_INTERNAL_DEVICE_STATUS_LIST_H__
|
#define COMMON_DEVICE_STATUS_LIST_H__
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -36,6 +36,7 @@ class DeviceStatusList {
|
|||||||
|
|
||||||
DeviceStatusList();
|
DeviceStatusList();
|
||||||
virtual ~DeviceStatusList();
|
virtual ~DeviceStatusList();
|
||||||
|
|
||||||
// Takes |signed_certificate_status_list| and copies to an internal map of
|
// Takes |signed_certificate_status_list| and copies to an internal map of
|
||||||
// device certifcate status list. The internal map is used to verify
|
// device certifcate status list. The internal map is used to verify
|
||||||
// a device was not revoked. Returns true is the list was successfully parsed.
|
// a device was not revoked. Returns true is the list was successfully parsed.
|
||||||
@@ -76,6 +77,19 @@ class DeviceStatusList {
|
|||||||
// a comma separated list of systems Ids to allow even if revoked.
|
// a comma separated list of systems Ids to allow even if revoked.
|
||||||
virtual void AllowRevokedDevices(const std::string& system_id_list);
|
virtual void AllowRevokedDevices(const std::string& system_id_list);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses signed device certificate status list and certificate status list
|
||||||
|
* from certificateProvisoningServer response.
|
||||||
|
*
|
||||||
|
* @param certificate_provisioning_service_response
|
||||||
|
* @param signed_certificate_status_list
|
||||||
|
* @param certificate_status_list
|
||||||
|
* @return WvPLStatus - Status::OK if success, else error.
|
||||||
|
*/
|
||||||
|
static util::Status ExtractFromProvisioningServiceResponse(
|
||||||
|
const std::string& certificate_provisioning_service_response,
|
||||||
|
std::string* signed_certificate_status_list, std::string* certificate_status_list);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Returns true if the system ID is allowed to be revoked.
|
// Returns true if the system ID is allowed to be revoked.
|
||||||
// Caller owns |system_id|. They must not be null.
|
// Caller owns |system_id|. They must not be null.
|
||||||
@@ -96,4 +110,4 @@ class DeviceStatusList {
|
|||||||
};
|
};
|
||||||
|
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
#endif // LICENSE_SERVER_SDK_INTERNAL_DEVICE_STATUS_LIST_H__
|
#endif // COMMON_DEVICE_STATUS_LIST_H__
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
// widevine-licensing@google.com.
|
// widevine-licensing@google.com.
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include "license_server_sdk/internal/device_status_list.h"
|
#include "common/device_status_list.h"
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -17,9 +17,9 @@
|
|||||||
#include "testing/gmock.h"
|
#include "testing/gmock.h"
|
||||||
#include "testing/gunit.h"
|
#include "testing/gunit.h"
|
||||||
#include "absl/strings/str_cat.h"
|
#include "absl/strings/str_cat.h"
|
||||||
|
#include "common/client_cert.h"
|
||||||
#include "common/rsa_key.h"
|
#include "common/rsa_key.h"
|
||||||
#include "common/rsa_test_keys.h"
|
#include "common/rsa_test_keys.h"
|
||||||
#include "license_server_sdk/internal/client_cert.h"
|
|
||||||
#include "protos/public/client_identification.pb.h"
|
#include "protos/public/client_identification.pb.h"
|
||||||
#include "protos/public/errors.pb.h"
|
#include "protos/public/errors.pb.h"
|
||||||
#include "protos/public/provisioned_device_info.pb.h"
|
#include "protos/public/provisioned_device_info.pb.h"
|
||||||
@@ -51,7 +51,7 @@ const uint32_t kDefaultExpirePeriod = 0;
|
|||||||
|
|
||||||
class MockCertificateClientCert : public CertificateClientCert {
|
class MockCertificateClientCert : public CertificateClientCert {
|
||||||
public:
|
public:
|
||||||
explicit MockCertificateClientCert() : CertificateClientCert("token-bytes") {}
|
MockCertificateClientCert() {}
|
||||||
MOCK_CONST_METHOD0(system_id, uint32_t());
|
MOCK_CONST_METHOD0(system_id, uint32_t());
|
||||||
MOCK_CONST_METHOD0(signer_serial_number, std::string &());
|
MOCK_CONST_METHOD0(signer_serial_number, std::string &());
|
||||||
MOCK_CONST_METHOD0(signer_creation_time_seconds, uint32_t());
|
MOCK_CONST_METHOD0(signer_creation_time_seconds, uint32_t());
|
||||||
@@ -61,7 +61,7 @@ class MockCertificateClientCert : public CertificateClientCert {
|
|||||||
|
|
||||||
class MockKeyboxClientCert : public KeyboxClientCert {
|
class MockKeyboxClientCert : public KeyboxClientCert {
|
||||||
public:
|
public:
|
||||||
explicit MockKeyboxClientCert() : KeyboxClientCert("token-bytes") {}
|
MockKeyboxClientCert() {}
|
||||||
MOCK_CONST_METHOD0(system_id, uint32_t());
|
MOCK_CONST_METHOD0(system_id, uint32_t());
|
||||||
MOCK_CONST_METHOD0(type, ClientIdentification::TokenType());
|
MOCK_CONST_METHOD0(type, ClientIdentification::TokenType());
|
||||||
};
|
};
|
||||||
@@ -6,23 +6,34 @@
|
|||||||
// widevine-licensing@google.com.
|
// widevine-licensing@google.com.
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// common_typos_disable. Successful / successfull.
|
||||||
|
|
||||||
#include "common/drm_root_certificate.h"
|
#include "common/drm_root_certificate.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "glog/logging.h"
|
#include "glog/logging.h"
|
||||||
|
#include "absl/memory/memory.h"
|
||||||
#include "absl/strings/escaping.h"
|
#include "absl/strings/escaping.h"
|
||||||
#include "openssl/sha.h"
|
#include "absl/synchronization/mutex.h"
|
||||||
#include "common/certificate_type.h"
|
|
||||||
#include "common/error_space.h"
|
#include "common/error_space.h"
|
||||||
#include "common/rsa_key.h"
|
#include "common/rsa_key.h"
|
||||||
|
#include "common/sha_util.h"
|
||||||
#include "protos/public/drm_certificate.pb.h"
|
#include "protos/public/drm_certificate.pb.h"
|
||||||
#include "protos/public/errors.pb.h"
|
#include "protos/public/errors.pb.h"
|
||||||
#include "protos/public/signed_drm_certificate.pb.h"
|
#include "protos/public/signed_drm_certificate.pb.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
|
|
||||||
// From common::TestCertificates.
|
namespace {
|
||||||
|
|
||||||
|
const char kDevelopmentString[] = "dev"; // QA systems.
|
||||||
|
const char kProductionString[] = "prod"; // Production.
|
||||||
|
const char kTestingString[] = "test"; // Code development / unit tests.
|
||||||
|
|
||||||
|
const bool kUseCache = true;
|
||||||
|
|
||||||
|
// From common::TestDrmCertificates.
|
||||||
// TODO(user): common::test_certificates is a testonly target, consider
|
// TODO(user): common::test_certificates is a testonly target, consider
|
||||||
// how to use instead of dupliciating the test cert here.
|
// how to use instead of dupliciating the test cert here.
|
||||||
static const unsigned char kTestRootCertificate[] = {
|
static const unsigned char kTestRootCertificate[] = {
|
||||||
@@ -231,14 +242,145 @@ static const unsigned char kProdRootCertificate[] = {
|
|||||||
0x1f, 0x17, 0x25, 0xce, 0x90, 0xb9, 0x6d, 0xcd, 0xc4, 0x46, 0xf5, 0xa3,
|
0x1f, 0x17, 0x25, 0xce, 0x90, 0xb9, 0x6d, 0xcd, 0xc4, 0x46, 0xf5, 0xa3,
|
||||||
0x62, 0x13, 0x74, 0x02, 0xa7, 0x62, 0xa4, 0xfa, 0x55, 0xd9, 0xde, 0xcf,
|
0x62, 0x13, 0x74, 0x02, 0xa7, 0x62, 0xa4, 0xfa, 0x55, 0xd9, 0xde, 0xcf,
|
||||||
0xa2, 0xe6, 0x80, 0x74, 0x55, 0x06, 0x49, 0xd5, 0x02, 0x0c};
|
0xa2, 0xe6, 0x80, 0x74, 0x55, 0x06, 0x49, 0xd5, 0x02, 0x0c};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
util::Status DrmRootCertificate::Create(
|
// Caches an individual signature for a certificate with a specific serial
|
||||||
const std::string& signed_drm_certificate,
|
// number (signer).
|
||||||
std::unique_ptr<DrmRootCertificate>* cert) {
|
struct VerifiedCertSignature {
|
||||||
|
VerifiedCertSignature(const std::string& cert, const std::string& sig,
|
||||||
|
const std::string& signer_sn)
|
||||||
|
: signed_cert(cert), signature(sig), signer_serial(signer_sn) {}
|
||||||
|
|
||||||
|
std::string signed_cert;
|
||||||
|
std::string signature;
|
||||||
|
std::string signer_serial;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Map of certificate serial number to its signature.
|
||||||
|
typedef std::map<std::string, VerifiedCertSignature> VerifiedCertSignatures;
|
||||||
|
class VerifiedCertSignatureCache {
|
||||||
|
public:
|
||||||
|
explicit VerifiedCertSignatureCache(const RsaKeyFactory* key_factory)
|
||||||
|
: key_factory_(key_factory) {}
|
||||||
|
|
||||||
|
// Checks cache, on miss, uses public key. If successful, adds to
|
||||||
|
// cache.
|
||||||
|
util::Status VerifySignature(const std::string& cert, const std::string& serial_number,
|
||||||
|
const std::string& signature,
|
||||||
|
const std::string& signer_public_key,
|
||||||
|
const std::string& signer_serial_number) {
|
||||||
|
{
|
||||||
|
VerifiedCertSignatures::iterator cached_signature;
|
||||||
|
absl::ReaderMutexLock read_lock(&signature_cache_mutex_);
|
||||||
|
cached_signature = signature_cache_.find(serial_number);
|
||||||
|
if (cached_signature != signature_cache_.end()) {
|
||||||
|
// TODO(user): Log which of the following three conditions occurs.
|
||||||
|
if ((cert != cached_signature->second.signed_cert) ||
|
||||||
|
(signature != cached_signature->second.signature) ||
|
||||||
|
(signer_serial_number != cached_signature->second.signer_serial)) {
|
||||||
|
// Cached signature mismatch.
|
||||||
|
return util::Status(error_space, INVALID_SIGNATURE,
|
||||||
|
"cached-signature-mismatch");
|
||||||
|
}
|
||||||
|
// Cached signature match.
|
||||||
|
return util::OkStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache miss. Verify signature.
|
||||||
|
std::unique_ptr<RsaPublicKey> signer_key(
|
||||||
|
key_factory_->CreateFromPkcs1PublicKey(signer_public_key));
|
||||||
|
if (!signer_key) {
|
||||||
|
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
|
"invalid-signer-public-key");
|
||||||
|
}
|
||||||
|
if (!signer_key->VerifySignature(cert, signature)) {
|
||||||
|
return util::Status(error_space, INVALID_SIGNATURE,
|
||||||
|
"cache-miss-invalid-signature");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add signature to cache.
|
||||||
|
absl::WriterMutexLock write_lock(&signature_cache_mutex_);
|
||||||
|
signature_cache_.emplace(
|
||||||
|
serial_number,
|
||||||
|
VerifiedCertSignature(cert, signature, signer_serial_number));
|
||||||
|
return util::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
VerifiedCertSignatures signature_cache_ GUARDED_BY(&signature_cache_mutex_);
|
||||||
|
absl::Mutex signature_cache_mutex_;
|
||||||
|
const RsaKeyFactory* key_factory_;
|
||||||
|
};
|
||||||
|
|
||||||
|
util::Status DrmRootCertificate::CreateByType(
|
||||||
|
CertificateType cert_type, std::unique_ptr<DrmRootCertificate>* cert) {
|
||||||
CHECK(cert);
|
CHECK(cert);
|
||||||
|
|
||||||
|
return Create(cert_type, absl::make_unique<RsaKeyFactory>(), cert);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<DrmRootCertificate> DrmRootCertificate::CreateByType(
|
||||||
|
CertificateType cert_type, util::Status* status) {
|
||||||
|
CHECK(status);
|
||||||
|
|
||||||
|
std::unique_ptr<DrmRootCertificate> new_root_cert;
|
||||||
|
*status = CreateByType(cert_type, &new_root_cert);
|
||||||
|
return new_root_cert;
|
||||||
|
}
|
||||||
|
|
||||||
|
util::Status DrmRootCertificate::CreateByTypeString(
|
||||||
|
const std::string& cert_type_string, std::unique_ptr<DrmRootCertificate>* cert) {
|
||||||
|
CHECK(cert);
|
||||||
|
|
||||||
|
CertificateType cert_type;
|
||||||
|
if (cert_type_string == kDevelopmentString) {
|
||||||
|
cert_type = kCertificateTypeDevelopment;
|
||||||
|
} else if (cert_type_string == kProductionString) {
|
||||||
|
cert_type = kCertificateTypeProduction;
|
||||||
|
} else if (cert_type_string == kTestingString) {
|
||||||
|
cert_type = kCertificateTypeTesting;
|
||||||
|
} else {
|
||||||
|
return util::Status(
|
||||||
|
error_space, INVALID_PARAMETER,
|
||||||
|
absl::StrCat("invalid-certificate-type ", cert_type_string));
|
||||||
|
}
|
||||||
|
|
||||||
|
return CreateByType(cert_type, cert);
|
||||||
|
}
|
||||||
|
|
||||||
|
util::Status DrmRootCertificate::Create(
|
||||||
|
CertificateType cert_type, std::unique_ptr<RsaKeyFactory> key_factory,
|
||||||
|
std::unique_ptr<DrmRootCertificate>* cert) {
|
||||||
|
DCHECK(cert);
|
||||||
|
|
||||||
|
std::string serialized_certificate;
|
||||||
|
switch (cert_type) {
|
||||||
|
case kCertificateTypeProduction: {
|
||||||
|
serialized_certificate.assign(
|
||||||
|
kProdRootCertificate,
|
||||||
|
kProdRootCertificate + sizeof(kProdRootCertificate));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case kCertificateTypeDevelopment: {
|
||||||
|
serialized_certificate.assign(
|
||||||
|
kDevRootCertificate,
|
||||||
|
kDevRootCertificate + sizeof(kDevRootCertificate));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case kCertificateTypeTesting: {
|
||||||
|
serialized_certificate.assign(
|
||||||
|
kTestRootCertificate,
|
||||||
|
kTestRootCertificate + sizeof(kTestRootCertificate));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return util::Status(error_space, INVALID_PARAMETER,
|
||||||
|
"invalid-certificate-type");
|
||||||
|
}
|
||||||
|
|
||||||
SignedDrmCertificate signed_root_cert;
|
SignedDrmCertificate signed_root_cert;
|
||||||
if (!signed_root_cert.ParseFromString(signed_drm_certificate)) {
|
if (!signed_root_cert.ParseFromString(serialized_certificate)) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"signed-root-cert-deserialize-fail");
|
"signed-root-cert-deserialize-fail");
|
||||||
}
|
}
|
||||||
@@ -259,8 +401,9 @@ util::Status DrmRootCertificate::Create(
|
|||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"missing-root-certificate-signature");
|
"missing-root-certificate-signature");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<RsaPublicKey> public_key(
|
std::unique_ptr<RsaPublicKey> public_key(
|
||||||
RsaPublicKey::Create(root_cert.public_key()));
|
key_factory->CreateFromPkcs1PublicKey(root_cert.public_key()));
|
||||||
if (!public_key) {
|
if (!public_key) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"invalid-root-public-key");
|
"invalid-root-public-key");
|
||||||
@@ -270,51 +413,123 @@ util::Status DrmRootCertificate::Create(
|
|||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"invalid-root-certificate-signature");
|
"invalid-root-certificate-signature");
|
||||||
}
|
}
|
||||||
cert->reset(new DrmRootCertificate(root_cert.public_key()));
|
|
||||||
|
cert->reset(new DrmRootCertificate(
|
||||||
|
cert_type, serialized_certificate, root_cert.serial_number(),
|
||||||
|
root_cert.public_key(), std::move(key_factory)));
|
||||||
return util::OkStatus();
|
return util::OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status DrmRootCertificate::CreateByType(
|
DrmRootCertificate::DrmRootCertificate(
|
||||||
CertificateType cert_type, std::unique_ptr<DrmRootCertificate>* cert) {
|
CertificateType type, const std::string& serialized_certificate,
|
||||||
CHECK(cert);
|
const std::string& serial_number, const std::string& public_key,
|
||||||
return Create(GetDrmRootCertificate(cert_type), cert);
|
std::unique_ptr<RsaKeyFactory> key_factory)
|
||||||
|
: type_(type),
|
||||||
|
serialized_certificate_(serialized_certificate),
|
||||||
|
serial_number_(serial_number),
|
||||||
|
public_key_(public_key),
|
||||||
|
key_factory_(std::move(key_factory)),
|
||||||
|
signature_cache_(new VerifiedCertSignatureCache(key_factory_.get())) {}
|
||||||
|
|
||||||
|
DrmRootCertificate::~DrmRootCertificate() {}
|
||||||
|
|
||||||
|
std::string DrmRootCertificate::GetDigest() const {
|
||||||
|
return absl::BytesToHexString(Sha256_Hash(serialized_certificate_));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string DrmRootCertificate::GetDrmRootCertificate(CertificateType cert_type) {
|
util::Status DrmRootCertificate::VerifyCertificate(
|
||||||
std::string root_cert;
|
const std::string& serialized_certificate,
|
||||||
switch (cert_type) {
|
SignedDrmCertificate* signed_certificate,
|
||||||
case kCertificateTypeProduction: {
|
DrmCertificate* certificate) const {
|
||||||
root_cert.assign(kProdRootCertificate,
|
std::unique_ptr<SignedDrmCertificate> local_signed_certificate;
|
||||||
kProdRootCertificate + sizeof(kProdRootCertificate));
|
if (!signed_certificate) {
|
||||||
break;
|
local_signed_certificate = absl::make_unique<SignedDrmCertificate>();
|
||||||
}
|
signed_certificate = local_signed_certificate.get();
|
||||||
case kCertificateTypeDevelopment: {
|
|
||||||
root_cert.assign(kDevRootCertificate,
|
|
||||||
kDevRootCertificate + sizeof(kDevRootCertificate));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case kCertificateTypeTesting: {
|
|
||||||
root_cert.assign(kTestRootCertificate,
|
|
||||||
kTestRootCertificate + sizeof(kTestRootCertificate));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// TODO(user): Consider returning util::Status indicating unsupported
|
|
||||||
// cert type.
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return root_cert;
|
if (!signed_certificate->ParseFromString(serialized_certificate)) {
|
||||||
|
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
|
"invalid-signed-drm-certificate");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<DrmCertificate> local_certificate;
|
||||||
|
if (!certificate) {
|
||||||
|
local_certificate = absl::make_unique<DrmCertificate>();
|
||||||
|
certificate = local_certificate.get();
|
||||||
|
}
|
||||||
|
if (signed_certificate->drm_certificate().empty() ||
|
||||||
|
!certificate->ParseFromString(signed_certificate->drm_certificate())) {
|
||||||
|
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
|
"invalid-drm-certificate");
|
||||||
|
}
|
||||||
|
if (certificate->serial_number().empty()) {
|
||||||
|
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
|
"missing-serial-number");
|
||||||
|
}
|
||||||
|
if (!certificate->has_creation_time_seconds()) {
|
||||||
|
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
|
"missing-creation-time");
|
||||||
|
}
|
||||||
|
if (certificate->public_key().empty()) {
|
||||||
|
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
|
"missing-public-key");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify signature chain, but do not use cache for leaf certificates.
|
||||||
|
return VerifySignatures(*signed_certificate, certificate->serial_number(),
|
||||||
|
!kUseCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string DrmRootCertificate::GetDigest(CertificateType cert_type) {
|
// Recursively verifies certificates with their signing certs or the root.
|
||||||
std::string cert(GetDrmRootCertificate(cert_type));
|
// use_cache should be false when initially called so that signatures do not
|
||||||
if (cert.empty()) {
|
// cached leaf certificates not signed with the root certificate, such as for
|
||||||
return std::string();
|
// the case of device-unique device certificates.
|
||||||
|
// Signatures for root-signed certificates are always cached, even if they are
|
||||||
|
// leaf certificates. For example service, and provisioner certificates.
|
||||||
|
util::Status DrmRootCertificate::VerifySignatures(
|
||||||
|
const SignedDrmCertificate& signed_cert, const std::string& cert_serial_number,
|
||||||
|
bool use_cache) const {
|
||||||
|
if (!signed_cert.has_signer()) {
|
||||||
|
// Always use cache for root-signed certificates.
|
||||||
|
return signature_cache_->VerifySignature(
|
||||||
|
signed_cert.drm_certificate(), cert_serial_number,
|
||||||
|
signed_cert.signature(), public_key(), serial_number_);
|
||||||
}
|
}
|
||||||
std::string hash(SHA256_DIGEST_LENGTH, 0);
|
|
||||||
SHA256(reinterpret_cast<const unsigned char*>(cert.data()), cert.size(),
|
DrmCertificate signer;
|
||||||
reinterpret_cast<unsigned char*>(&hash[0]));
|
if (!signer.ParseFromString(signed_cert.signer().drm_certificate())) {
|
||||||
return absl::BytesToHexString(hash);
|
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
|
"invalid-signer-certificate");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the signer before verifying signed_cert.
|
||||||
|
util::Status status =
|
||||||
|
VerifySignatures(signed_cert.signer(), signer.serial_number(), kUseCache);
|
||||||
|
if (!status.ok()) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (use_cache) {
|
||||||
|
status = signature_cache_->VerifySignature(
|
||||||
|
signed_cert.drm_certificate(), cert_serial_number,
|
||||||
|
signed_cert.signature(), signer.public_key(), signer.serial_number());
|
||||||
|
if (!status.ok()) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::unique_ptr<RsaPublicKey> signer_public_key(
|
||||||
|
key_factory_->CreateFromPkcs1PublicKey(signer.public_key()));
|
||||||
|
if (!signer_public_key) {
|
||||||
|
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
|
"invalid-leaf-signer-public-key");
|
||||||
|
}
|
||||||
|
if (!signer_public_key->VerifySignature(signed_cert.drm_certificate(),
|
||||||
|
signed_cert.signature())) {
|
||||||
|
return util::Status(error_space, INVALID_SIGNATURE,
|
||||||
|
"cache-miss-invalid-signature");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return util::OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
|
|||||||
@@ -13,6 +13,8 @@
|
|||||||
#ifndef COMMON_DRM_ROOT_CERTIFICATE_H_
|
#ifndef COMMON_DRM_ROOT_CERTIFICATE_H_
|
||||||
#define COMMON_DRM_ROOT_CERTIFICATE_H_
|
#define COMMON_DRM_ROOT_CERTIFICATE_H_
|
||||||
|
|
||||||
|
// common_typos_disable. Successful / successfull.
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@@ -23,41 +25,82 @@
|
|||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
|
|
||||||
|
class DrmCertificate;
|
||||||
|
class RsaKeyFactory;
|
||||||
|
class RsaPublicKey;
|
||||||
|
class SignedDrmCertificate;
|
||||||
|
class VerifiedCertSignatureCache;
|
||||||
|
|
||||||
|
// Root certificate and certificate chain verifier with internal caching.
|
||||||
|
// This object is thread-safe.
|
||||||
class DrmRootCertificate {
|
class DrmRootCertificate {
|
||||||
public:
|
public:
|
||||||
virtual ~DrmRootCertificate() {}
|
virtual ~DrmRootCertificate();
|
||||||
|
|
||||||
// Creates a DrmRootCertificate object given a certificate type.
|
// Creates a DrmRootCertificate object given a certificate type.
|
||||||
// |cert| may not be nullptr, and it points to a
|
// |cert| may not be nullptr, and it points to a
|
||||||
// std::unique_ptr<DrmRootCertificate> which will be used to return a newly
|
// std::unique_ptr<DrmRootCertificate> which will be used to return a newly
|
||||||
// created DrmRootCertificate* if successful. The caller assumes ownership of
|
// created const DrmRootCertificate* if successful. The caller assumes
|
||||||
// the new DrmRootCertificate. This method returns util::Status::OK on
|
// ownership of the new DrmRootCertificate. This method returns
|
||||||
// success, or appropriate error status otherwise.
|
// util::Status::OK on success, or appropriate error status otherwise.
|
||||||
static util::Status CreateByType(CertificateType cert_type,
|
static util::Status CreateByType(CertificateType cert_type,
|
||||||
std::unique_ptr<DrmRootCertificate>* cert);
|
std::unique_ptr<DrmRootCertificate>* cert);
|
||||||
// Returns the hex-encoded SHA-256 digest for the specified root certificate.
|
|
||||||
static std::string GetDigest(CertificateType cert_type);
|
// Variant on the method above to make CLIF happy until b/110539622 is fixed.
|
||||||
// Given |cert_type|, the appropiate root certificate is returned as
|
static std::unique_ptr<DrmRootCertificate> CreateByType(
|
||||||
// a serialized SignedDrmCertificates.
|
CertificateType cert_type, util::Status* status);
|
||||||
static std::string GetDrmRootCertificate(CertificateType cert_type);
|
|
||||||
|
// Creates a DrmRootCertificate object given a certificate type std::string, which
|
||||||
|
// must be one of "prod", "qa", or "test".
|
||||||
|
// |cert| may not be nullptr, and it points to a
|
||||||
|
// std::unique_ptr<DrmRootCertificate> which will be used to return a newly
|
||||||
|
// created const DrmRootCertificate* if successful. The caller assumes
|
||||||
|
// ownership of the new DrmRootCertificate. This method returns
|
||||||
|
// util::Status::OK on success, or appropriate error status otherwise.
|
||||||
|
static util::Status CreateByTypeString(
|
||||||
|
const std::string& cert_type_string,
|
||||||
|
std::unique_ptr<DrmRootCertificate>* cert);
|
||||||
|
|
||||||
|
// |certificate| will contgain the DRM certificate upon successful return.
|
||||||
|
// May be null.
|
||||||
|
// Returns util::Status::OK if successful, or an appropriate error code
|
||||||
|
// otherwise.
|
||||||
|
virtual util::Status VerifyCertificate(
|
||||||
|
const std::string& serialized_certificate,
|
||||||
|
SignedDrmCertificate* signed_certificate,
|
||||||
|
DrmCertificate* certificate) const;
|
||||||
|
|
||||||
|
// Returns the hex-encoded SHA-256 digest for this certificate.
|
||||||
|
virtual std::string GetDigest() const;
|
||||||
|
|
||||||
|
const CertificateType type() const { return type_; }
|
||||||
|
|
||||||
const std::string& public_key() const { return public_key_; }
|
const std::string& public_key() const { return public_key_; }
|
||||||
|
|
||||||
// Verifies a DRM certificate.
|
protected:
|
||||||
|
DrmRootCertificate(CertificateType cert_type,
|
||||||
|
const std::string& serialized_certificate,
|
||||||
|
const std::string& serial_number, const std::string& public_key,
|
||||||
|
std::unique_ptr<RsaKeyFactory> key_factory);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class DrmRootCertificateTest;
|
friend class DrmRootCertificateTest;
|
||||||
|
|
||||||
// Creates a DrmRootCertificate object given a serialized
|
static util::Status Create(CertificateType cert_type,
|
||||||
// SignedDrmCertificate. |cert| may not be nullptr, and it points to a
|
std::unique_ptr<RsaKeyFactory> key_factory,
|
||||||
// std::unique_ptr<DrmRootCertificate> which will be used to return a newly
|
|
||||||
// created DrmRootCertificate* if successful. The caller assumes ownership of
|
|
||||||
// the new DrmRootCertificate. This method returns util::Status::OK on
|
|
||||||
// success, or appropriate error status otherwise.
|
|
||||||
// TODO(user): Consider moving to private.
|
|
||||||
static util::Status Create(const std::string& signed_drm_certificate,
|
|
||||||
std::unique_ptr<DrmRootCertificate>* cert);
|
std::unique_ptr<DrmRootCertificate>* cert);
|
||||||
explicit DrmRootCertificate(const std::string& public_key)
|
|
||||||
: public_key_(public_key) {}
|
|
||||||
|
|
||||||
|
util::Status VerifySignatures(const SignedDrmCertificate& signed_cert,
|
||||||
|
const std::string& cert_serial_number,
|
||||||
|
bool use_cache) const;
|
||||||
|
|
||||||
|
CertificateType type_;
|
||||||
|
std::string serialized_certificate_;
|
||||||
|
std::string serial_number_;
|
||||||
std::string public_key_;
|
std::string public_key_;
|
||||||
|
std::unique_ptr<RsaKeyFactory> key_factory_;
|
||||||
|
mutable std::unique_ptr<VerifiedCertSignatureCache> signature_cache_;
|
||||||
|
|
||||||
DISALLOW_IMPLICIT_CONSTRUCTORS(DrmRootCertificate);
|
DISALLOW_IMPLICIT_CONSTRUCTORS(DrmRootCertificate);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -9,92 +9,256 @@
|
|||||||
// Description:
|
// Description:
|
||||||
// Unit tests for drm_root_certificate.cc
|
// Unit tests for drm_root_certificate.cc
|
||||||
|
|
||||||
|
#include "common/drm_root_certificate.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include "google/protobuf/util/message_differencer.h"
|
||||||
|
#include "testing/gmock.h"
|
||||||
#include "testing/gunit.h"
|
#include "testing/gunit.h"
|
||||||
#include "common/drm_root_certificate.h"
|
#include "common/error_space.h"
|
||||||
#include "common/rsa_key.h"
|
#include "common/rsa_key.h"
|
||||||
#include "common/rsa_test_keys.h"
|
#include "common/rsa_test_keys.h"
|
||||||
|
#include "common/test_drm_certificates.h"
|
||||||
#include "protos/public/drm_certificate.pb.h"
|
#include "protos/public/drm_certificate.pb.h"
|
||||||
#include "protos/public/errors.pb.h"
|
#include "protos/public/errors.pb.h"
|
||||||
#include "protos/public/signed_drm_certificate.pb.h"
|
#include "protos/public/signed_drm_certificate.pb.h"
|
||||||
|
|
||||||
|
using google::protobuf::util::MessageDifferencer;
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
|
|
||||||
|
TEST(DrmRootCertificateCreateTest, TestCertificate) {
|
||||||
|
const std::string kTestCertificateHash(
|
||||||
|
"49f917b1bdfed78002a58e799a58e940"
|
||||||
|
"1fffaaed9d8d80752782b066757e2c8c");
|
||||||
|
std::unique_ptr<DrmRootCertificate> root_cert;
|
||||||
|
ASSERT_EQ(util::OkStatus(), DrmRootCertificate::CreateByType(
|
||||||
|
kCertificateTypeTesting, &root_cert));
|
||||||
|
ASSERT_TRUE(root_cert != nullptr);
|
||||||
|
EXPECT_EQ(kTestCertificateHash, root_cert->GetDigest());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DrmRootCertificateCreateTest, DevCertificate) {
|
||||||
|
const std::string kDevelopmentCertificateHash(
|
||||||
|
"0e25ee95476a770f30b98ac5ef778b3f"
|
||||||
|
"137b66c29385b84f547a361b4724b17d");
|
||||||
|
std::unique_ptr<DrmRootCertificate> root_cert;
|
||||||
|
ASSERT_EQ(util::OkStatus(), DrmRootCertificate::CreateByType(
|
||||||
|
kCertificateTypeDevelopment, &root_cert));
|
||||||
|
ASSERT_TRUE(root_cert != nullptr);
|
||||||
|
EXPECT_EQ(kDevelopmentCertificateHash, root_cert->GetDigest());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DrmRootCertificateCreateTest, ProdCertificate) {
|
||||||
|
const std::string kProductionCertificateHash(
|
||||||
|
"d62fdabc9286648a81f7d3bedaf2f5a5"
|
||||||
|
"27bbad39bc38da034ba98a21569adb9b");
|
||||||
|
std::unique_ptr<DrmRootCertificate> root_cert;
|
||||||
|
ASSERT_EQ(util::OkStatus(), DrmRootCertificate::CreateByType(
|
||||||
|
kCertificateTypeProduction, &root_cert));
|
||||||
|
ASSERT_TRUE(root_cert != nullptr);
|
||||||
|
EXPECT_EQ(kProductionCertificateHash, root_cert->GetDigest());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DrmRootCertificateTestCertificatesTest, Success) {
|
||||||
|
TestDrmCertificates test_certs;
|
||||||
|
std::unique_ptr<DrmRootCertificate> root_cert;
|
||||||
|
ASSERT_TRUE(
|
||||||
|
DrmRootCertificate::CreateByType(kCertificateTypeTesting, &root_cert)
|
||||||
|
.ok());
|
||||||
|
EXPECT_TRUE(root_cert
|
||||||
|
->VerifyCertificate(test_certs.test_root_certificate(),
|
||||||
|
nullptr, nullptr)
|
||||||
|
.ok());
|
||||||
|
EXPECT_TRUE(
|
||||||
|
root_cert
|
||||||
|
->VerifyCertificate(test_certs.test_intermediate_certificate(),
|
||||||
|
nullptr, nullptr)
|
||||||
|
.ok());
|
||||||
|
EXPECT_TRUE(root_cert
|
||||||
|
->VerifyCertificate(test_certs.test_user_device_certificate(),
|
||||||
|
nullptr, nullptr)
|
||||||
|
.ok());
|
||||||
|
EXPECT_TRUE(root_cert
|
||||||
|
->VerifyCertificate(test_certs.test_service_certificate(),
|
||||||
|
nullptr, nullptr)
|
||||||
|
.ok());
|
||||||
|
}
|
||||||
|
|
||||||
class DrmRootCertificateTest : public testing::Test {
|
class DrmRootCertificateTest : public testing::Test {
|
||||||
protected:
|
protected:
|
||||||
DrmRootCertificateTest() {}
|
DrmRootCertificateTest() {
|
||||||
util::Status DrmRootCertificateCreate(
|
private_keys_.emplace_back(
|
||||||
const std::string& signed_drm_certificate,
|
RsaPrivateKey::Create(test_keys_.private_test_key_1_3072_bits()));
|
||||||
std::unique_ptr<DrmRootCertificate>* cert) {
|
private_keys_.emplace_back(
|
||||||
return DrmRootCertificate::Create(signed_drm_certificate, cert);
|
RsaPrivateKey::Create(test_keys_.private_test_key_2_2048_bits()));
|
||||||
|
private_keys_.emplace_back(
|
||||||
|
RsaPrivateKey::Create(test_keys_.private_test_key_3_2048_bits()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetUp() override {
|
||||||
|
drm_certificates_[0].set_serial_number("level 0");
|
||||||
|
drm_certificates_[0].set_creation_time_seconds(0);
|
||||||
|
drm_certificates_[0].set_public_key(
|
||||||
|
test_keys_.public_test_key_1_3072_bits());
|
||||||
|
drm_certificates_[1].set_serial_number("level 1");
|
||||||
|
drm_certificates_[1].set_creation_time_seconds(1);
|
||||||
|
drm_certificates_[1].set_public_key(
|
||||||
|
test_keys_.public_test_key_2_2048_bits());
|
||||||
|
drm_certificates_[2].set_serial_number("level 2");
|
||||||
|
drm_certificates_[2].set_creation_time_seconds(2);
|
||||||
|
drm_certificates_[2].set_public_key(
|
||||||
|
test_keys_.public_test_key_3_2048_bits());
|
||||||
|
|
||||||
|
ASSERT_EQ(util::OkStatus(), DrmRootCertificate::CreateByType(
|
||||||
|
kCertificateTypeTesting, &root_cert_));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GenerateSignedDrmCertificate() {
|
||||||
|
SignedDrmCertificate* current_sc(&signed_drm_certificate_);
|
||||||
|
ASSERT_TRUE(drm_certificates_[2].SerializeToString(
|
||||||
|
current_sc->mutable_drm_certificate()));
|
||||||
|
ASSERT_TRUE(private_keys_[1]->GenerateSignature(
|
||||||
|
current_sc->drm_certificate(), current_sc->mutable_signature()));
|
||||||
|
|
||||||
|
current_sc = current_sc->mutable_signer();
|
||||||
|
ASSERT_TRUE(drm_certificates_[1].SerializeToString(
|
||||||
|
current_sc->mutable_drm_certificate()));
|
||||||
|
ASSERT_TRUE(private_keys_[0]->GenerateSignature(
|
||||||
|
current_sc->drm_certificate(), current_sc->mutable_signature()));
|
||||||
|
|
||||||
|
current_sc = current_sc->mutable_signer();
|
||||||
|
ASSERT_TRUE(drm_certificates_[0].SerializeToString(
|
||||||
|
current_sc->mutable_drm_certificate()));
|
||||||
|
ASSERT_TRUE(private_keys_[0]->GenerateSignature(
|
||||||
|
current_sc->drm_certificate(), current_sc->mutable_signature()));
|
||||||
|
}
|
||||||
|
|
||||||
|
RsaTestKeys test_keys_;
|
||||||
|
std::vector<std::unique_ptr<RsaPrivateKey>> private_keys_;
|
||||||
|
SignedDrmCertificate signed_drm_certificate_;
|
||||||
|
DrmCertificate drm_certificates_[3];
|
||||||
|
std::unique_ptr<DrmRootCertificate> root_cert_;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(DrmRootCertificateTest, DrmRootCertificateCreation) {
|
TEST_F(DrmRootCertificateTest, SuccessNoOutput) {
|
||||||
RsaTestKeys test_keys;
|
GenerateSignedDrmCertificate();
|
||||||
std::unique_ptr<DrmRootCertificate> root_cert;
|
ASSERT_EQ(util::OkStatus(),
|
||||||
|
root_cert_->VerifyCertificate(
|
||||||
// First, invalid serialized cert. Should fail.
|
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
||||||
EXPECT_EQ(INVALID_DRM_CERTIFICATE,
|
|
||||||
DrmRootCertificateCreate("bad_cert", &root_cert).error_code());
|
|
||||||
SignedDrmCertificate signed_cert;
|
|
||||||
std::string serialized;
|
|
||||||
// Serialized empty cert. Should fail.
|
|
||||||
ASSERT_TRUE(signed_cert.SerializeToString(&serialized));
|
|
||||||
EXPECT_NE(util::OkStatus(),
|
|
||||||
DrmRootCertificateCreate(serialized, &root_cert));
|
|
||||||
// Add public key. Should still fail.
|
|
||||||
DrmCertificate drm_cert;
|
|
||||||
drm_cert.set_public_key(test_keys.public_test_key_1_3072_bits());
|
|
||||||
ASSERT_TRUE(
|
|
||||||
drm_cert.SerializeToString(signed_cert.mutable_drm_certificate()));
|
|
||||||
ASSERT_TRUE(signed_cert.SerializeToString(&serialized));
|
|
||||||
EXPECT_EQ(INVALID_DRM_CERTIFICATE,
|
|
||||||
DrmRootCertificateCreate(serialized, &root_cert).error_code());
|
|
||||||
// Now self-sign the cert. Should succeed.
|
|
||||||
std::unique_ptr<RsaPrivateKey> private_key(
|
|
||||||
RsaPrivateKey::Create(test_keys.private_test_key_1_3072_bits()));
|
|
||||||
ASSERT_TRUE(private_key.get());
|
|
||||||
ASSERT_TRUE(private_key->GenerateSignature(signed_cert.drm_certificate(),
|
|
||||||
signed_cert.mutable_signature()));
|
|
||||||
ASSERT_TRUE(signed_cert.SerializeToString(&serialized));
|
|
||||||
EXPECT_EQ(util::OkStatus(),
|
|
||||||
DrmRootCertificateCreate(serialized, &root_cert));
|
|
||||||
ASSERT_TRUE(root_cert);
|
|
||||||
// Verify the public key.
|
|
||||||
EXPECT_EQ(test_keys.public_test_key_1_3072_bits(), root_cert->public_key());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DrmRootCertificateTest, DrmRootCertificateCreationByType) {
|
TEST_F(DrmRootCertificateTest, SuccessWithOutput) {
|
||||||
std::unique_ptr<DrmRootCertificate> root_cert;
|
GenerateSignedDrmCertificate();
|
||||||
EXPECT_EQ(util::OkStatus(), DrmRootCertificate::CreateByType(
|
SignedDrmCertificate out_signed_cert;
|
||||||
kCertificateTypeTesting, &root_cert));
|
DrmCertificate out_cert;
|
||||||
ASSERT_TRUE(root_cert != nullptr);
|
ASSERT_EQ(util::OkStatus(), root_cert_->VerifyCertificate(
|
||||||
EXPECT_EQ(util::OkStatus(), DrmRootCertificate::CreateByType(
|
signed_drm_certificate_.SerializeAsString(),
|
||||||
kCertificateTypeDevelopment, &root_cert));
|
&out_signed_cert, &out_cert));
|
||||||
ASSERT_TRUE(root_cert != nullptr);
|
EXPECT_TRUE(
|
||||||
EXPECT_EQ(util::OkStatus(), DrmRootCertificate::CreateByType(
|
MessageDifferencer::Equals(out_signed_cert, signed_drm_certificate_));
|
||||||
kCertificateTypeProduction, &root_cert));
|
EXPECT_TRUE(MessageDifferencer::Equals(out_cert, drm_certificates_[2]));
|
||||||
ASSERT_TRUE(root_cert != nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DrmRootCertificateTest, DrmRootCertificateDigest) {
|
TEST_F(DrmRootCertificateTest, InvalidSignedDrmCertificate) {
|
||||||
const std::string test_cert_hash(
|
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"49f917b1bdfed78002a58e799a58e940"
|
"invalid-signed-drm-certificate"),
|
||||||
"1fffaaed9d8d80752782b066757e2c8c");
|
root_cert_->VerifyCertificate("pure garbage", nullptr, nullptr));
|
||||||
const std::string dev_cert_hash(
|
}
|
||||||
"0e25ee95476a770f30b98ac5ef778b3f"
|
|
||||||
"137b66c29385b84f547a361b4724b17d");
|
TEST_F(DrmRootCertificateTest, InvalidSignerCertificate) {
|
||||||
const std::string prod_cert_hash(
|
GenerateSignedDrmCertificate();
|
||||||
"d62fdabc9286648a81f7d3bedaf2f5a5"
|
signed_drm_certificate_.mutable_signer()->set_drm_certificate("more garbage");
|
||||||
"27bbad39bc38da034ba98a21569adb9b");
|
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
EXPECT_EQ(test_cert_hash,
|
"invalid-signer-certificate"),
|
||||||
DrmRootCertificate::GetDigest(kCertificateTypeTesting));
|
root_cert_->VerifyCertificate(
|
||||||
EXPECT_EQ(dev_cert_hash,
|
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
||||||
DrmRootCertificate::GetDigest(kCertificateTypeDevelopment));
|
}
|
||||||
EXPECT_EQ(prod_cert_hash,
|
|
||||||
DrmRootCertificate::GetDigest(kCertificateTypeProduction));
|
TEST_F(DrmRootCertificateTest, MissingDrmCertificate) {
|
||||||
|
GenerateSignedDrmCertificate();
|
||||||
|
signed_drm_certificate_.clear_drm_certificate();
|
||||||
|
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
|
"invalid-drm-certificate"),
|
||||||
|
root_cert_->VerifyCertificate(
|
||||||
|
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DrmRootCertificateTest, InvalidDrmCertificate) {
|
||||||
|
GenerateSignedDrmCertificate();
|
||||||
|
signed_drm_certificate_.set_drm_certificate("junk");
|
||||||
|
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
|
"invalid-drm-certificate"),
|
||||||
|
root_cert_->VerifyCertificate(
|
||||||
|
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DrmRootCertificateTest, InvalidPublicKey) {
|
||||||
|
drm_certificates_[0].set_public_key("rubbish");
|
||||||
|
GenerateSignedDrmCertificate();
|
||||||
|
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
|
"invalid-signer-public-key"),
|
||||||
|
root_cert_->VerifyCertificate(
|
||||||
|
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DrmRootCertificateTest, MissingPublicKey) {
|
||||||
|
drm_certificates_[2].clear_public_key();
|
||||||
|
GenerateSignedDrmCertificate();
|
||||||
|
EXPECT_EQ(
|
||||||
|
util::Status(error_space, INVALID_DRM_CERTIFICATE, "missing-public-key"),
|
||||||
|
root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(),
|
||||||
|
nullptr, nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DrmRootCertificateTest, MissingCreationTime) {
|
||||||
|
drm_certificates_[2].clear_creation_time_seconds();
|
||||||
|
GenerateSignedDrmCertificate();
|
||||||
|
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
|
"missing-creation-time"),
|
||||||
|
root_cert_->VerifyCertificate(
|
||||||
|
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DrmRootCertificateTest, MissingSerialNumber) {
|
||||||
|
drm_certificates_[2].set_serial_number("");
|
||||||
|
GenerateSignedDrmCertificate();
|
||||||
|
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
|
"missing-serial-number"),
|
||||||
|
root_cert_->VerifyCertificate(
|
||||||
|
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DrmRootCertificateTest, InvalidSignatureWithNoCache) {
|
||||||
|
GenerateSignedDrmCertificate();
|
||||||
|
signed_drm_certificate_.mutable_signer()->set_signature(
|
||||||
|
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
|
||||||
|
EXPECT_EQ(util::Status(error_space, INVALID_SIGNATURE,
|
||||||
|
"cache-miss-invalid-signature"),
|
||||||
|
root_cert_->VerifyCertificate(
|
||||||
|
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DrmRootCertificateTest, InvalidSignatureWithCache) {
|
||||||
|
GenerateSignedDrmCertificate();
|
||||||
|
// Verify and cache.
|
||||||
|
ASSERT_EQ(util::OkStatus(),
|
||||||
|
root_cert_->VerifyCertificate(
|
||||||
|
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
||||||
|
|
||||||
|
// Verify success using cache.
|
||||||
|
ASSERT_EQ(util::OkStatus(),
|
||||||
|
root_cert_->VerifyCertificate(
|
||||||
|
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
||||||
|
|
||||||
|
// Verify failure using cache.
|
||||||
|
signed_drm_certificate_.mutable_signer()->set_signature(
|
||||||
|
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
|
||||||
|
EXPECT_EQ(
|
||||||
|
util::Status(error_space, INVALID_SIGNATURE, "cached-signature-mismatch"),
|
||||||
|
root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(),
|
||||||
|
nullptr, nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
|
|||||||
@@ -108,49 +108,24 @@ DrmServiceCertificateMap* DrmServiceCertificateMap::GetInstance() {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
util::Status DrmServiceCertificate::AddDrmServiceCertificate(
|
util::Status DrmServiceCertificate::AddDrmServiceCertificate(
|
||||||
const std::string& root_public_key, const std::string& service_certificate,
|
const DrmRootCertificate* root_cert, const std::string& service_certificate,
|
||||||
const std::string& service_private_key,
|
const std::string& service_private_key,
|
||||||
const std::string& service_private_key_passphrase) {
|
const std::string& service_private_key_passphrase) {
|
||||||
std::unique_ptr<RsaPublicKey> root_key(RsaPublicKey::Create(root_public_key));
|
|
||||||
if (root_key == nullptr) {
|
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
|
||||||
"root-certificate-rsa-public-key-failed");
|
|
||||||
}
|
|
||||||
SignedDrmCertificate signed_cert;
|
|
||||||
if (!signed_cert.ParseFromString(service_certificate)) {
|
|
||||||
return util::Status(error_space, INVALID_SERVICE_CERTIFICATE,
|
|
||||||
"signed-certificate-parse-failed");
|
|
||||||
}
|
|
||||||
if (!root_key->VerifySignature(signed_cert.drm_certificate(),
|
|
||||||
signed_cert.signature())) {
|
|
||||||
return util::Status(error_space, INVALID_SERVICE_CERTIFICATE,
|
|
||||||
"certificate-signature-verification-failed");
|
|
||||||
}
|
|
||||||
DrmCertificate drm_cert;
|
DrmCertificate drm_cert;
|
||||||
if (!drm_cert.ParseFromString(signed_cert.drm_certificate())) {
|
util::Status status =
|
||||||
return util::Status(error_space, INVALID_SERVICE_CERTIFICATE,
|
root_cert->VerifyCertificate(service_certificate, nullptr, &drm_cert);
|
||||||
"certificate-parse-failed");
|
if (!status.ok()) {
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (drm_cert.type() != DrmCertificate::SERVICE) {
|
if (drm_cert.type() != DrmCertificate::SERVICE) {
|
||||||
return util::Status(error_space, INVALID_SERVICE_CERTIFICATE,
|
return util::Status(error_space, INVALID_SERVICE_CERTIFICATE,
|
||||||
"not-service-certificate");
|
"not-service-certificate");
|
||||||
}
|
}
|
||||||
if (drm_cert.serial_number().empty()) {
|
|
||||||
return util::Status(error_space, INVALID_SERVICE_CERTIFICATE,
|
|
||||||
"missing-certificate-serial-number");
|
|
||||||
}
|
|
||||||
if (drm_cert.provider_id().empty()) {
|
if (drm_cert.provider_id().empty()) {
|
||||||
return util::Status(error_space, INVALID_SERVICE_CERTIFICATE,
|
return util::Status(error_space, INVALID_SERVICE_CERTIFICATE,
|
||||||
"missing-certificate-service-id");
|
"missing-certificate-service-id");
|
||||||
}
|
}
|
||||||
if (!drm_cert.has_creation_time_seconds()) {
|
|
||||||
return util::Status(error_space, INVALID_SERVICE_CERTIFICATE,
|
|
||||||
"missing-certificate-creation-time");
|
|
||||||
}
|
|
||||||
if (drm_cert.public_key().empty()) {
|
|
||||||
return util::Status(error_space, INVALID_SERVICE_CERTIFICATE,
|
|
||||||
"missing-certificate-public-key");
|
|
||||||
}
|
|
||||||
std::unique_ptr<RsaPublicKey> public_key(
|
std::unique_ptr<RsaPublicKey> public_key(
|
||||||
RsaPublicKey::Create(drm_cert.public_key()));
|
RsaPublicKey::Create(drm_cert.public_key()));
|
||||||
if (!public_key) {
|
if (!public_key) {
|
||||||
@@ -178,21 +153,6 @@ util::Status DrmServiceCertificate::AddDrmServiceCertificate(
|
|||||||
return util::OkStatus();
|
return util::OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status DrmServiceCertificate::AddDrmServiceCertificate(
|
|
||||||
CertificateType root_cert_type, const std::string& service_certificate,
|
|
||||||
const std::string& service_private_key,
|
|
||||||
const std::string& service_private_key_passphrase) {
|
|
||||||
std::unique_ptr<DrmRootCertificate> root_cert;
|
|
||||||
util::Status status =
|
|
||||||
DrmRootCertificate::CreateByType(root_cert_type, &root_cert);
|
|
||||||
if (!status.ok()) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
return AddDrmServiceCertificate(root_cert->public_key(), service_certificate,
|
|
||||||
service_private_key,
|
|
||||||
service_private_key_passphrase);
|
|
||||||
}
|
|
||||||
|
|
||||||
const DrmServiceCertificate*
|
const DrmServiceCertificate*
|
||||||
DrmServiceCertificate::GetDefaultDrmServiceCertificate() {
|
DrmServiceCertificate::GetDefaultDrmServiceCertificate() {
|
||||||
return DrmServiceCertificateMap::GetInstance()->GetDefaultCert();
|
return DrmServiceCertificateMap::GetInstance()->GetDefaultCert();
|
||||||
@@ -212,30 +172,15 @@ const DrmServiceCertificate* DrmServiceCertificate::GetDrmServiceCertificate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
util::Status DrmServiceCertificate::SetDefaultDrmServiceCertificate(
|
util::Status DrmServiceCertificate::SetDefaultDrmServiceCertificate(
|
||||||
const std::string& root_public_key, const std::string& service_certificate,
|
const DrmRootCertificate* root_drm_cert, const std::string& service_certificate,
|
||||||
const std::string& service_private_key,
|
const std::string& service_private_key,
|
||||||
const std::string& service_private_key_passphrase) {
|
const std::string& service_private_key_passphrase) {
|
||||||
DrmServiceCertificateMap::GetInstance()->ClearDefaultDrmServiceCertificate();
|
DrmServiceCertificateMap::GetInstance()->ClearDefaultDrmServiceCertificate();
|
||||||
return AddDrmServiceCertificate(root_public_key, service_certificate,
|
return AddDrmServiceCertificate(root_drm_cert, service_certificate,
|
||||||
service_private_key,
|
service_private_key,
|
||||||
service_private_key_passphrase);
|
service_private_key_passphrase);
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status DrmServiceCertificate::SetDefaultDrmServiceCertificate(
|
|
||||||
CertificateType root_cert_type, const std::string& service_certificate,
|
|
||||||
const std::string& service_private_key,
|
|
||||||
const std::string& service_private_key_passphrase) {
|
|
||||||
std::unique_ptr<DrmRootCertificate> root_cert;
|
|
||||||
util::Status status =
|
|
||||||
DrmRootCertificate::CreateByType(root_cert_type, &root_cert);
|
|
||||||
if (!status.ok()) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
return SetDefaultDrmServiceCertificate(
|
|
||||||
root_cert->public_key(), service_certificate, service_private_key,
|
|
||||||
service_private_key_passphrase);
|
|
||||||
}
|
|
||||||
|
|
||||||
util::Status DrmServiceCertificate::DecryptClientIdentification(
|
util::Status DrmServiceCertificate::DecryptClientIdentification(
|
||||||
const EncryptedClientIdentification& encrypted_client_id,
|
const EncryptedClientIdentification& encrypted_client_id,
|
||||||
ClientIdentification* client_id) {
|
ClientIdentification* client_id) {
|
||||||
|
|||||||
@@ -29,13 +29,16 @@ class RequestInspectorTest;
|
|||||||
namespace widevine {
|
namespace widevine {
|
||||||
|
|
||||||
class ClientIdentification;
|
class ClientIdentification;
|
||||||
|
class DrmRootCertificate;
|
||||||
class EncryptedClientIdentification;
|
class EncryptedClientIdentification;
|
||||||
|
|
||||||
|
// TODO(user): Add a DrmCertificateList class to provide the static method
|
||||||
|
// functionality.
|
||||||
class DrmServiceCertificate {
|
class DrmServiceCertificate {
|
||||||
public:
|
public:
|
||||||
// Create a new DrmServiceCertificate object and add it to the list of valid
|
// Create a new DrmServiceCertificate object and add it to the list of valid
|
||||||
// service certificates. |root_cert_type| indicates which root public key to
|
// service certificates. |drm_root_cert| is the root certificate for the type
|
||||||
// use to verify |service_certificate|, |service_certificate| is a
|
// of certifiate being added. |service_certificate| is a
|
||||||
// Google-generated certificate used to authenticate the service provider for
|
// Google-generated certificate used to authenticate the service provider for
|
||||||
// purposes of device privacy, |service_private_key| is the encrypted PKCS#8
|
// purposes of device privacy, |service_private_key| is the encrypted PKCS#8
|
||||||
// private RSA key corresponding to the service certificate,
|
// private RSA key corresponding to the service certificate,
|
||||||
@@ -46,16 +49,16 @@ class DrmServiceCertificate {
|
|||||||
// used as the default service certificate.
|
// used as the default service certificate.
|
||||||
// This method is thread-safe.
|
// This method is thread-safe.
|
||||||
static util::Status AddDrmServiceCertificate(
|
static util::Status AddDrmServiceCertificate(
|
||||||
CertificateType root_cert_type, const std::string& service_certificate,
|
const DrmRootCertificate* root_drm_cert,
|
||||||
const std::string& service_private_key,
|
const std::string& service_certificate, const std::string& service_private_key,
|
||||||
const std::string& service_private_key_passphrase);
|
const std::string& service_private_key_passphrase);
|
||||||
|
|
||||||
// Same as AddDrmServiceCertificate(), but will clear the default service
|
// Same as AddDrmServiceCertificate(), but will clear the default service
|
||||||
// certificate if it's set. This will result in this service certificate
|
// certificate if it's set. This will result in this service certificate
|
||||||
// being set as the default service certificate.
|
// being set as the default service certificate.
|
||||||
static util::Status SetDefaultDrmServiceCertificate(
|
static util::Status SetDefaultDrmServiceCertificate(
|
||||||
CertificateType root_cert_type, const std::string& service_certificate,
|
const DrmRootCertificate* root_drm_cert,
|
||||||
const std::string& service_private_key,
|
const std::string& service_certificate, const std::string& service_private_key,
|
||||||
const std::string& service_private_key_passphrase);
|
const std::string& service_private_key_passphrase);
|
||||||
|
|
||||||
// Returns the default service certificate. Will return null if no default
|
// Returns the default service certificate. Will return null if no default
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
// widevine-licensing@google.com.
|
// widevine-licensing@google.com.
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "common/drm_service_certificate.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "glog/logging.h"
|
#include "glog/logging.h"
|
||||||
@@ -14,11 +16,11 @@
|
|||||||
#include "testing/gunit.h"
|
#include "testing/gunit.h"
|
||||||
#include "absl/strings/escaping.h"
|
#include "absl/strings/escaping.h"
|
||||||
#include "common/aes_cbc_util.h"
|
#include "common/aes_cbc_util.h"
|
||||||
#include "common/drm_service_certificate.h"
|
#include "common/drm_root_certificate.h"
|
||||||
#include "common/rsa_key.h"
|
#include "common/rsa_key.h"
|
||||||
#include "common/rsa_test_keys.h"
|
#include "common/rsa_test_keys.h"
|
||||||
#include "common/rsa_util.h"
|
#include "common/rsa_util.h"
|
||||||
#include "common/test_certificates.h"
|
#include "common/test_drm_certificates.h"
|
||||||
#include "protos/public/client_identification.pb.h"
|
#include "protos/public/client_identification.pb.h"
|
||||||
#include "protos/public/drm_certificate.pb.h"
|
#include "protos/public/drm_certificate.pb.h"
|
||||||
#include "protos/public/errors.pb.h" // IWYU pragma: keep
|
#include "protos/public/errors.pb.h" // IWYU pragma: keep
|
||||||
@@ -38,7 +40,9 @@ class DrmServiceCertificateTest : public ::testing::Test {
|
|||||||
iv_(absl::HexStringToBytes(kIv)),
|
iv_(absl::HexStringToBytes(kIv)),
|
||||||
root_private_key_(
|
root_private_key_(
|
||||||
RsaPrivateKey::Create(test_keys_.private_test_key_1_3072_bits())) {
|
RsaPrivateKey::Create(test_keys_.private_test_key_1_3072_bits())) {
|
||||||
CHECK(root_private_key_ != nullptr);
|
EXPECT_TRUE(root_private_key_);
|
||||||
|
EXPECT_OK(
|
||||||
|
DrmRootCertificate::CreateByType(kCertificateTypeTesting, &root_cert_));
|
||||||
client_id_.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE);
|
client_id_.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE);
|
||||||
client_id_.set_token(test_certs_.test_user_device_certificate());
|
client_id_.set_token(test_certs_.test_user_device_certificate());
|
||||||
}
|
}
|
||||||
@@ -78,8 +82,7 @@ class DrmServiceCertificateTest : public ::testing::Test {
|
|||||||
return util::Status(util::error::INTERNAL, "");
|
return util::Status(util::error::INTERNAL, "");
|
||||||
}
|
}
|
||||||
return DrmServiceCertificate::SetDefaultDrmServiceCertificate(
|
return DrmServiceCertificate::SetDefaultDrmServiceCertificate(
|
||||||
test_keys_.public_test_key_1_3072_bits(), signed_cert,
|
root_cert_.get(), signed_cert, encrypted_private_key, kPassphrase);
|
||||||
encrypted_private_key, kPassphrase);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status AddDrmServiceCertificate(const std::string& serial_number,
|
util::Status AddDrmServiceCertificate(const std::string& serial_number,
|
||||||
@@ -95,8 +98,7 @@ class DrmServiceCertificateTest : public ::testing::Test {
|
|||||||
return util::Status(util::error::INTERNAL, "");
|
return util::Status(util::error::INTERNAL, "");
|
||||||
}
|
}
|
||||||
return DrmServiceCertificate::AddDrmServiceCertificate(
|
return DrmServiceCertificate::AddDrmServiceCertificate(
|
||||||
test_keys_.public_test_key_1_3072_bits(), signed_cert,
|
root_cert_.get(), signed_cert, encrypted_private_key, kPassphrase);
|
||||||
encrypted_private_key, kPassphrase);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EncryptClientIdentification(
|
void EncryptClientIdentification(
|
||||||
@@ -118,10 +120,11 @@ class DrmServiceCertificateTest : public ::testing::Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RsaTestKeys test_keys_;
|
RsaTestKeys test_keys_;
|
||||||
TestCertificates test_certs_;
|
TestDrmCertificates test_certs_;
|
||||||
std::string privacy_key_;
|
std::string privacy_key_;
|
||||||
std::string iv_;
|
std::string iv_;
|
||||||
std::unique_ptr<RsaPrivateKey> root_private_key_;
|
std::unique_ptr<RsaPrivateKey> root_private_key_;
|
||||||
|
std::unique_ptr<DrmRootCertificate> root_cert_;
|
||||||
ClientIdentification client_id_;
|
ClientIdentification client_id_;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -201,6 +204,7 @@ TEST_F(DrmServiceCertificateTest, MultipleCertsPerService) {
|
|||||||
std::string serial_number1("serial_number1");
|
std::string serial_number1("serial_number1");
|
||||||
std::string serial_number2("serial_number2");
|
std::string serial_number2("serial_number2");
|
||||||
std::string serial_number3("serial_number3");
|
std::string serial_number3("serial_number3");
|
||||||
|
std::string serial_number4("serial_number4");
|
||||||
std::string provider_id("someservice.com");
|
std::string provider_id("someservice.com");
|
||||||
uint32_t creation_time_seconds(1234);
|
uint32_t creation_time_seconds(1234);
|
||||||
|
|
||||||
@@ -249,13 +253,13 @@ TEST_F(DrmServiceCertificateTest, MultipleCertsPerService) {
|
|||||||
ASSERT_TRUE(drm_cert.ParseFromString(signed_cert.drm_certificate()));
|
ASSERT_TRUE(drm_cert.ParseFromString(signed_cert.drm_certificate()));
|
||||||
EXPECT_EQ(serial_number1, drm_cert.serial_number());
|
EXPECT_EQ(serial_number1, drm_cert.serial_number());
|
||||||
|
|
||||||
EXPECT_OK(SetDefaultDrmServiceCertificate(serial_number2, provider_id,
|
EXPECT_OK(SetDefaultDrmServiceCertificate(serial_number4, provider_id,
|
||||||
creation_time_seconds));
|
creation_time_seconds));
|
||||||
default_cert = DrmServiceCertificate::GetDefaultDrmServiceCertificate();
|
default_cert = DrmServiceCertificate::GetDefaultDrmServiceCertificate();
|
||||||
ASSERT_TRUE(default_cert);
|
ASSERT_TRUE(default_cert);
|
||||||
ASSERT_TRUE(signed_cert.ParseFromString(default_cert->certificate()));
|
ASSERT_TRUE(signed_cert.ParseFromString(default_cert->certificate()));
|
||||||
ASSERT_TRUE(drm_cert.ParseFromString(signed_cert.drm_certificate()));
|
ASSERT_TRUE(drm_cert.ParseFromString(signed_cert.drm_certificate()));
|
||||||
EXPECT_EQ(serial_number2, drm_cert.serial_number());
|
EXPECT_EQ(serial_number4, drm_cert.serial_number());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DrmServiceCertificateTest, DrmServiceCertificateNotFound) {
|
TEST_F(DrmServiceCertificateTest, DrmServiceCertificateNotFound) {
|
||||||
|
|||||||
@@ -54,14 +54,14 @@ class MockRsaKeyFactory : public RsaKeyFactory {
|
|||||||
MockRsaKeyFactory() {}
|
MockRsaKeyFactory() {}
|
||||||
~MockRsaKeyFactory() override {}
|
~MockRsaKeyFactory() override {}
|
||||||
|
|
||||||
MOCK_METHOD1(CreateFromPkcs1PrivateKey,
|
MOCK_CONST_METHOD1(CreateFromPkcs1PrivateKey,
|
||||||
std::unique_ptr<RsaPrivateKey>(const std::string& private_key));
|
std::unique_ptr<RsaPrivateKey>(const std::string& private_key));
|
||||||
MOCK_METHOD2(
|
MOCK_CONST_METHOD2(
|
||||||
CreateFromPkcs8PrivateKey,
|
CreateFromPkcs8PrivateKey,
|
||||||
std::unique_ptr<RsaPrivateKey>(const std::string& private_key,
|
std::unique_ptr<RsaPrivateKey>(const std::string& private_key,
|
||||||
const std::string& private_key_passphrase));
|
const std::string& private_key_passphrase));
|
||||||
MOCK_METHOD1(CreateFromPkcs1PublicKey,
|
MOCK_CONST_METHOD1(CreateFromPkcs1PublicKey,
|
||||||
std::unique_ptr<RsaPublicKey>(const std::string& public_key));
|
std::unique_ptr<RsaPublicKey>(const std::string& public_key));
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MockRsaKeyFactory(const MockRsaKeyFactory&) = delete;
|
MockRsaKeyFactory(const MockRsaKeyFactory&) = delete;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include "openssl/bio.h"
|
#include "openssl/bio.h"
|
||||||
#include "openssl/evp.h"
|
#include "openssl/evp.h"
|
||||||
|
#include "openssl/pkcs7.h"
|
||||||
#include "openssl/rsa.h"
|
#include "openssl/rsa.h"
|
||||||
#include "openssl/x509v3.h"
|
#include "openssl/x509v3.h"
|
||||||
|
|
||||||
@@ -46,6 +47,7 @@ using ScopedOpenSSLStackOnly =
|
|||||||
|
|
||||||
using ScopedBIGNUM = ScopedOpenSSLType<BIGNUM, BN_free>;
|
using ScopedBIGNUM = ScopedOpenSSLType<BIGNUM, BN_free>;
|
||||||
using ScopedBIO = ScopedOpenSSLType<BIO, BIO_vfree>;
|
using ScopedBIO = ScopedOpenSSLType<BIO, BIO_vfree>;
|
||||||
|
using ScopedPKCS7 = ScopedOpenSSLType<PKCS7, PKCS7_free>;
|
||||||
using ScopedPKEY = ScopedOpenSSLType<EVP_PKEY, EVP_PKEY_free>;
|
using ScopedPKEY = ScopedOpenSSLType<EVP_PKEY, EVP_PKEY_free>;
|
||||||
using ScopedRSA = ScopedOpenSSLType<RSA, RSA_free>;
|
using ScopedRSA = ScopedOpenSSLType<RSA, RSA_free>;
|
||||||
using ScopedX509 = ScopedOpenSSLType<X509, X509_free>;
|
using ScopedX509 = ScopedOpenSSLType<X509, X509_free>;
|
||||||
@@ -59,6 +61,7 @@ using ScopedX509StoreCtx =
|
|||||||
ScopedOpenSSLType<X509_STORE_CTX, X509_STORE_CTX_free>;
|
ScopedOpenSSLType<X509_STORE_CTX, X509_STORE_CTX_free>;
|
||||||
using ScopedX509Req = ScopedOpenSSLType<X509_REQ, X509_REQ_free>;
|
using ScopedX509Req = ScopedOpenSSLType<X509_REQ, X509_REQ_free>;
|
||||||
using ScopedAsn1UtcTime = ScopedOpenSSLType<ASN1_UTCTIME, ASN1_UTCTIME_free>;
|
using ScopedAsn1UtcTime = ScopedOpenSSLType<ASN1_UTCTIME, ASN1_UTCTIME_free>;
|
||||||
|
using ScopedAsn1Time = ScopedOpenSSLType<ASN1_TIME, ASN1_TIME_free>;
|
||||||
using ScopedAsn1Utc8String =
|
using ScopedAsn1Utc8String =
|
||||||
ScopedOpenSSLType<ASN1_UTF8STRING, ASN1_UTF8STRING_free>;
|
ScopedOpenSSLType<ASN1_UTF8STRING, ASN1_UTF8STRING_free>;
|
||||||
using ScopedAsn1Integer = ScopedOpenSSLType<ASN1_INTEGER, ASN1_INTEGER_free>;
|
using ScopedAsn1Integer = ScopedOpenSSLType<ASN1_INTEGER, ASN1_INTEGER_free>;
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ RemoteAttestationVerifier& RemoteAttestationVerifier::get() {
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteAttestationVerifier::EnableTestCertificates(bool enable) {
|
void RemoteAttestationVerifier::EnableTestDrmCertificates(bool enable) {
|
||||||
absl::WriterMutexLock lock(&ca_mutex_);
|
absl::WriterMutexLock lock(&ca_mutex_);
|
||||||
enable_test_certificates_ = enable;
|
enable_test_certificates_ = enable;
|
||||||
ca_.reset();
|
ca_.reset();
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class RemoteAttestationVerifier {
|
|||||||
|
|
||||||
// Call to use the test (non-production) remote attestation root certificate.
|
// Call to use the test (non-production) remote attestation root certificate.
|
||||||
// This method is thread-safe.
|
// This method is thread-safe.
|
||||||
void EnableTestCertificates(bool enable);
|
void EnableTestDrmCertificates(bool enable);
|
||||||
|
|
||||||
// Call to verify a RemoteAttestation challenge response, used in licensing
|
// Call to verify a RemoteAttestation challenge response, used in licensing
|
||||||
// protocol.
|
// protocol.
|
||||||
|
|||||||
@@ -286,12 +286,12 @@ RsaKeyFactory::RsaKeyFactory() {}
|
|||||||
RsaKeyFactory::~RsaKeyFactory() {}
|
RsaKeyFactory::~RsaKeyFactory() {}
|
||||||
|
|
||||||
std::unique_ptr<RsaPrivateKey> RsaKeyFactory::CreateFromPkcs1PrivateKey(
|
std::unique_ptr<RsaPrivateKey> RsaKeyFactory::CreateFromPkcs1PrivateKey(
|
||||||
const std::string& private_key) {
|
const std::string& private_key) const {
|
||||||
return std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(private_key));
|
return std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(private_key));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<RsaPrivateKey> RsaKeyFactory::CreateFromPkcs8PrivateKey(
|
std::unique_ptr<RsaPrivateKey> RsaKeyFactory::CreateFromPkcs8PrivateKey(
|
||||||
const std::string& private_key, const std::string& private_key_passphrase) {
|
const std::string& private_key, const std::string& private_key_passphrase) const {
|
||||||
std::string pkcs1_key;
|
std::string pkcs1_key;
|
||||||
const bool result =
|
const bool result =
|
||||||
private_key_passphrase.empty()
|
private_key_passphrase.empty()
|
||||||
@@ -306,7 +306,7 @@ std::unique_ptr<RsaPrivateKey> RsaKeyFactory::CreateFromPkcs8PrivateKey(
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<RsaPublicKey> RsaKeyFactory::CreateFromPkcs1PublicKey(
|
std::unique_ptr<RsaPublicKey> RsaKeyFactory::CreateFromPkcs1PublicKey(
|
||||||
const std::string& public_key) {
|
const std::string& public_key) const {
|
||||||
return std::unique_ptr<RsaPublicKey>(RsaPublicKey::Create(public_key));
|
return std::unique_ptr<RsaPublicKey>(RsaPublicKey::Create(public_key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,9 +60,12 @@ class RsaPrivateKey {
|
|||||||
// Returns the RSA key size (modulus) in bytes.
|
// Returns the RSA key size (modulus) in bytes.
|
||||||
virtual uint32_t KeySize() const;
|
virtual uint32_t KeySize() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class RsaPublicKey;
|
||||||
|
friend class X509CertificateBuilder; // TODO(user): Get rid of this.
|
||||||
|
|
||||||
const RSA* key() const { return key_; }
|
const RSA* key() const { return key_; }
|
||||||
|
|
||||||
private:
|
|
||||||
RSA* key_;
|
RSA* key_;
|
||||||
|
|
||||||
// SWIG appears to think this declaration is a syntax error. Excluding it for
|
// SWIG appears to think this declaration is a syntax error. Excluding it for
|
||||||
@@ -110,9 +113,12 @@ class RsaPublicKey {
|
|||||||
// Returns the RSA key size (modulus) in bytes.
|
// Returns the RSA key size (modulus) in bytes.
|
||||||
virtual uint32_t KeySize() const;
|
virtual uint32_t KeySize() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class RsaPrivateKey;
|
||||||
|
friend class X509CertificateBuilder; // TODO(user): Get rid of this.
|
||||||
|
|
||||||
const RSA* key() const { return key_; }
|
const RSA* key() const { return key_; }
|
||||||
|
|
||||||
private:
|
|
||||||
RSA* key_;
|
RSA* key_;
|
||||||
|
|
||||||
// SWIG appears to think this declaration is a syntax error. Excluding it for
|
// SWIG appears to think this declaration is a syntax error. Excluding it for
|
||||||
@@ -130,16 +136,16 @@ class RsaKeyFactory {
|
|||||||
|
|
||||||
// Create an RsaPrivateKey object using a DER encoded PKCS#1 RSAPrivateKey.
|
// Create an RsaPrivateKey object using a DER encoded PKCS#1 RSAPrivateKey.
|
||||||
virtual std::unique_ptr<RsaPrivateKey> CreateFromPkcs1PrivateKey(
|
virtual std::unique_ptr<RsaPrivateKey> CreateFromPkcs1PrivateKey(
|
||||||
const std::string& private_key);
|
const std::string& private_key) const;
|
||||||
|
|
||||||
// Create a PKCS#1 RsaPrivateKey object using an PKCS#8 PrivateKeyInfo or
|
// Create a PKCS#1 RsaPrivateKey object using an PKCS#8 PrivateKeyInfo or
|
||||||
// EncryptedPrivateKeyInfo (if |private_key_passprhase| is not empty).
|
// EncryptedPrivateKeyInfo (if |private_key_passprhase| is not empty).
|
||||||
virtual std::unique_ptr<RsaPrivateKey> CreateFromPkcs8PrivateKey(
|
virtual std::unique_ptr<RsaPrivateKey> CreateFromPkcs8PrivateKey(
|
||||||
const std::string& private_key, const std::string& private_key_passphrase);
|
const std::string& private_key, const std::string& private_key_passphrase) const;
|
||||||
|
|
||||||
// Create an RsaPublicKey object using a DER encoded PKCS#1 RSAPublicKey.
|
// Create an RsaPublicKey object using a DER encoded PKCS#1 RSAPublicKey.
|
||||||
virtual std::unique_ptr<RsaPublicKey> CreateFromPkcs1PublicKey(
|
virtual std::unique_ptr<RsaPublicKey> CreateFromPkcs1PublicKey(
|
||||||
const std::string& public_key);
|
const std::string& public_key) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DISALLOW_COPY_AND_ASSIGN(RsaKeyFactory);
|
DISALLOW_COPY_AND_ASSIGN(RsaKeyFactory);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "common/test_certificates.h"
|
#include "common/test_drm_certificates.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
|
|
||||||
@@ -311,7 +311,7 @@ const unsigned char kTestDrmServiceCertificate[] = {
|
|||||||
0x34, 0xba, 0xf5, 0xec, 0xaf, 0x26, 0xfb, 0x64, 0xc4, 0x38, 0x7e, 0xdb,
|
0x34, 0xba, 0xf5, 0xec, 0xaf, 0x26, 0xfb, 0x64, 0xc4, 0x38, 0x7e, 0xdb,
|
||||||
0x51, 0x28, 0x49, 0xa7, 0x12, 0x88, 0xa5, 0x6d, 0xa2, 0xfa};
|
0x51, 0x28, 0x49, 0xa7, 0x12, 0x88, 0xa5, 0x6d, 0xa2, 0xfa};
|
||||||
|
|
||||||
TestCertificates::TestCertificates()
|
TestDrmCertificates::TestDrmCertificates()
|
||||||
: test_root_certificate_(
|
: test_root_certificate_(
|
||||||
kTestRootCertificate,
|
kTestRootCertificate,
|
||||||
kTestRootCertificate + sizeof(kTestRootCertificate)),
|
kTestRootCertificate + sizeof(kTestRootCertificate)),
|
||||||
@@ -10,18 +10,18 @@
|
|||||||
// Class contains certificates that can be used for testing. Provides methods
|
// Class contains certificates that can be used for testing. Provides methods
|
||||||
// to retrieve a test root certificate, a test intermediate certificate and a
|
// to retrieve a test root certificate, a test intermediate certificate and a
|
||||||
// test user device certificate.
|
// test user device certificate.
|
||||||
#ifndef COMMON_TEST_CERTIFICATES_H_
|
#ifndef COMMON_TEST_DRM_CERTIFICATES_H_
|
||||||
#define COMMON_TEST_CERTIFICATES_H_
|
#define COMMON_TEST_DRM_CERTIFICATES_H_
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "base/macros.h"
|
#include "base/macros.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
|
|
||||||
class TestCertificates {
|
class TestDrmCertificates {
|
||||||
public:
|
public:
|
||||||
TestCertificates();
|
TestDrmCertificates();
|
||||||
virtual ~TestCertificates() {}
|
virtual ~TestDrmCertificates() {}
|
||||||
|
|
||||||
// returns a test root certificate
|
// returns a test root certificate
|
||||||
const std::string& test_root_certificate() const { return test_root_certificate_; }
|
const std::string& test_root_certificate() const { return test_root_certificate_; }
|
||||||
@@ -47,8 +47,8 @@ class TestCertificates {
|
|||||||
const std::string test_user_device_certificate_;
|
const std::string test_user_device_certificate_;
|
||||||
const std::string test_service_certificate_;
|
const std::string test_service_certificate_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(TestCertificates);
|
DISALLOW_COPY_AND_ASSIGN(TestDrmCertificates);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
#endif // COMMON_TEST_CERTIFICATES_H_
|
#endif // COMMON_TEST_DRM_CERTIFICATES_H_
|
||||||
@@ -248,7 +248,7 @@ VmpChecker::VmpChecker() : allow_development_vmp_(false) {}
|
|||||||
|
|
||||||
VmpChecker::~VmpChecker() {}
|
VmpChecker::~VmpChecker() {}
|
||||||
|
|
||||||
util::Status VmpChecker::SelectDrmCertificateType(CertificateType cert_type) {
|
util::Status VmpChecker::SelectCertificateType(CertificateType cert_type) {
|
||||||
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
|
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
|
||||||
util::Status status = ca_cert->LoadDer(
|
util::Status status = ca_cert->LoadDer(
|
||||||
cert_type == kCertificateTypeProduction
|
cert_type == kCertificateTypeProduction
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class VmpChecker {
|
|||||||
static VmpChecker* Instance();
|
static VmpChecker* Instance();
|
||||||
|
|
||||||
// Select the type of root to use. Not thread-safe.
|
// Select the type of root to use. Not thread-safe.
|
||||||
virtual util::Status SelectDrmCertificateType(CertificateType root_type);
|
virtual util::Status SelectCertificateType(CertificateType cert_type);
|
||||||
|
|
||||||
// Verify VMP data and return appropriate result.
|
// Verify VMP data and return appropriate result.
|
||||||
virtual util::Status VerifyVmpData(const std::string& vmp_data, Result* result);
|
virtual util::Status VerifyVmpData(const std::string& vmp_data, Result* result);
|
||||||
|
|||||||
@@ -154,8 +154,8 @@ const char kSameAsPrevious[] = "";
|
|||||||
class VmpCheckerTest : public ::testing::Test {
|
class VmpCheckerTest : public ::testing::Test {
|
||||||
public:
|
public:
|
||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
ASSERT_OK(VmpChecker::Instance()->SelectDrmCertificateType(
|
ASSERT_OK(
|
||||||
kCertificateTypeTesting));
|
VmpChecker::Instance()->SelectCertificateType(kCertificateTypeTesting));
|
||||||
vmp_data_.Clear();
|
vmp_data_.Clear();
|
||||||
VmpChecker::Instance()->set_allow_development_vmp(true);
|
VmpChecker::Instance()->set_allow_development_vmp(true);
|
||||||
signing_key_.reset(
|
signing_key_.reset(
|
||||||
|
|||||||
@@ -255,6 +255,41 @@ util::Status X509CertChain::LoadPkcs7(const std::string& pk7_cert_chain) {
|
|||||||
return util::OkStatus();
|
return util::OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string X509CertChain::GetPkcs7() {
|
||||||
|
std::string pkcs7_cert;
|
||||||
|
ScopedX509Stack cert_stack(sk_X509_new_null());
|
||||||
|
for (X509Cert* cert : cert_chain_) {
|
||||||
|
// X509 stack takes ownership of certificates. Copy certificates to retain
|
||||||
|
// |cert_chain_|.
|
||||||
|
X509Cert cert_copy;
|
||||||
|
if (!cert_copy.LoadPem(cert->GetPem()).ok()) {
|
||||||
|
LOG(WARNING) << "Certificate chain serialization failed";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
X509* openssl_cert_copy = const_cast<X509*>(cert_copy.openssl_cert());
|
||||||
|
cert_copy.openssl_cert_ = nullptr;
|
||||||
|
sk_X509_push(cert_stack.get(), openssl_cert_copy);
|
||||||
|
}
|
||||||
|
ScopedPKCS7 pkcs7(
|
||||||
|
PKCS7_sign(nullptr, nullptr, cert_stack.get(), nullptr, PKCS7_DETACHED));
|
||||||
|
if (!pkcs7) {
|
||||||
|
LOG(WARNING) << "Could not convert certificate chain to PKCS7";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
ScopedBIO bio(BIO_new(BIO_s_mem()));
|
||||||
|
if (bio.get() == nullptr || !i2d_PKCS7_bio(bio.get(), pkcs7.get())) {
|
||||||
|
LOG(WARNING) << "Failed writing PKCS7 to bio";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
int cert_size = BIO_pending(bio.get());
|
||||||
|
pkcs7_cert.resize(cert_size);
|
||||||
|
if (BIO_read(bio.get(), &pkcs7_cert[0], cert_size) != cert_size) {
|
||||||
|
LOG(WARNING) << "BIO_read failure";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return pkcs7_cert;
|
||||||
|
}
|
||||||
|
|
||||||
X509Cert* X509CertChain::GetCert(size_t cert_index) const {
|
X509Cert* X509CertChain::GetCert(size_t cert_index) const {
|
||||||
if (cert_index >= cert_chain_.size()) {
|
if (cert_index >= cert_chain_.size()) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -326,6 +361,25 @@ util::Status X509CA::VerifyCertChain(const X509CertChain& cert_chain) {
|
|||||||
return OpenSslX509Verify(leaf_cert->openssl_cert(), intermediates.get());
|
return OpenSslX509Verify(leaf_cert->openssl_cert(), intermediates.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
util::Status X509CA::VerifyCertWithChain(const X509Cert& cert,
|
||||||
|
const X509CertChain& cert_chain) {
|
||||||
|
ScopedX509StackOnly intermediates(sk_X509_new_null());
|
||||||
|
if (!intermediates) {
|
||||||
|
// MakeStatus is now preferred. But we don't support it in the exported
|
||||||
|
// version, yet. So, ignore lint here.
|
||||||
|
// NOLINTNEXTLINE
|
||||||
|
return util::Status(
|
||||||
|
util::Status::canonical_space(), util::error::INTERNAL,
|
||||||
|
"Failed to allocate X.509 intermediate certificate stack");
|
||||||
|
}
|
||||||
|
for (size_t idx = 0; idx < cert_chain.GetNumCerts(); ++idx) {
|
||||||
|
sk_X509_push(intermediates.get(),
|
||||||
|
const_cast<X509*>(cert_chain.GetCert(idx)->openssl_cert()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return OpenSslX509Verify(cert.openssl_cert(), intermediates.get());
|
||||||
|
}
|
||||||
|
|
||||||
util::Status X509CA::OpenSslX509Verify(const X509* cert,
|
util::Status X509CA::OpenSslX509Verify(const X509* cert,
|
||||||
STACK_OF(X509) * intermediates) {
|
STACK_OF(X509) * intermediates) {
|
||||||
DCHECK(cert);
|
DCHECK(cert);
|
||||||
|
|||||||
@@ -107,6 +107,10 @@ class X509CertChain {
|
|||||||
// container.
|
// container.
|
||||||
util::Status LoadPkcs7(const std::string& pk7_cert_chain);
|
util::Status LoadPkcs7(const std::string& pk7_cert_chain);
|
||||||
|
|
||||||
|
// Writes the |cert_chain_| to a DER-encoded PKCS#7 X.509 cryptographic
|
||||||
|
// message. The final message does not include signed data.
|
||||||
|
std::string GetPkcs7();
|
||||||
|
|
||||||
// Returns the number of certificates in the chain.
|
// Returns the number of certificates in the chain.
|
||||||
size_t GetNumCerts() const { return cert_chain_.size(); }
|
size_t GetNumCerts() const { return cert_chain_.size(); }
|
||||||
|
|
||||||
@@ -138,6 +142,12 @@ class X509CA {
|
|||||||
// used when constructing X509CA. This method is thread-safe.
|
// used when constructing X509CA. This method is thread-safe.
|
||||||
util::Status VerifyCertChain(const X509CertChain& cert_chain);
|
util::Status VerifyCertChain(const X509CertChain& cert_chain);
|
||||||
|
|
||||||
|
// Does X.509 PKI validation of |cert| using the |cert_chain|
|
||||||
|
// certificates. This method allows |cert| to be an ICA. This method is
|
||||||
|
// thread-safe.
|
||||||
|
util::Status VerifyCertWithChain(const X509Cert& cert,
|
||||||
|
const X509CertChain& cert_chain);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
util::Status InitializeStore();
|
util::Status InitializeStore();
|
||||||
util::Status OpenSslX509Verify(const X509* cert, STACK_OF(X509) * stack);
|
util::Status OpenSslX509Verify(const X509* cert, STACK_OF(X509) * stack);
|
||||||
|
|||||||
@@ -52,6 +52,32 @@ const char kTestRootCaDerCert[] =
|
|||||||
"d22de9a13c5092c92c297021c51a2a0a5250cf26c271ff262f25a7738ae4"
|
"d22de9a13c5092c92c297021c51a2a0a5250cf26c271ff262f25a7738ae4"
|
||||||
"c270d87191c13aefdd177b";
|
"c270d87191c13aefdd177b";
|
||||||
|
|
||||||
|
const char kTestRootCaPemCert[] =
|
||||||
|
"-----BEGIN CERTIFICATE-----\n"
|
||||||
|
"MIIEAzCCAuugAwIBAgIJAKJPlK965oMfMA0GCSqGSIb3DQEBBQUAMIGXMQswCQYD\n"
|
||||||
|
"VQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjERMA8GA1UEBwwIS2lya2xhbmQx\n"
|
||||||
|
"EzARBgNVBAoMCkdvb2dsZSBJbmMxETAPBgNVBAsMCFdpZGV2aW5lMRUwEwYDVQQD\n"
|
||||||
|
"DAxUZXN0IFJvb3QgQ0ExITAfBgkqhkiG9w0BCQEWEnRpbnNraXBAZ29vZ2xlLmNv\n"
|
||||||
|
"bTAeFw0xMzA4MTYwMDU3MTBaFw0zMzA4MTUwMDU3MTBaMIGXMQswCQYDVQQGEwJV\n"
|
||||||
|
"UzETMBEGA1UECAwKV2FzaGluZ3RvbjERMA8GA1UEBwwIS2lya2xhbmQxEzARBgNV\n"
|
||||||
|
"BAoMCkdvb2dsZSBJbmMxETAPBgNVBAsMCFdpZGV2aW5lMRUwEwYDVQQDDAxUZXN0\n"
|
||||||
|
"IFJvb3QgQ0ExITAfBgkqhkiG9w0BCQEWEnRpbnNraXBAZ29vZ2xlLmNvbTCCASIw\n"
|
||||||
|
"DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbu5inZn3c2LbVUXtHW37NhbHQs\n"
|
||||||
|
"YX1f1I8vv8s/LsQKCAvQTVUc5RlHGou07Fwsdb+KLSyvP4XZDp45OR372q5oBRMZ\n"
|
||||||
|
"DacbGyrkgpoVxEvBsZsXE0hEuUxvBtkhYzMjZXTz8RsNEMPGIUEOQmMMV86ekBBX\n"
|
||||||
|
"7aXDwiA+4q2AWg2TUvqR2kWm9IdbRSTBk8Qv2QSKECBOWyyCA0Arp2Dn4bQSbD4q\n"
|
||||||
|
"tCWPK/KM0xcN6Mc4pqH0z8wGSfqV8UFP2dCd1PURvAqb86WESjNNngpLlSXSeJvm\n"
|
||||||
|
"q6/i0MwgedzwMP+pvorj/iyrTr36SU1IqoxjJk0x4iCKnCj3PgEDzhZGg78CAwEA\n"
|
||||||
|
"AaNQME4wHQYDVR0OBBYEFE0w/xgaxPENqZ5qEsAeAqzK34QKMB8GA1UdIwQYMBaA\n"
|
||||||
|
"FE0w/xgaxPENqZ5qEsAeAqzK34QKMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEF\n"
|
||||||
|
"BQADggEBAHeem5jT7AZvKYYpA6AOnJglnZh8BLnmoubDOB7lnsHdDX3uedphLk36\n"
|
||||||
|
"o0ZciRaZPtet67JzQN4gyhAQZ/g0KyEk7A1dtTEne0ZTw7xysqja6uEg5TSOGjOP\n"
|
||||||
|
"bmjnEpQ2Am54Ak8E12axMiUuwVJALc7CgXQ0aqC6mX1/GvFA/wJb7IQfgDm6ENfM\n"
|
||||||
|
"CYzyRVT4y7KqMYdSBcZ98vBTDYeE+vY8T5ReYto3TK1hVeauRPWXvP9FZuoqrEJY\n"
|
||||||
|
"5K6BVpwO3dHfaSlTK0U4vSBLL/WEfLRqxzg8lv6C0i3poTxQksksKXAhxRoqClJQ\n"
|
||||||
|
"zybCcf8mLyWnc4rkwnDYcZHBOu/dF3s=\n"
|
||||||
|
"-----END CERTIFICATE-----\n";
|
||||||
|
|
||||||
const char kTestPemCert[] =
|
const char kTestPemCert[] =
|
||||||
"-----BEGIN CERTIFICATE-----\n"
|
"-----BEGIN CERTIFICATE-----\n"
|
||||||
"MIIDwzCCAqsCAQIwDQYJKoZIhvcNAQEFBQAwgZ8xCzAJBgNVBAYTAlVTMRMwEQYD\n"
|
"MIIDwzCCAqsCAQIwDQYJKoZIhvcNAQEFBQAwgZ8xCzAJBgNVBAYTAlVTMRMwEQYD\n"
|
||||||
@@ -130,6 +156,32 @@ const char kTestPemCertChain[] =
|
|||||||
"6kIkGZCFP/ws7ctk+fQyjjttncIdL2k=\n"
|
"6kIkGZCFP/ws7ctk+fQyjjttncIdL2k=\n"
|
||||||
"-----END CERTIFICATE-----\n";
|
"-----END CERTIFICATE-----\n";
|
||||||
|
|
||||||
|
const char kTestPemIca[] =
|
||||||
|
"-----BEGIN CERTIFICATE-----\n"
|
||||||
|
"MIIEAzCCAuugAwIBAgIBATANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UEBhMCVVMx\n"
|
||||||
|
"EzARBgNVBAgMCldhc2hpbmd0b24xETAPBgNVBAcMCEtpcmtsYW5kMRMwEQYDVQQK\n"
|
||||||
|
"DApHb29nbGUgSW5jMREwDwYDVQQLDAhXaWRldmluZTEVMBMGA1UEAwwMVGVzdCBS\n"
|
||||||
|
"b290IENBMSEwHwYJKoZIhvcNAQkBFhJ0aW5za2lwQGdvb2dsZS5jb20wHhcNMTMw\n"
|
||||||
|
"ODE2MjE0MTQ2WhcNMzMwODE1MjE0MTQ2WjCBnzELMAkGA1UEBhMCVVMxEzARBgNV\n"
|
||||||
|
"BAgMCldhc2hpbmd0b24xETAPBgNVBAcMCEtpcmtsYW5kMRMwEQYDVQQKDApHb29n\n"
|
||||||
|
"bGUgSW5jMREwDwYDVQQLDAhXaWRldmluZTEdMBsGA1UEAwwUVGVzdCBJbnRlcm1l\n"
|
||||||
|
"ZGlhdGUgQ0ExITAfBgkqhkiG9w0BCQEWEnRpbnNraXBAZ29vZ2xlLmNvbTCCASIw\n"
|
||||||
|
"DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANooBi6x3I9Incs6ytlPjBu7yEy5\n"
|
||||||
|
"f6BLf5NREE5nQm74Rt7PAA7YVDtxHP+pi1uyxsL3fUrx904s4tdXNRK85/2zn7+o\n"
|
||||||
|
"oZPYb8fH6dgl7ocmYeyC0jSmg7++ZiaS6OsjPSUTE2aEbAe6Q+ZhYsAbdkL7Z2dN\n"
|
||||||
|
"UJR9akhLEqlqfX4q5bWA0M3P/2/fqNYMS0w010Nwpd+KydbceT0rHQTmTGVsqCCL\n"
|
||||||
|
"gmaP9a8aQRMSP0dn5IOcc/K1Qnnfw1gxnjGF4aBP7KbCMxNBrbgBOwiTxgEMIcKZ\n"
|
||||||
|
"9IGszAcpftKX5ra3XePzFWCcnwilppaaE/2XWXkcAehc8d3xtkdAYZyVIBUCAwEA\n"
|
||||||
|
"AaNQME4wHQYDVR0OBBYEFDm35gzM6ll13HhZUbW5uDw7BieTMB8GA1UdIwQYMBaA\n"
|
||||||
|
"FE0w/xgaxPENqZ5qEsAeAqzK34QKMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEF\n"
|
||||||
|
"BQADggEBALj+/Z8ygfWVNncV0N9UsAcwlGUe5ME+VoXUF/0SOmdrc8LtPc2Dkc8b\n"
|
||||||
|
"xiQN1wHxE/OFsbsOdobPzwOBh67KyYyVWtxzzsLO0MHGxsbOmwa1AersoP4x8xoC\n"
|
||||||
|
"HaBU90cviYqz5k6rZyBIlFIrM5lqG1JB3U0kTceG/1sqwRAAu94BYqMW1iWyr9Mq\n"
|
||||||
|
"ASRCVBOrksWda4pZkCLp62vk7ItOcs2PrHf6UWbANTDH+8Q+pIw2wuJ5lf/imqKO\n"
|
||||||
|
"qrYCJmAi6VBa2jyHqXVPMk6lL1Rmdk4UgOsRvsbmKzb2vYeWIwhsXY5Spo3WVTLv\n"
|
||||||
|
"6kIkGZCFP/ws7ctk+fQyjjttncIdL2k=\n"
|
||||||
|
"-----END CERTIFICATE-----\n";
|
||||||
|
|
||||||
const char kTestPk7CertChain[] =
|
const char kTestPk7CertChain[] =
|
||||||
"308207fb06092a864886f70d010702a08207ec308207e80201013100300b"
|
"308207fb06092a864886f70d010702a08207ec308207e80201013100300b"
|
||||||
"06092a864886f70d010701a08207ce308203c3308202ab020102300d0609"
|
"06092a864886f70d010701a08207ce308203c3308202ab020102300d0609"
|
||||||
@@ -293,6 +345,7 @@ const char kTestDevCodeSigningCert[] =
|
|||||||
"5MXS+h+FxQ6QUar2q1zHc/0Gr1hLzA6HYBmI0/AF8LsHs799XjrMKHkSBN6UQkC1\n"
|
"5MXS+h+FxQ6QUar2q1zHc/0Gr1hLzA6HYBmI0/AF8LsHs799XjrMKHkSBN6UQkC1\n"
|
||||||
"hRk=\n"
|
"hRk=\n"
|
||||||
"-----END CERTIFICATE-----\n";
|
"-----END CERTIFICATE-----\n";
|
||||||
|
|
||||||
const char kDevCertFlagOid[] = "1.3.6.1.4.1.11129.4.1.2";
|
const char kDevCertFlagOid[] = "1.3.6.1.4.1.11129.4.1.2";
|
||||||
const bool kTestDevCodeSigningCertFlagValue = true;
|
const bool kTestDevCodeSigningCertFlagValue = true;
|
||||||
|
|
||||||
@@ -388,6 +441,62 @@ TEST(X509CertTest, ChainVerificationPkcs7) {
|
|||||||
EXPECT_EQ(util::OkStatus(), ca.VerifyCertChain(test_chain));
|
EXPECT_EQ(util::OkStatus(), ca.VerifyCertChain(test_chain));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(X509CertTest, VerifyCertWithChainIca) {
|
||||||
|
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
|
||||||
|
ASSERT_EQ(util::OkStatus(), ca_cert->LoadPem(kTestRootCaPemCert));
|
||||||
|
X509CA ca(ca_cert.release());
|
||||||
|
|
||||||
|
// Verify the ICA with the root succeeds.
|
||||||
|
X509CertChain test_chain;
|
||||||
|
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestRootCaPemCert));
|
||||||
|
ASSERT_EQ(1, test_chain.GetNumCerts());
|
||||||
|
X509Cert ica_cert;
|
||||||
|
ASSERT_EQ(util::OkStatus(), ica_cert.LoadPem(kTestPemIca));
|
||||||
|
EXPECT_EQ(util::OkStatus(), ca.VerifyCertWithChain(ica_cert, test_chain));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(X509CertTest, VerifyCertWithChainLeaf) {
|
||||||
|
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
|
||||||
|
ASSERT_EQ(util::OkStatus(), ca_cert->LoadPem(kTestRootCaPemCert));
|
||||||
|
X509CA ca(ca_cert.release());
|
||||||
|
|
||||||
|
// Verify the leaf with the root and ICA succeeds.
|
||||||
|
X509CertChain test_chain;
|
||||||
|
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemIca));
|
||||||
|
ASSERT_EQ(1, test_chain.GetNumCerts());
|
||||||
|
X509Cert leaf_cert;
|
||||||
|
ASSERT_EQ(util::OkStatus(), leaf_cert.LoadPem(kTestPemCert));
|
||||||
|
EXPECT_EQ(util::OkStatus(), ca.VerifyCertWithChain(leaf_cert, test_chain));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(X509CertTest, VerifyCertWithChainLeafMissincIca) {
|
||||||
|
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
|
||||||
|
ASSERT_EQ(util::OkStatus(), ca_cert->LoadPem(kTestRootCaPemCert));
|
||||||
|
X509CA ca(ca_cert.release());
|
||||||
|
|
||||||
|
// Verify the leaf with only the root fails (ICA missing).
|
||||||
|
X509CertChain test_chain;
|
||||||
|
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestRootCaPemCert));
|
||||||
|
ASSERT_EQ(1, test_chain.GetNumCerts());
|
||||||
|
X509Cert leaf_cert;
|
||||||
|
ASSERT_EQ(util::OkStatus(), leaf_cert.LoadPem(kTestPemCert));
|
||||||
|
EXPECT_NE(util::OkStatus(), ca.VerifyCertWithChain(leaf_cert, test_chain));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(X509CertTest, GetPkcs7) {
|
||||||
|
X509CertChain test_chain;
|
||||||
|
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCertChain));
|
||||||
|
std::string pkcs7_certificate = test_chain.GetPkcs7();
|
||||||
|
ASSERT_NE(pkcs7_certificate.size(), 0);
|
||||||
|
X509CertChain new_test_chain;
|
||||||
|
ASSERT_EQ(util::OkStatus(), new_test_chain.LoadPkcs7(pkcs7_certificate));
|
||||||
|
ASSERT_EQ(test_chain.GetNumCerts(), new_test_chain.GetNumCerts());
|
||||||
|
for (int i = 0; i < test_chain.GetNumCerts(); i++) {
|
||||||
|
ASSERT_EQ(test_chain.GetCert(i)->GetPem(),
|
||||||
|
new_test_chain.GetCert(i)->GetPem());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST(X509CertTest, BooleanExtension) {
|
TEST(X509CertTest, BooleanExtension) {
|
||||||
std::unique_ptr<X509Cert> cert1(new X509Cert);
|
std::unique_ptr<X509Cert> cert1(new X509Cert);
|
||||||
ASSERT_EQ(util::OkStatus(), cert1->LoadPem(kTestPemCert));
|
ASSERT_EQ(util::OkStatus(), cert1->LoadPem(kTestPemCert));
|
||||||
|
|||||||
@@ -25,14 +25,6 @@ package_group(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
filegroup(
|
|
||||||
name = "binary_release_files",
|
|
||||||
srcs = [
|
|
||||||
"client_cert.h",
|
|
||||||
],
|
|
||||||
visibility = ["//visibility:public"],
|
|
||||||
)
|
|
||||||
|
|
||||||
cc_library(
|
cc_library(
|
||||||
name = "session_impl",
|
name = "session_impl",
|
||||||
srcs = [
|
srcs = [
|
||||||
@@ -52,14 +44,15 @@ cc_library(
|
|||||||
"//util:status",
|
"//util:status",
|
||||||
"//common:aes_cbc_util",
|
"//common:aes_cbc_util",
|
||||||
"//common:certificate_type",
|
"//common:certificate_type",
|
||||||
"//common:certificate_util",
|
"//common:client_cert",
|
||||||
"//common:crypto_util",
|
"//common:crypto_util",
|
||||||
"//common:drm_root_certificate",
|
"//common:device_status_list",
|
||||||
"//common:drm_service_certificate",
|
|
||||||
"//common:error_space",
|
"//common:error_space",
|
||||||
"//common:random_util",
|
"//common:random_util",
|
||||||
"//common:remote_attestation_verifier",
|
"//common:remote_attestation_verifier",
|
||||||
|
"//common:drm_root_certificate",
|
||||||
"//common:rsa_key",
|
"//common:rsa_key",
|
||||||
|
"//common:drm_service_certificate",
|
||||||
"//common:signing_key_util",
|
"//common:signing_key_util",
|
||||||
"//common:verified_media_pipeline",
|
"//common:verified_media_pipeline",
|
||||||
"//common:vmp_checker",
|
"//common:vmp_checker",
|
||||||
@@ -75,15 +68,11 @@ cc_library(
|
|||||||
cc_library(
|
cc_library(
|
||||||
name = "sdk",
|
name = "sdk",
|
||||||
srcs = [
|
srcs = [
|
||||||
"client_cert.cc",
|
|
||||||
"device_status_list.cc",
|
|
||||||
"key_control_block.cc",
|
"key_control_block.cc",
|
||||||
"parse_content_id.cc",
|
"parse_content_id.cc",
|
||||||
"generate_error_response.cc",
|
"generate_error_response.cc",
|
||||||
],
|
],
|
||||||
hdrs = [
|
hdrs = [
|
||||||
"client_cert.h",
|
|
||||||
"device_status_list.h",
|
|
||||||
"generate_error_response.h",
|
"generate_error_response.h",
|
||||||
"key_control_block.h",
|
"key_control_block.h",
|
||||||
"parse_content_id.h",
|
"parse_content_id.h",
|
||||||
@@ -98,11 +87,14 @@ cc_library(
|
|||||||
"//util/endian",
|
"//util/endian",
|
||||||
"//util/gtl:map_util",
|
"//util/gtl:map_util",
|
||||||
"//util:status",
|
"//util:status",
|
||||||
|
"//common:client_cert",
|
||||||
"//common:crypto_util",
|
"//common:crypto_util",
|
||||||
"//common:drm_service_certificate",
|
"//common:device_status_list",
|
||||||
"//common:error_space",
|
"//common:error_space",
|
||||||
"//common:random_util",
|
"//common:random_util",
|
||||||
"//common:rsa_key",
|
"//common:rsa_key",
|
||||||
|
"//common:drm_root_certificate",
|
||||||
|
"//common:drm_service_certificate",
|
||||||
"//common:signing_key_util",
|
"//common:signing_key_util",
|
||||||
"//common:wvm_token_handler",
|
"//common:wvm_token_handler",
|
||||||
"//sdk/external/common/wvpl:wvpl_types",
|
"//sdk/external/common/wvpl:wvpl_types",
|
||||||
@@ -130,15 +122,17 @@ cc_test(
|
|||||||
"//testing:gunit_main",
|
"//testing:gunit_main",
|
||||||
"@abseil_repo//absl/strings",
|
"@abseil_repo//absl/strings",
|
||||||
"//common:aes_cbc_util",
|
"//common:aes_cbc_util",
|
||||||
|
"//common:client_cert",
|
||||||
"//common:crypto_util",
|
"//common:crypto_util",
|
||||||
"//common:drm_root_certificate",
|
|
||||||
"//common:error_space",
|
"//common:error_space",
|
||||||
"//common:remote_attestation_verifier",
|
"//common:remote_attestation_verifier",
|
||||||
|
"//common:device_status_list",
|
||||||
|
"//common:drm_root_certificate",
|
||||||
"//common:rsa_key",
|
"//common:rsa_key",
|
||||||
"//common:rsa_test_keys",
|
"//common:rsa_test_keys",
|
||||||
"//common:rsa_util",
|
"//common:rsa_util",
|
||||||
"//common:signing_key_util",
|
"//common:signing_key_util",
|
||||||
"//common:test_certificates",
|
"//common:test_drm_certificates",
|
||||||
"//common:test_utils",
|
"//common:test_utils",
|
||||||
"//protos/public:client_identification_proto",
|
"//protos/public:client_identification_proto",
|
||||||
"//protos/public:device_certificate_status_proto",
|
"//protos/public:device_certificate_status_proto",
|
||||||
@@ -168,24 +162,6 @@ cc_test(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
cc_test(
|
|
||||||
name = "device_status_list_test",
|
|
||||||
timeout = "short",
|
|
||||||
srcs = ["device_status_list_test.cc"],
|
|
||||||
deps = [
|
|
||||||
":sdk",
|
|
||||||
"//base",
|
|
||||||
"//testing:gunit_main",
|
|
||||||
"@abseil_repo//absl/strings",
|
|
||||||
"//common:rsa_key",
|
|
||||||
"//common:rsa_test_keys",
|
|
||||||
"//protos/public:client_identification_proto",
|
|
||||||
"//protos/public:errors_proto",
|
|
||||||
"//protos/public:provisioned_device_info_proto",
|
|
||||||
"//protos/public:signed_drm_certificate_proto",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
cc_test(
|
cc_test(
|
||||||
name = "parse_content_id_test",
|
name = "parse_content_id_test",
|
||||||
timeout = "short",
|
timeout = "short",
|
||||||
|
|||||||
@@ -1,408 +0,0 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Copyright 2017 Google LLC.
|
|
||||||
//
|
|
||||||
// This software is licensed under the terms defined in the Widevine Master
|
|
||||||
// License Agreement. For a copy of this agreement, please contact
|
|
||||||
// widevine-licensing@google.com.
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#include "license_server_sdk/internal/client_cert.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "glog/logging.h"
|
|
||||||
#include "strings/serialize.h"
|
|
||||||
#include "absl/strings/escaping.h"
|
|
||||||
#include "absl/synchronization/mutex.h"
|
|
||||||
#include "util/gtl/map_util.h"
|
|
||||||
#include "util/status.h"
|
|
||||||
#include "common/crypto_util.h"
|
|
||||||
#include "common/error_space.h"
|
|
||||||
#include "common/random_util.h"
|
|
||||||
#include "common/signing_key_util.h"
|
|
||||||
#include "common/wvm_token_handler.h"
|
|
||||||
#include "protos/public/drm_certificate.pb.h"
|
|
||||||
#include "protos/public/errors.pb.h"
|
|
||||||
#include "protos/public/signed_drm_certificate.pb.h"
|
|
||||||
|
|
||||||
namespace widevine {
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
const int kPreProvisioningKeySizeBytes = 16;
|
|
||||||
const int kKeyboxSizeBytes = 72;
|
|
||||||
|
|
||||||
struct ValidatedSignerCertificate {
|
|
||||||
std::string certificate;
|
|
||||||
std::string signature;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ValidatedSignerCache {
|
|
||||||
public:
|
|
||||||
void SetRootPublicKey(std::unique_ptr<RsaPublicKey> new_root_key);
|
|
||||||
bool Exist(const std::string& serial_number, const std::string& certificate,
|
|
||||||
const std::string& signature);
|
|
||||||
util::Status ValidateSigner(const std::string& serial_number,
|
|
||||||
const std::string& certificate,
|
|
||||||
const std::string& signature);
|
|
||||||
|
|
||||||
void ResetSignerCache();
|
|
||||||
size_t SignerCacheSize();
|
|
||||||
|
|
||||||
static ValidatedSignerCache* GetSingleton();
|
|
||||||
|
|
||||||
private:
|
|
||||||
absl::Mutex rsa_root_public_key_mutex_;
|
|
||||||
std::unique_ptr<RsaPublicKey> rsa_root_public_key_
|
|
||||||
GUARDED_BY(&rsa_root_public_key_mutex_);
|
|
||||||
absl::Mutex validated_signer_cache_mutex_;
|
|
||||||
std::map<std::string, ValidatedSignerCertificate> validated_signer_cache_
|
|
||||||
GUARDED_BY(&validated_signer_cache_mutex_);
|
|
||||||
};
|
|
||||||
|
|
||||||
void ValidatedSignerCache::SetRootPublicKey(
|
|
||||||
std::unique_ptr<RsaPublicKey> new_root_key) {
|
|
||||||
absl::WriterMutexLock lock(&rsa_root_public_key_mutex_);
|
|
||||||
rsa_root_public_key_ = std::move(new_root_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ValidatedSignerCache::Exist(const std::string& serial_number,
|
|
||||||
const std::string& certificate,
|
|
||||||
const std::string& signature) {
|
|
||||||
absl::ReaderMutexLock lock(&validated_signer_cache_mutex_);
|
|
||||||
ValidatedSignerCertificate* validated_signer =
|
|
||||||
gtl::FindOrNull(validated_signer_cache_, serial_number);
|
|
||||||
return (validated_signer != nullptr) &&
|
|
||||||
(validated_signer->certificate == certificate) &&
|
|
||||||
(validated_signer->signature == signature);
|
|
||||||
}
|
|
||||||
|
|
||||||
util::Status ValidatedSignerCache::ValidateSigner(const std::string& serial_number,
|
|
||||||
const std::string& certificate,
|
|
||||||
const std::string& signature) {
|
|
||||||
{
|
|
||||||
absl::ReaderMutexLock key_lock(&rsa_root_public_key_mutex_);
|
|
||||||
if (rsa_root_public_key_ == nullptr) {
|
|
||||||
return util::Status(error_space, ROOT_CERTIFICATE_NOT_SET, "");
|
|
||||||
}
|
|
||||||
if (!rsa_root_public_key_->VerifySignature(certificate, signature)) {
|
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
|
||||||
"signer-certificate-verification-failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
absl::WriterMutexLock cache_lock(&validated_signer_cache_mutex_);
|
|
||||||
validated_signer_cache_[serial_number].certificate = certificate;
|
|
||||||
validated_signer_cache_[serial_number].signature = signature;
|
|
||||||
return util::OkStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ValidatedSignerCache::ResetSignerCache() {
|
|
||||||
absl::WriterMutexLock lock(&validated_signer_cache_mutex_);
|
|
||||||
validated_signer_cache_.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t ValidatedSignerCache::SignerCacheSize() {
|
|
||||||
absl::ReaderMutexLock lock(&validated_signer_cache_mutex_);
|
|
||||||
return validated_signer_cache_.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
ValidatedSignerCache* ValidatedSignerCache::GetSingleton() {
|
|
||||||
static auto* const kInstance = new ValidatedSignerCache();
|
|
||||||
return kInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
// TODO(user): change to util::StatusOr<std::unique_ptr<ClientCert>>
|
|
||||||
// instead of ClientCert** to explicitly assigning ownership of the created
|
|
||||||
// object to the caller.
|
|
||||||
|
|
||||||
util::Status ClientCert::Create(ClientIdentification::TokenType token_type,
|
|
||||||
const std::string& token, ClientCert** client_cert) {
|
|
||||||
DCHECK(client_cert);
|
|
||||||
if (token_type == ClientIdentification::KEYBOX) {
|
|
||||||
*client_cert = nullptr;
|
|
||||||
if (token.size() < kKeyboxSizeBytes) {
|
|
||||||
return util::Status(error_space, INVALID_KEYBOX_TOKEN,
|
|
||||||
"keybox-token-is-too-short");
|
|
||||||
}
|
|
||||||
return ClientCert::CreateWithToken(token, client_cert);
|
|
||||||
} else if (token_type == ClientIdentification::DRM_DEVICE_CERTIFICATE) {
|
|
||||||
return CreateCertificateClientCert(token, client_cert);
|
|
||||||
} else {
|
|
||||||
return util::Status(error_space, util::error::UNIMPLEMENTED,
|
|
||||||
"client-type-not-implemented");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
util::Status ClientCert::CreateWithToken(const std::string& keybox_token,
|
|
||||||
ClientCert** client_cert) {
|
|
||||||
*client_cert = nullptr;
|
|
||||||
std::unique_ptr<ClientCert> ret(new KeyboxClientCert(keybox_token));
|
|
||||||
if (ret->status() != util::OkStatus()) {
|
|
||||||
return ret->status();
|
|
||||||
}
|
|
||||||
*client_cert = ret.release();
|
|
||||||
return util::OkStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
util::Status ClientCert::CreateCertificateClientCert(
|
|
||||||
const std::string& drm_certificate, ClientCert** client_cert) {
|
|
||||||
std::unique_ptr<ClientCert> ret(new CertificateClientCert(drm_certificate));
|
|
||||||
if (ret->status() != util::OkStatus()) {
|
|
||||||
return ret->status();
|
|
||||||
}
|
|
||||||
*client_cert = ret.release();
|
|
||||||
return util::OkStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClientCert::CreateSignature(const std::string& message, std::string* signature) {
|
|
||||||
DCHECK(signature);
|
|
||||||
DCHECK(!signing_key().empty());
|
|
||||||
if (signature == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
using crypto_util::CreateSignatureHmacSha256;
|
|
||||||
*signature =
|
|
||||||
CreateSignatureHmacSha256(GetServerSigningKey(signing_key()), message);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClientCert::GenerateSigningKey(const std::string& message,
|
|
||||||
ProtocolVersion protocol_version) {
|
|
||||||
if (!signing_key_.empty()) return;
|
|
||||||
DCHECK(!key().empty());
|
|
||||||
using crypto_util::DeriveKey;
|
|
||||||
using crypto_util::kSigningKeyLabel;
|
|
||||||
set_signing_key(DeriveKey(key(), kSigningKeyLabel, message,
|
|
||||||
SigningKeyMaterialSize(protocol_version)));
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyboxClientCert::~KeyboxClientCert() {}
|
|
||||||
|
|
||||||
void KeyboxClientCert::SetPreProvisioningKeys(
|
|
||||||
const std::multimap<uint32_t, std::string>& keymap) {
|
|
||||||
std::vector<WvmTokenHandler::PreprovKey> keyvector;
|
|
||||||
keyvector.reserve(keymap.size());
|
|
||||||
for (std::multimap<uint32_t, std::string>::const_iterator it = keymap.begin();
|
|
||||||
it != keymap.end(); ++it) {
|
|
||||||
std::string key = absl::HexStringToBytes(it->second);
|
|
||||||
DCHECK_EQ(key.size(), 16);
|
|
||||||
keyvector.push_back(WvmTokenHandler::PreprovKey(it->first, key));
|
|
||||||
}
|
|
||||||
WvmTokenHandler::SetPreprovKeys(keyvector);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool KeyboxClientCert::IsSystemIdKnown(const uint32_t system_id) {
|
|
||||||
return WvmTokenHandler::IsSystemIdKnown(system_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t KeyboxClientCert::GetSystemId(const std::string& keybox_bytes) {
|
|
||||||
return WvmTokenHandler::GetSystemId(keybox_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyboxClientCert::KeyboxClientCert(const std::string& keybox_bytes) {
|
|
||||||
if (keybox_bytes.size() < kKeyboxSizeBytes) {
|
|
||||||
set_status(util::Status(error_space, INVALID_KEYBOX_TOKEN,
|
|
||||||
"keybox-token-is-too-short"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
set_system_id(WvmTokenHandler::GetSystemId(keybox_bytes));
|
|
||||||
set_serial_number(WvmTokenHandler::GetEncryptedUniqueId(keybox_bytes));
|
|
||||||
bool insecure_keybox = false;
|
|
||||||
util::Status status = WvmTokenHandler::DecryptDeviceKey(
|
|
||||||
keybox_bytes, &device_key_, nullptr, &insecure_keybox);
|
|
||||||
if (!status.ok()) {
|
|
||||||
Errors new_code = status.error_code() == util::error::NOT_FOUND
|
|
||||||
? MISSING_PRE_PROV_KEY
|
|
||||||
: KEYBOX_DECRYPT_ERROR;
|
|
||||||
set_status(util::Status(error_space, new_code, status.error_message()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool KeyboxClientCert::VerifySignature(const std::string& message,
|
|
||||||
const std::string& signature,
|
|
||||||
ProtocolVersion protocol_version) {
|
|
||||||
DCHECK(!signing_key().empty());
|
|
||||||
using crypto_util::VerifySignatureHmacSha256;
|
|
||||||
if (!VerifySignatureHmacSha256(
|
|
||||||
GetClientSigningKey(signing_key(), protocol_version), signature,
|
|
||||||
message)) {
|
|
||||||
set_status(util::Status(error_space, INVALID_SIGNATURE, ""));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
util::Status CertificateClientCert::SetDrmRootCertificatePublicKey(
|
|
||||||
const std::string& root_public_key) {
|
|
||||||
std::unique_ptr<RsaPublicKey> new_root_key(
|
|
||||||
RsaPublicKey::Create(root_public_key));
|
|
||||||
if (new_root_key == nullptr) {
|
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
|
||||||
"root-certificate-rsa-public-key-failed");
|
|
||||||
}
|
|
||||||
ValidatedSignerCache::GetSingleton()->SetRootPublicKey(
|
|
||||||
std::move(new_root_key));
|
|
||||||
return util::OkStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checks the device certificate using the following steps.
|
|
||||||
// 1. Load the certificate bytes into a signed device certificate.
|
|
||||||
// 2. Get the signer for the certificate.
|
|
||||||
// 3. Verify the signature of the certificate using the signer.
|
|
||||||
// 4. Load the root certificate.
|
|
||||||
// 5. Verify the signature of the signer certificate.
|
|
||||||
util::Status CertificateClientCert::ValidateCertificate(
|
|
||||||
const SignedDrmCertificate& signed_drm_certificate) {
|
|
||||||
// TODO(user): Cache valid certificates.
|
|
||||||
// TODO(user): Find out why signed_drm_certificate.has_signer() always
|
|
||||||
// returns false. Blindly assuming signer is there for now.
|
|
||||||
const SignedDrmCertificate& signer = signed_drm_certificate.signer();
|
|
||||||
DrmCertificate intermediate_certificate;
|
|
||||||
if (!intermediate_certificate.ParseFromString(signer.drm_certificate())) {
|
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
|
||||||
"device-certificate-invalid-signer");
|
|
||||||
}
|
|
||||||
std::unique_ptr<RsaPublicKey> rsa_public_signer_key(
|
|
||||||
RsaPublicKey::Create(intermediate_certificate.public_key()));
|
|
||||||
if (!rsa_public_signer_key.get()) {
|
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
|
||||||
"signer-certificate-public-key-failed");
|
|
||||||
}
|
|
||||||
if (!rsa_public_signer_key->VerifySignature(
|
|
||||||
signed_drm_certificate.drm_certificate(),
|
|
||||||
signed_drm_certificate.signature())) {
|
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
|
||||||
"device-certificate-verification-failed");
|
|
||||||
}
|
|
||||||
if (!intermediate_certificate.has_serial_number()) {
|
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
|
||||||
"missing-signer-serial-number");
|
|
||||||
}
|
|
||||||
// Check to see if this intermediate device certificate is signed by a
|
|
||||||
// provisioner (entity using Widevine Provisioning Server SDK).
|
|
||||||
// TODO(user): refactor this code for clarity with the cert chaining.
|
|
||||||
if (signer.has_signer()) {
|
|
||||||
DrmCertificate provisioner_certificate;
|
|
||||||
if (!provisioner_certificate.ParseFromString(
|
|
||||||
signer.signer().drm_certificate())) {
|
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
|
||||||
"intermediate-certificate-invalid-signer");
|
|
||||||
}
|
|
||||||
if (provisioner_certificate.type() == DrmCertificate::PROVISIONER) {
|
|
||||||
set_signed_by_provisioner(true);
|
|
||||||
} else {
|
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
|
||||||
"expected-provisioning-provider-certificate-type");
|
|
||||||
}
|
|
||||||
if (!CheckSignerCache(provisioner_certificate.serial_number(),
|
|
||||||
signer.signer().drm_certificate(),
|
|
||||||
signer.signature())) {
|
|
||||||
util::Status status = ValidateSigner(
|
|
||||||
provisioner_certificate.serial_number(),
|
|
||||||
signer.signer().drm_certificate(), signer.signer().signature());
|
|
||||||
if (!status.ok()) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!provisioner_certificate.has_provider_id() ||
|
|
||||||
provisioner_certificate.provider_id().empty()) {
|
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
|
||||||
"missing-provisioning-service-id");
|
|
||||||
}
|
|
||||||
set_service_id(provisioner_certificate.provider_id());
|
|
||||||
} else {
|
|
||||||
if (!CheckSignerCache(intermediate_certificate.serial_number(),
|
|
||||||
signer.drm_certificate(), signer.signature())) {
|
|
||||||
util::Status status =
|
|
||||||
ValidateSigner(intermediate_certificate.serial_number(),
|
|
||||||
signer.drm_certificate(), signer.signature());
|
|
||||||
if (!status.ok()) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
set_signer_serial_number(intermediate_certificate.serial_number());
|
|
||||||
set_signer_creation_time_seconds(
|
|
||||||
intermediate_certificate.creation_time_seconds());
|
|
||||||
return util::OkStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
CertificateClientCert::CertificateClientCert(
|
|
||||||
const std::string& signed_drm_certificate_bytes) {
|
|
||||||
SignedDrmCertificate signed_drm_certificate;
|
|
||||||
if (!signed_drm_certificate.ParseFromString(signed_drm_certificate_bytes)) {
|
|
||||||
set_status(util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
|
||||||
"device-certificate-invalid-token"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
util::Status status = ValidateCertificate(signed_drm_certificate);
|
|
||||||
if (!status.ok()) {
|
|
||||||
set_status(status);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
DrmCertificate drm_certificate;
|
|
||||||
if (!drm_certificate.ParseFromString(
|
|
||||||
signed_drm_certificate.drm_certificate())) {
|
|
||||||
set_status(util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
|
||||||
"device-certificate-invalid"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!drm_certificate.has_system_id()) {
|
|
||||||
set_status(util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
|
||||||
"device-certificate-missing-system-id"));
|
|
||||||
}
|
|
||||||
set_system_id(drm_certificate.system_id());
|
|
||||||
set_serial_number(drm_certificate.serial_number());
|
|
||||||
set_public_key(drm_certificate.public_key());
|
|
||||||
rsa_public_key_.reset(RsaPublicKey::Create(public_key()));
|
|
||||||
if (rsa_public_key_ == nullptr) {
|
|
||||||
set_status(util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
|
||||||
"device-certificate-public-key-failed"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
set_key(Random16Bytes());
|
|
||||||
if (!rsa_public_key_->Encrypt(key(), &encrypted_session_key_)) {
|
|
||||||
set_status(util::Status(error_space, ENCRYPT_ERROR,
|
|
||||||
"device-certificate-failed-encrypt-session-key"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CertificateClientCert::~CertificateClientCert() {}
|
|
||||||
|
|
||||||
bool CertificateClientCert::VerifySignature(const std::string& message,
|
|
||||||
const std::string& signature,
|
|
||||||
ProtocolVersion protocol_version) {
|
|
||||||
if (!rsa_public_key_->VerifySignature(message, signature)) {
|
|
||||||
set_status(util::Status(error_space, INVALID_SIGNATURE, ""));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CertificateClientCert::CheckSignerCache(const std::string& serial_number,
|
|
||||||
const std::string& certificate,
|
|
||||||
const std::string& signature) const {
|
|
||||||
return ValidatedSignerCache::GetSingleton()->Exist(serial_number, certificate,
|
|
||||||
signature);
|
|
||||||
}
|
|
||||||
|
|
||||||
util::Status CertificateClientCert::ValidateSigner(const std::string& serial_number,
|
|
||||||
const std::string& certificate,
|
|
||||||
const std::string& signature) {
|
|
||||||
return ValidatedSignerCache::GetSingleton()->ValidateSigner(
|
|
||||||
serial_number, certificate, signature);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CertificateClientCert::ResetSignerCache() {
|
|
||||||
ValidatedSignerCache::GetSingleton()->ResetSignerCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t CertificateClientCert::SignerCacheSize() {
|
|
||||||
return ValidatedSignerCache::GetSingleton()->SignerCacheSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace widevine
|
|
||||||
@@ -26,9 +26,9 @@
|
|||||||
#include "util/endian/endian.h"
|
#include "util/endian/endian.h"
|
||||||
#include "util/random/global_id.h"
|
#include "util/random/global_id.h"
|
||||||
#include "common/aes_cbc_util.h"
|
#include "common/aes_cbc_util.h"
|
||||||
#include "common/certificate_type.h"
|
#include "common/client_cert.h"
|
||||||
#include "common/certificate_util.h"
|
|
||||||
#include "common/crypto_util.h"
|
#include "common/crypto_util.h"
|
||||||
|
#include "common/device_status_list.h"
|
||||||
#include "common/drm_root_certificate.h"
|
#include "common/drm_root_certificate.h"
|
||||||
#include "common/drm_service_certificate.h"
|
#include "common/drm_service_certificate.h"
|
||||||
#include "common/error_space.h"
|
#include "common/error_space.h"
|
||||||
@@ -38,8 +38,6 @@
|
|||||||
#include "common/signing_key_util.h"
|
#include "common/signing_key_util.h"
|
||||||
#include "common/verified_media_pipeline.h"
|
#include "common/verified_media_pipeline.h"
|
||||||
#include "common/vmp_checker.h"
|
#include "common/vmp_checker.h"
|
||||||
#include "license_server_sdk/internal/client_cert.h"
|
|
||||||
#include "license_server_sdk/internal/device_status_list.h"
|
|
||||||
#include "license_server_sdk/internal/generate_error_response.h"
|
#include "license_server_sdk/internal/generate_error_response.h"
|
||||||
#include "license_server_sdk/internal/key_control_block.h"
|
#include "license_server_sdk/internal/key_control_block.h"
|
||||||
#include "license_server_sdk/internal/parse_content_id.h"
|
#include "license_server_sdk/internal/parse_content_id.h"
|
||||||
@@ -93,26 +91,38 @@ void SessionImpl::SetPreProvisioningKeys(
|
|||||||
}
|
}
|
||||||
|
|
||||||
util::Status SessionImpl::SetCertificateStatusList(
|
util::Status SessionImpl::SetCertificateStatusList(
|
||||||
CertificateType cert_type, const std::string& certificate_status_list,
|
const DrmRootCertificate* root_cert, const std::string& certificate_status_list,
|
||||||
uint32_t expiration_period_seconds, bool allow_unknown_devices) {
|
uint32_t expiration_period_seconds, bool allow_unknown_devices) {
|
||||||
return widevine::SetCertificateStatusList(
|
CHECK(root_cert);
|
||||||
cert_type, certificate_status_list, expiration_period_seconds,
|
|
||||||
|
util::Status status = DeviceStatusList::Instance()->UpdateStatusList(
|
||||||
|
root_cert->public_key(), certificate_status_list,
|
||||||
|
expiration_period_seconds);
|
||||||
|
if (!status.ok()) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
DeviceStatusList::Instance()->set_allow_unknown_devices(
|
||||||
allow_unknown_devices);
|
allow_unknown_devices);
|
||||||
|
|
||||||
|
return util::OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status SessionImpl::AddDrmServiceCertificate(
|
util::Status SessionImpl::AddDrmServiceCertificate(
|
||||||
CertificateType cert_type, const std::string& service_certificate,
|
const DrmRootCertificate* root_cert, const std::string& service_certificate,
|
||||||
const std::string& service_private_key,
|
const std::string& service_private_key,
|
||||||
const std::string& service_private_key_passphrase) {
|
const std::string& service_private_key_passphrase) {
|
||||||
util::Status status = widevine::AddDrmServiceCertificate(
|
CHECK(root_cert);
|
||||||
cert_type, service_certificate, service_private_key,
|
|
||||||
|
util::Status status = DrmServiceCertificate::AddDrmServiceCertificate(
|
||||||
|
root_cert, service_certificate, service_private_key,
|
||||||
service_private_key_passphrase);
|
service_private_key_passphrase);
|
||||||
if (!status.ok()) return status;
|
if (!status.ok()) {
|
||||||
status = DrmServiceCertificate::ValidateDrmServiceCertificate();
|
return status;
|
||||||
if (status.ok()) {
|
|
||||||
is_service_certificate_loaded_ = true;
|
|
||||||
}
|
}
|
||||||
return status;
|
is_service_certificate_loaded_ = true;
|
||||||
|
|
||||||
|
// TODO(user): Remove the need for this by having a LicenseEngine.
|
||||||
|
return VmpChecker::Instance()->SelectCertificateType(root_cert->type());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SessionImpl::AllowDevelopmentClients(bool enable) {
|
void SessionImpl::AllowDevelopmentClients(bool enable) {
|
||||||
@@ -124,22 +134,24 @@ void SessionImpl::AllowRevokedDevices(const std::string& system_id_list) {
|
|||||||
DeviceStatusList::Instance()->AllowRevokedDevices(system_id_list);
|
DeviceStatusList::Instance()->AllowRevokedDevices(system_id_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status SessionImpl::Create(const std::string& signed_license_request,
|
util::Status SessionImpl::Create(const DrmRootCertificate* root_cert,
|
||||||
|
const std::string& signed_license_request,
|
||||||
SessionImpl** session) {
|
SessionImpl** session) {
|
||||||
util::Status status(util::OkStatus());
|
|
||||||
if (!is_service_certificate_loaded_) {
|
if (!is_service_certificate_loaded_) {
|
||||||
status = util::Status(error_space, SERVICE_CERTIFICATE_NOT_FOUND, "");
|
return util::Status(error_space, SERVICE_CERTIFICATE_NOT_FOUND, "");
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
return SessionImpl::Create(signed_license_request, session, nullptr);
|
return SessionImpl::Create(root_cert, signed_license_request, session,
|
||||||
|
nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status SessionImpl::Create(const std::string& signed_license_request,
|
util::Status SessionImpl::Create(const DrmRootCertificate* root_cert,
|
||||||
|
const std::string& signed_license_request,
|
||||||
SessionImpl** session,
|
SessionImpl** session,
|
||||||
LicenseRequest* parsed_request_out) {
|
LicenseRequest* parsed_request_out) {
|
||||||
util::Status status(util::OkStatus());
|
CHECK(root_cert);
|
||||||
DCHECK(session);
|
DCHECK(session);
|
||||||
DCHECK(*session == NULL);
|
|
||||||
|
util::Status status;
|
||||||
|
|
||||||
LicenseRequest* request_ptr = new LicenseRequest();
|
LicenseRequest* request_ptr = new LicenseRequest();
|
||||||
SignedMessage* signed_message_ptr = new SignedMessage();
|
SignedMessage* signed_message_ptr = new SignedMessage();
|
||||||
@@ -181,7 +193,7 @@ util::Status SessionImpl::Create(const std::string& signed_license_request,
|
|||||||
std::unique_ptr<SessionImpl> new_session(
|
std::unique_ptr<SessionImpl> new_session(
|
||||||
new SessionImpl(signed_message.release(), request.release(),
|
new SessionImpl(signed_message.release(), request.release(),
|
||||||
has_key_control_nonce, key_control_nonce, nullptr));
|
has_key_control_nonce, key_control_nonce, nullptr));
|
||||||
status = new_session->Init();
|
status = new_session->Init(root_cert);
|
||||||
if (status.ok()) {
|
if (status.ok()) {
|
||||||
*session = new_session.release();
|
*session = new_session.release();
|
||||||
}
|
}
|
||||||
@@ -189,7 +201,7 @@ util::Status SessionImpl::Create(const std::string& signed_license_request,
|
|||||||
}
|
}
|
||||||
|
|
||||||
util::Status SessionImpl::CreateForProxy(
|
util::Status SessionImpl::CreateForProxy(
|
||||||
const std::string& signed_license_request,
|
const DrmRootCertificate* root_cert, const std::string& signed_license_request,
|
||||||
const PlatformVerificationStatus platform_verification_status,
|
const PlatformVerificationStatus platform_verification_status,
|
||||||
const ClientIdentification* client_id, SessionImpl** session,
|
const ClientIdentification* client_id, SessionImpl** session,
|
||||||
LicenseRequest* parsed_request_out) {
|
LicenseRequest* parsed_request_out) {
|
||||||
@@ -229,7 +241,7 @@ util::Status SessionImpl::CreateForProxy(
|
|||||||
has_key_control_nonce, key_control_nonce, nullptr));
|
has_key_control_nonce, key_control_nonce, nullptr));
|
||||||
if (platform_verification_status != PLATFORM_NO_VERIFICATION) {
|
if (platform_verification_status != PLATFORM_NO_VERIFICATION) {
|
||||||
}
|
}
|
||||||
status = new_session->Init();
|
status = new_session->Init(root_cert);
|
||||||
if (status.ok()) {
|
if (status.ok()) {
|
||||||
*session = new_session.release();
|
*session = new_session.release();
|
||||||
}
|
}
|
||||||
@@ -335,13 +347,13 @@ SessionImpl::SessionImpl(SignedMessage* message, LicenseRequest* request,
|
|||||||
|
|
||||||
SessionImpl::~SessionImpl() {}
|
SessionImpl::~SessionImpl() {}
|
||||||
|
|
||||||
util::Status SessionImpl::Init() {
|
util::Status SessionImpl::Init(const DrmRootCertificate* root_cert) {
|
||||||
if (license_request_->has_client_id()) {
|
if (license_request_->has_client_id()) {
|
||||||
// Check the client token and verify the message signature.
|
// Check the client token and verify the message signature.
|
||||||
ClientCert* client_cert_ptr = NULL;
|
ClientCert* client_cert_ptr = NULL;
|
||||||
|
|
||||||
util::Status status = ClientCert::Create(
|
util::Status status = ClientCert::Create(
|
||||||
license_request_->client_id().type(),
|
root_cert, license_request_->client_id().type(),
|
||||||
license_request_->client_id().token(), &client_cert_ptr);
|
license_request_->client_id().token(), &client_cert_ptr);
|
||||||
client_cert_.reset(client_cert_ptr);
|
client_cert_.reset(client_cert_ptr);
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
@@ -369,10 +381,11 @@ util::Status SessionImpl::Init() {
|
|||||||
// Generate/Derive a new signing key if one does not previously exist.
|
// Generate/Derive a new signing key if one does not previously exist.
|
||||||
client_cert_->GenerateSigningKey(signed_message_->msg(),
|
client_cert_->GenerateSigningKey(signed_message_->msg(),
|
||||||
license_request_->protocol_version());
|
license_request_->protocol_version());
|
||||||
if (!client_cert_->VerifySignature(
|
util::Status status = client_cert_->VerifySignature(
|
||||||
signed_message_->msg(), signed_message_->signature(),
|
signed_message_->msg(), signed_message_->signature(),
|
||||||
license_request_->protocol_version())) {
|
license_request_->protocol_version());
|
||||||
return client_cert_->status();
|
if (!status.ok()) {
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -829,13 +842,14 @@ util::Status SessionImpl::GenerateSignedLicense(
|
|||||||
if (provisioned_device_info_) {
|
if (provisioned_device_info_) {
|
||||||
system_id = provisioned_device_info_->system_id();
|
system_id = provisioned_device_info_->system_id();
|
||||||
}
|
}
|
||||||
std::unique_ptr<RsaPublicKey> rsa_public_key;
|
|
||||||
if (client_cert_ != nullptr) {
|
if (client_cert_ != nullptr) {
|
||||||
rsa_public_key.reset(RsaPublicKey::Create(client_cert_->public_key()));
|
if (client_cert_->type() == ClientIdentification::DRM_DEVICE_CERTIFICATE) {
|
||||||
if (client_cert_->type() == ClientIdentification::DRM_DEVICE_CERTIFICATE &&
|
std::unique_ptr<RsaPublicKey> rsa_public_key;
|
||||||
rsa_public_key == nullptr) {
|
rsa_public_key.reset(RsaPublicKey::Create(client_cert_->public_key()));
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
if (rsa_public_key == nullptr) {
|
||||||
"create-device-public-key-failed");
|
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
|
"create-device-public-key-failed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0; i < license.key_size(); ++i) {
|
for (int i = 0; i < license.key_size(); ++i) {
|
||||||
@@ -946,10 +960,6 @@ bool SessionImpl::GenerateErrorResponse(const util::Status& status,
|
|||||||
return widevine::GenerateErrorResponse(status, signed_message_bytes);
|
return widevine::GenerateErrorResponse(status, signed_message_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SessionImpl::GetRootCertificateDigest(CertificateType cert_type) {
|
|
||||||
return DrmRootCertificate::GetDigest(cert_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string SessionImpl::GetSdkVersionString() {
|
std::string SessionImpl::GetSdkVersionString() {
|
||||||
return absl::StrCat(kMajorVersion, ".", kMinorVersion, ".", kRelease);
|
return absl::StrCat(kMajorVersion, ".", kMinorVersion, ".", kRelease);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include "base/macros.h"
|
#include "base/macros.h"
|
||||||
#include "util/status.h"
|
#include "util/status.h"
|
||||||
#include "common/certificate_type.h"
|
|
||||||
#include "absl/synchronization/mutex.h"
|
#include "absl/synchronization/mutex.h"
|
||||||
#include "protos/public/client_identification.pb.h"
|
#include "protos/public/client_identification.pb.h"
|
||||||
#include "protos/public/license_protocol.pb.h"
|
#include "protos/public/license_protocol.pb.h"
|
||||||
@@ -28,6 +27,7 @@ namespace widevine {
|
|||||||
|
|
||||||
class ClientCert;
|
class ClientCert;
|
||||||
class ClientIdentification;
|
class ClientIdentification;
|
||||||
|
class DrmRootCertificate;
|
||||||
class ContentInfo;
|
class ContentInfo;
|
||||||
class SessionInit;
|
class SessionInit;
|
||||||
class SessionState;
|
class SessionState;
|
||||||
@@ -53,19 +53,20 @@ std::string GetProviderClientToken(const SessionInit& session_init,
|
|||||||
// license request. Example usage:
|
// license request. Example usage:
|
||||||
// Session::SetPreProvisioningKeys(<hex formatted std::string>);
|
// Session::SetPreProvisioningKeys(<hex formatted std::string>);
|
||||||
// Session::SetCertificateStatusList(
|
// Session::SetCertificateStatusList(
|
||||||
// widevine::sdk::kCertificateTypeProduction,
|
// root_cert,
|
||||||
// cert_status_list,
|
// cert_status_list,
|
||||||
// expiration_period_seconds,
|
// expiration_period_seconds,
|
||||||
// /* allow unknown device */ false);
|
// /* allow unknown device */ false);
|
||||||
// Session::AddDrmServiceCertificate(
|
// Session::AddDrmServiceCertificate(
|
||||||
// widevine::sdk::kCertificateTypeProduction,
|
// root_cert,
|
||||||
// service_certificate,
|
// service_certificate,
|
||||||
// service_private_key,
|
// service_private_key,
|
||||||
// service_private_key_passphrase);
|
// service_private_key_passphrase);
|
||||||
// std::string signed_license_request;
|
// std::string signed_license_request;
|
||||||
// // assign signed_license_request to incoming license request.
|
// // assign signed_license_request to incoming license request.
|
||||||
// Session* session = NULL;
|
// Session* session = NULL;
|
||||||
// util::Status status = Session::Create(signed_license_request, &session);
|
// util::Status status = Session::Create(root_cert, signed_license_request,
|
||||||
|
// &session);
|
||||||
// if (!status.ok()) {
|
// if (!status.ok()) {
|
||||||
// std::string error_license;
|
// std::string error_license;
|
||||||
// if (Session::GenerateErrorResponse(status, &error_license)) {
|
// if (Session::GenerateErrorResponse(status, &error_license)) {
|
||||||
@@ -105,25 +106,26 @@ class SessionImpl {
|
|||||||
static void SetPreProvisioningKeys(const std::map<uint32_t, std::string>& keys);
|
static void SetPreProvisioningKeys(const std::map<uint32_t, std::string>& keys);
|
||||||
static void SetPreProvisioningKeys(const std::multimap<uint32_t, std::string>& keys);
|
static void SetPreProvisioningKeys(const std::multimap<uint32_t, std::string>& keys);
|
||||||
|
|
||||||
// Set the certificate status list system-wide. |cert_type| specifies
|
// Set the certificate status list system-wide. |root_cert| is the root
|
||||||
// whether to use development or production root certificates.
|
// certificate which signed the DCSL.
|
||||||
// |expiration_period| is the number of seconds until the
|
// |expiration_period| is the number of seconds until the
|
||||||
// certificate_status_list expires after its creation time
|
// certificate_status_list expires after its creation time
|
||||||
// (creation_time_seconds). If |allow_unknown_devices| is false, an error is
|
// (creation_time_seconds). If |allow_unknown_devices| is false, an error is
|
||||||
// returned if the device does not appear in the certificate_status_list.
|
// returned if the device does not appear in the certificate_status_list.
|
||||||
static util::Status SetCertificateStatusList(
|
static util::Status SetCertificateStatusList(
|
||||||
CertificateType cert_type, const std::string& certificate_status_list,
|
const DrmRootCertificate* root_cert,
|
||||||
uint32_t expiration_period_seconds, bool allow_unknown_devices);
|
const std::string& certificate_status_list, uint32_t expiration_period_seconds,
|
||||||
|
bool allow_unknown_devices);
|
||||||
|
|
||||||
// Add a service certificate system-wide. |cert_type| indicates the type of
|
// Add a service certificate system-wide. |root_cert| is the root certificate
|
||||||
// root certificate used to sign the service certificate;
|
// which signed the service certificate;
|
||||||
// |service_certificate| is a Google-generated certificate used to
|
// |service_certificate| is a Google-generated certificate used to
|
||||||
// authenticate the service provider for purposes of device privacy;
|
// authenticate the service provider for purposes of device privacy;
|
||||||
// |service_private_key| is the encrypted PKCS#8 private RSA key corresponding
|
// |service_private_key| is the encrypted PKCS#8 private RSA key corresponding
|
||||||
// to the service certificate; and |service_private_key_passphrase| is the
|
// to the service certificate; and |service_private_key_passphrase| is the
|
||||||
// password required to decrypt |service_private_key|.
|
// password required to decrypt |service_private_key|.
|
||||||
static util::Status AddDrmServiceCertificate(
|
static util::Status AddDrmServiceCertificate(
|
||||||
CertificateType cert_type, const std::string& service_certificate,
|
const DrmRootCertificate* root_cert, const std::string& service_certificate,
|
||||||
const std::string& service_private_key,
|
const std::string& service_private_key,
|
||||||
const std::string& service_private_key_passphrase);
|
const std::string& service_private_key_passphrase);
|
||||||
|
|
||||||
@@ -146,7 +148,8 @@ class SessionImpl {
|
|||||||
// Session::GenerateErrorResponse should be invoked.
|
// Session::GenerateErrorResponse should be invoked.
|
||||||
// Example usage:
|
// Example usage:
|
||||||
// Session* session = NULL;
|
// Session* session = NULL;
|
||||||
// util::Status status = Session::Create(request_from_client, &session);
|
// util::Status status = Session::Create(root_cert, request_from_client,
|
||||||
|
// &session);
|
||||||
// if (!status.ok()) {
|
// if (!status.ok()) {
|
||||||
// std::string error_license;
|
// std::string error_license;
|
||||||
// if (Session::GenerateErrorResponse(status, &error_license)) {
|
// if (Session::GenerateErrorResponse(status, &error_license)) {
|
||||||
@@ -157,12 +160,14 @@ class SessionImpl {
|
|||||||
// return ...
|
// return ...
|
||||||
// }
|
// }
|
||||||
// // Create license, invoke GenerateSignedLicense, etc.
|
// // Create license, invoke GenerateSignedLicense, etc.
|
||||||
static util::Status Create(const std::string& signed_license_request,
|
static util::Status Create(const DrmRootCertificate* root_cert,
|
||||||
|
const std::string& signed_license_request,
|
||||||
SessionImpl** session);
|
SessionImpl** session);
|
||||||
|
|
||||||
// Variation of Session::Create which also fills in the parsed LicenseRequest,
|
// Variation of Session::Create which also fills in the parsed LicenseRequest,
|
||||||
// for use in logging or debugging.
|
// for use in logging or debugging.
|
||||||
static util::Status Create(const std::string& signed_license_request,
|
static util::Status Create(const DrmRootCertificate* root_cert,
|
||||||
|
const std::string& signed_license_request,
|
||||||
SessionImpl** session,
|
SessionImpl** session,
|
||||||
LicenseRequest* parsed_request_out);
|
LicenseRequest* parsed_request_out);
|
||||||
|
|
||||||
@@ -180,7 +185,7 @@ class SessionImpl {
|
|||||||
// clear client identification in |client_id| and the platform verification
|
// clear client identification in |client_id| and the platform verification
|
||||||
// in |platform_verification_status|.
|
// in |platform_verification_status|.
|
||||||
static util::Status CreateForProxy(
|
static util::Status CreateForProxy(
|
||||||
const std::string& signed_license_request,
|
const DrmRootCertificate* root_cert, const std::string& signed_license_request,
|
||||||
const PlatformVerificationStatus platform_verification_status,
|
const PlatformVerificationStatus platform_verification_status,
|
||||||
const ClientIdentification* client_id, SessionImpl** session,
|
const ClientIdentification* client_id, SessionImpl** session,
|
||||||
LicenseRequest* parsed_request_out);
|
LicenseRequest* parsed_request_out);
|
||||||
@@ -203,11 +208,6 @@ class SessionImpl {
|
|||||||
static std::string DeriveKey(const std::string& key, const std::string& label,
|
static std::string DeriveKey(const std::string& key, const std::string& label,
|
||||||
const std::string& context, const uint32_t size_bits);
|
const std::string& context, const uint32_t size_bits);
|
||||||
|
|
||||||
// Returns a std::string containing the hex-encoded SHA-256 digest of the root
|
|
||||||
// certificate specified by |cert_type|. Used for purposes of root certificate
|
|
||||||
// verification.
|
|
||||||
static std::string GetRootCertificateDigest(CertificateType cert_type);
|
|
||||||
|
|
||||||
// Returns a std::string containing the Widevine License Server SDK version in the
|
// Returns a std::string containing the Widevine License Server SDK version in the
|
||||||
// form <major_version>.<minor_version>.<release> <build date> <build time> .
|
// form <major_version>.<minor_version>.<release> <build date> <build time> .
|
||||||
static std::string GetSdkVersionString();
|
static std::string GetSdkVersionString();
|
||||||
@@ -310,7 +310,7 @@ class SessionImpl {
|
|||||||
uint32_t nonce, widevine::ProvisionedDeviceInfo* device_info);
|
uint32_t nonce, widevine::ProvisionedDeviceInfo* device_info);
|
||||||
|
|
||||||
// Called by the SessionImpl::Create factory to initialize a new session.
|
// Called by the SessionImpl::Create factory to initialize a new session.
|
||||||
util::Status Init();
|
util::Status Init(const DrmRootCertificate* root_cert);
|
||||||
util::Status GenerateNewLicenseInfo(/*IN*/ const SessionInit* session_init,
|
util::Status GenerateNewLicenseInfo(/*IN*/ const SessionInit* session_init,
|
||||||
/*OUT*/ LicenseIdentification* new_id,
|
/*OUT*/ LicenseIdentification* new_id,
|
||||||
/*OUT*/ std::string* renewal_signing_key,
|
/*OUT*/ std::string* renewal_signing_key,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -26,14 +26,7 @@ WvPLCASProxyEnvironment::WvPLCASProxyEnvironment(
|
|||||||
std::map<std::string, std::string>::const_iterator it =
|
std::map<std::string, std::string>::const_iterator it =
|
||||||
config_values.find(kDrmCertificateType);
|
config_values.find(kDrmCertificateType);
|
||||||
if (it != config_values.end()) {
|
if (it != config_values.end()) {
|
||||||
if (it->second == "dev" || it->second == "prod" || it->second == "test") {
|
drm_certificate_type_ = it->second;
|
||||||
drm_certificate_type_ = it->second;
|
|
||||||
}
|
|
||||||
if (drm_certificate_type_ == "dev") {
|
|
||||||
certificate_type_ = kCertificateTypeDevelopment;
|
|
||||||
} else if (drm_certificate_type_ == "test") {
|
|
||||||
certificate_type_ = kCertificateTypeTesting;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
it = config_values.find(kProvider);
|
it = config_values.find(kProvider);
|
||||||
if (it != config_values.end()) {
|
if (it != config_values.end()) {
|
||||||
@@ -48,6 +41,11 @@ WvPLCASProxyEnvironment::WvPLCASProxyEnvironment(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WvPLStatus WvPLCASProxyEnvironment::Initialize() {
|
||||||
|
return widevine::DrmRootCertificate::CreateByTypeString(
|
||||||
|
drm_certificate_type_, &drm_root_certificate_);
|
||||||
|
}
|
||||||
|
|
||||||
WvPLStatus WvPLCASProxyEnvironment::CreateSession(
|
WvPLStatus WvPLCASProxyEnvironment::CreateSession(
|
||||||
const std::string& cas_license_request,
|
const std::string& cas_license_request,
|
||||||
WvPLCASProxySession** cas_proxy_session) {
|
WvPLCASProxySession** cas_proxy_session) {
|
||||||
@@ -61,7 +59,8 @@ WvPLStatus WvPLCASProxyEnvironment::CreateSession(
|
|||||||
"*proxy_session is not NULL");
|
"*proxy_session is not NULL");
|
||||||
}
|
}
|
||||||
std::unique_ptr<WvPLCASProxySession> wvpl_cas_proxy_session(
|
std::unique_ptr<WvPLCASProxySession> wvpl_cas_proxy_session(
|
||||||
new WvPLCASProxySession(cas_license_request));
|
new WvPLCASProxySession(drm_root_certificate_.get(),
|
||||||
|
cas_license_request));
|
||||||
// TODO(user): Complete the license request parsing in WvPLCASProxySession.
|
// TODO(user): Complete the license request parsing in WvPLCASProxySession.
|
||||||
// status = wvpl_cas_proxy_session->ParseLicenseRequest();
|
// status = wvpl_cas_proxy_session->ParseLicenseRequest();
|
||||||
if (status.ok()) {
|
if (status.ok()) {
|
||||||
@@ -70,6 +69,11 @@ WvPLStatus WvPLCASProxyEnvironment::CreateSession(
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WvPLStatus WvPLCASProxyEnvironment::SetDeviceCertificateStatusList(
|
||||||
|
const std::string& cert_list) const {
|
||||||
|
return WvPLSDKEnvironment::SetDeviceCertificateStatusList(cert_list);
|
||||||
|
}
|
||||||
|
|
||||||
WvPLCASProxyEnvironment::~WvPLCASProxyEnvironment() {}
|
WvPLCASProxyEnvironment::~WvPLCASProxyEnvironment() {}
|
||||||
|
|
||||||
} // namespace wv_pl_sdk
|
} // namespace wv_pl_sdk
|
||||||
|
|||||||
@@ -32,6 +32,11 @@ class WvPLCASProxyEnvironment : public WvPLSDKEnvironment {
|
|||||||
*/
|
*/
|
||||||
~WvPLCASProxyEnvironment() override;
|
~WvPLCASProxyEnvironment() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* One-time initialization. Must be called after creating the environment.
|
||||||
|
*/
|
||||||
|
virtual WvPLStatus Initialize();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a session for the license request from the Widevine CDM.
|
* Creates a session for the license request from the Widevine CDM.
|
||||||
*
|
*
|
||||||
@@ -42,6 +47,17 @@ class WvPLCASProxyEnvironment : public WvPLSDKEnvironment {
|
|||||||
*/
|
*/
|
||||||
virtual WvPLStatus CreateSession(const std::string& cas_license_request,
|
virtual WvPLStatus CreateSession(const std::string& cas_license_request,
|
||||||
WvPLCASProxySession** cas_proxy_session);
|
WvPLCASProxySession** cas_proxy_session);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the certificate status list system-wide.
|
||||||
|
* |cert_list| specifies the device certificate status
|
||||||
|
* list as std::string or certificate status list response from keysmith.
|
||||||
|
*
|
||||||
|
* @param cert_list
|
||||||
|
*
|
||||||
|
* @return WvPLStatus enumeration
|
||||||
|
*/
|
||||||
|
WvPLStatus SetDeviceCertificateStatusList(const std::string& cert_list) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace wv_pl_sdk
|
} // namespace wv_pl_sdk
|
||||||
|
|||||||
@@ -25,6 +25,11 @@ PlatformVerificationStatus WvPLCASProxySession::VerifyPlatform() {
|
|||||||
return PLATFORM_NO_VERIFICATION;
|
return PLATFORM_NO_VERIFICATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WvPLCASProxySession::WvPLCASProxySession(
|
||||||
|
const widevine::DrmRootCertificate* drm_root_certificate,
|
||||||
|
const std::string& cas_license_request_from_cdm)
|
||||||
|
: WvPLSDKSession(drm_root_certificate) {}
|
||||||
|
|
||||||
WvPLStatus WvPLCASProxySession::ParsePsshData(
|
WvPLStatus WvPLCASProxySession::ParsePsshData(
|
||||||
WvPLWidevinePsshData* wvpl_widevine_pssh_data) const {
|
WvPLWidevinePsshData* wvpl_widevine_pssh_data) const {
|
||||||
// TODO(user): Implement this functionality in WvPLSdk and remove the
|
// TODO(user): Implement this functionality in WvPLSdk and remove the
|
||||||
|
|||||||
@@ -73,7 +73,9 @@ class WvPLCASProxySession : public WvPLSDKSession {
|
|||||||
friend class WvPLCASProxyEnvironmentTest;
|
friend class WvPLCASProxyEnvironmentTest;
|
||||||
friend class WvPLCASProxySessionTest;
|
friend class WvPLCASProxySessionTest;
|
||||||
|
|
||||||
explicit WvPLCASProxySession(const std::string& cas_license_request_from_cdm) {}
|
WvPLCASProxySession(
|
||||||
|
const widevine::DrmRootCertificate* drm_root_certificate,
|
||||||
|
const std::string& cas_license_request_from_cdm);
|
||||||
|
|
||||||
WvPLStatus ParsePsshData(
|
WvPLStatus ParsePsshData(
|
||||||
WvPLWidevinePsshData* wvpl_widevine_pssh_data) const override;
|
WvPLWidevinePsshData* wvpl_widevine_pssh_data) const override;
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class WvPLCASProxySessionTest : public testing::Test {
|
|||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
// TODO(user): Fill out with valid CAS License request.
|
// TODO(user): Fill out with valid CAS License request.
|
||||||
const std::string request = "";
|
const std::string request = "";
|
||||||
wvpl_cas_proxy_session_ = new WvPLCASProxySession(request);
|
wvpl_cas_proxy_session_ = new WvPLCASProxySession(nullptr, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsChromeCDM() { return wvpl_cas_proxy_session_->IsChromeCDM(); }
|
bool IsChromeCDM() { return wvpl_cas_proxy_session_->IsChromeCDM(); }
|
||||||
|
|||||||
@@ -74,6 +74,14 @@ message ClientIdentification {
|
|||||||
optional AnalogOutputCapabilities analog_output_capabilities = 10
|
optional AnalogOutputCapabilities analog_output_capabilities = 10
|
||||||
[default = ANALOG_OUTPUT_UNKNOWN];
|
[default = ANALOG_OUTPUT_UNKNOWN];
|
||||||
optional bool can_disable_analog_output = 11 [default = false];
|
optional bool can_disable_analog_output = 11 [default = false];
|
||||||
|
// Clients can indicate a performance level supported by OEMCrypto.
|
||||||
|
// This will allow applications and providers to choose an appropriate
|
||||||
|
// quality of content to serve. Currently defined tiers are
|
||||||
|
// 1 (low), 2 (medium) and 3 (high). Any other value indicate that
|
||||||
|
// the resource rating is unavailable or reporting erroneous values
|
||||||
|
// for that device. For details see,
|
||||||
|
// https://docs.google.com/document/d/1wodSYK-Unj3AgTSXqujWuBCAFC00qF85G1AhfLtqdko
|
||||||
|
optional uint32 resource_rating_tier = 12 [default = 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type of factory-provisioned device root of trust. Optional.
|
// Type of factory-provisioned device root of trust. Optional.
|
||||||
|
|||||||
@@ -236,4 +236,7 @@ enum Errors {
|
|||||||
// Invalid key size.
|
// Invalid key size.
|
||||||
INVALID_KEY_SIZE = 169;
|
INVALID_KEY_SIZE = 169;
|
||||||
|
|
||||||
|
// Invalid method parameter.
|
||||||
|
INVALID_PARAMETER = 170;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -284,6 +284,8 @@ message ModularDrmLicenseResponse {
|
|||||||
// ClientIdentification.ClientCapabilities.can_update_srm in the license
|
// ClientIdentification.ClientCapabilities.can_update_srm in the license
|
||||||
// request.
|
// request.
|
||||||
optional bool can_update_srm = 6 [default = false];
|
optional bool can_update_srm = 6 [default = false];
|
||||||
|
// SessionInit that was used when generating the license.
|
||||||
|
optional SessionInit session_init = 7;
|
||||||
}
|
}
|
||||||
optional LicenseMetadata license_metadata = 4;
|
optional LicenseMetadata license_metadata = 4;
|
||||||
message Track {
|
message Track {
|
||||||
|
|||||||
20
sdk/external/common/wvpl/BUILD
vendored
20
sdk/external/common/wvpl/BUILD
vendored
@@ -38,13 +38,14 @@ cc_library(
|
|||||||
],
|
],
|
||||||
deps = [
|
deps = [
|
||||||
# TODO(user): Refactor these deps as classes that derive from WvPLSDKSession may not rely on license SDK(s).
|
# TODO(user): Refactor these deps as classes that derive from WvPLSDKSession may not rely on license SDK(s).
|
||||||
|
":wvpl_types",
|
||||||
"//base",
|
"//base",
|
||||||
"//util:status",
|
"//util:status",
|
||||||
":wvpl_types",
|
"//common:client_cert",
|
||||||
"//common:certificate_type",
|
|
||||||
"//common:drm_service_certificate",
|
|
||||||
"//common:error_space",
|
"//common:error_space",
|
||||||
"//common:remote_attestation_verifier",
|
"//common:remote_attestation_verifier",
|
||||||
|
"//common:drm_root_certificate",
|
||||||
|
"//common:drm_service_certificate",
|
||||||
"//common:verified_media_pipeline",
|
"//common:verified_media_pipeline",
|
||||||
"//license_server_sdk/internal:sdk",
|
"//license_server_sdk/internal:sdk",
|
||||||
"//protos/public:client_identification_proto",
|
"//protos/public:client_identification_proto",
|
||||||
@@ -66,16 +67,16 @@ cc_library(
|
|||||||
],
|
],
|
||||||
deps = [
|
deps = [
|
||||||
# TODO(user): Refactor these deps as classes that derive from WvPLSDKEnvironment may not rely on license SDK(s).
|
# TODO(user): Refactor these deps as classes that derive from WvPLSDKEnvironment may not rely on license SDK(s).
|
||||||
|
":wvpl_types",
|
||||||
"//base",
|
"//base",
|
||||||
"@abseil_repo//absl/strings",
|
"@abseil_repo//absl/strings",
|
||||||
"@abseil_repo//absl/synchronization",
|
"@abseil_repo//absl/synchronization",
|
||||||
"//util:status",
|
"//util:status",
|
||||||
":wvpl_types",
|
|
||||||
"//common:aes_cbc_util",
|
"//common:aes_cbc_util",
|
||||||
"//common:certificate_type",
|
"//common:device_status_list",
|
||||||
"//common:certificate_util",
|
"//common:drm_root_certificate",
|
||||||
"//common:drm_service_certificate",
|
|
||||||
"//common:error_space",
|
"//common:error_space",
|
||||||
|
"//common:drm_service_certificate",
|
||||||
"//common:sha_util",
|
"//common:sha_util",
|
||||||
"//license_server_sdk/internal:sdk",
|
"//license_server_sdk/internal:sdk",
|
||||||
"//protos/public:device_certificate_status_proto",
|
"//protos/public:device_certificate_status_proto",
|
||||||
@@ -99,8 +100,9 @@ cc_library(
|
|||||||
"@abseil_repo//absl/synchronization",
|
"@abseil_repo//absl/synchronization",
|
||||||
"//util:status",
|
"//util:status",
|
||||||
"//common:aes_cbc_util",
|
"//common:aes_cbc_util",
|
||||||
"//common:certificate_type",
|
"//common:client_cert",
|
||||||
"//common:certificate_util",
|
"//common:device_status_list",
|
||||||
|
"//common:drm_root_certificate",
|
||||||
"//common:drm_service_certificate",
|
"//common:drm_service_certificate",
|
||||||
"//common:error_space",
|
"//common:error_space",
|
||||||
"//common:remote_attestation_verifier",
|
"//common:remote_attestation_verifier",
|
||||||
|
|||||||
39
sdk/external/common/wvpl/wvpl_sdk_environment.cc
vendored
39
sdk/external/common/wvpl/wvpl_sdk_environment.cc
vendored
@@ -12,8 +12,7 @@
|
|||||||
#include "absl/synchronization/mutex.h"
|
#include "absl/synchronization/mutex.h"
|
||||||
#include "util/status.h"
|
#include "util/status.h"
|
||||||
#include "common/aes_cbc_util.h"
|
#include "common/aes_cbc_util.h"
|
||||||
#include "common/certificate_type.h"
|
#include "common/device_status_list.h"
|
||||||
#include "common/certificate_util.h"
|
|
||||||
#include "common/drm_service_certificate.h"
|
#include "common/drm_service_certificate.h"
|
||||||
#include "common/error_space.h"
|
#include "common/error_space.h"
|
||||||
#include "common/sha_util.h"
|
#include "common/sha_util.h"
|
||||||
@@ -21,16 +20,16 @@
|
|||||||
#include "protos/public/errors.pb.h"
|
#include "protos/public/errors.pb.h"
|
||||||
|
|
||||||
namespace util = widevine::util;
|
namespace util = widevine::util;
|
||||||
using widevine::AddDrmServiceCertificate;
|
|
||||||
using widevine::DeviceCertificateStatus;
|
using widevine::DeviceCertificateStatus;
|
||||||
using widevine::DeviceCertificateStatusList;
|
using widevine::DeviceCertificateStatusList;
|
||||||
|
using widevine::DeviceStatusList;
|
||||||
using widevine::DrmServiceCertificate;
|
using widevine::DrmServiceCertificate;
|
||||||
using widevine::error_space;
|
using widevine::error_space;
|
||||||
using widevine::kCertificateTypeDevelopment;
|
using widevine::kCertificateTypeDevelopment;
|
||||||
using widevine::kCertificateTypeProduction;
|
using widevine::kCertificateTypeProduction;
|
||||||
using widevine::kCertificateTypeTesting;
|
using widevine::kCertificateTypeTesting;
|
||||||
using widevine::ProvisionedDeviceInfo;
|
using widevine::ProvisionedDeviceInfo;
|
||||||
using widevine::SetCertificateStatusList;
|
using widevine::SignedDeviceCertificateStatusList;
|
||||||
using widevine::crypto_util::EncryptAesCbc;
|
using widevine::crypto_util::EncryptAesCbc;
|
||||||
|
|
||||||
namespace widevine_server {
|
namespace widevine_server {
|
||||||
@@ -74,8 +73,9 @@ ProvisionedDeviceInfoMap& GetProvisionedDeviceInfoMap() {
|
|||||||
WvPLStatus WvPLSDKEnvironment::SetDrmServiceCertificate(
|
WvPLStatus WvPLSDKEnvironment::SetDrmServiceCertificate(
|
||||||
const std::string& service_certificate, const std::string& service_private_key,
|
const std::string& service_certificate, const std::string& service_private_key,
|
||||||
const std::string& service_private_key_passphrase) {
|
const std::string& service_private_key_passphrase) {
|
||||||
WvPLStatus wvpl_status = AddDrmServiceCertificate(
|
CHECK(drm_root_certificate()) << "DRM root certificate not set!";
|
||||||
certificate_type_, service_certificate, service_private_key,
|
WvPLStatus wvpl_status = DrmServiceCertificate::AddDrmServiceCertificate(
|
||||||
|
drm_root_certificate(), service_certificate, service_private_key,
|
||||||
service_private_key_passphrase);
|
service_private_key_passphrase);
|
||||||
if (!wvpl_status.ok()) return wvpl_status;
|
if (!wvpl_status.ok()) return wvpl_status;
|
||||||
wvpl_status = DrmServiceCertificate::ValidateDrmServiceCertificate();
|
wvpl_status = DrmServiceCertificate::ValidateDrmServiceCertificate();
|
||||||
@@ -85,7 +85,6 @@ WvPLStatus WvPLSDKEnvironment::SetDrmServiceCertificate(
|
|||||||
return wvpl_status;
|
return wvpl_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool WvPLSDKEnvironment::GenerateErrorResponse(
|
bool WvPLSDKEnvironment::GenerateErrorResponse(
|
||||||
const WvPLStatus& create_session_status, std::string* license_response) {
|
const WvPLStatus& create_session_status, std::string* license_response) {
|
||||||
return widevine::GenerateErrorResponse(create_session_status,
|
return widevine::GenerateErrorResponse(create_session_status,
|
||||||
@@ -198,5 +197,31 @@ void WvPLSDKEnvironment::SetConfigValue(
|
|||||||
const std::map<std::string, std::string>& config_values) {
|
const std::map<std::string, std::string>& config_values) {
|
||||||
config_values_->insert(config_values.begin(), config_values.end());
|
config_values_->insert(config_values.begin(), config_values.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WvPLStatus WvPLSDKEnvironment::SetDeviceCertificateStatusList(
|
||||||
|
const std::string& cert_list) const {
|
||||||
|
WvPLStatus status = util::OkStatus();
|
||||||
|
SignedDeviceCertificateStatusList device_certificate_status_list;
|
||||||
|
std::string decoded_certificate_status_list;
|
||||||
|
std::string device_certicate_status_list;
|
||||||
|
status = DeviceStatusList::ExtractFromProvisioningServiceResponse(
|
||||||
|
cert_list, &decoded_certificate_status_list,
|
||||||
|
&device_certicate_status_list);
|
||||||
|
if (!status.ok()) return status;
|
||||||
|
DeviceCertificateStatusList certificate_status_list;
|
||||||
|
if (!certificate_status_list.ParseFromString(device_certicate_status_list)) {
|
||||||
|
return util::Status(error_space,
|
||||||
|
widevine::INVALID_CERTIFICATE_STATUS_LIST,
|
||||||
|
"certificate status list parse error");
|
||||||
|
}
|
||||||
|
status = DeviceStatusList::Instance()->UpdateStatusList(
|
||||||
|
drm_root_certificate_->public_key(), decoded_certificate_status_list,
|
||||||
|
device_certificate_expiration_seconds_);
|
||||||
|
if (!status.ok()) return status;
|
||||||
|
status = WvPLSDKEnvironment::UpdateProvisionedDeviceInfoMap(
|
||||||
|
certificate_status_list);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace wv_pl_sdk
|
} // namespace wv_pl_sdk
|
||||||
} // namespace widevine_server
|
} // namespace widevine_server
|
||||||
|
|||||||
17
sdk/external/common/wvpl/wvpl_sdk_environment.h
vendored
17
sdk/external/common/wvpl/wvpl_sdk_environment.h
vendored
@@ -9,9 +9,10 @@
|
|||||||
#ifndef SDK_EXTERNAL_COMMON_WVPL_WVPL_SDK_ENVIRONMENT_H_
|
#ifndef SDK_EXTERNAL_COMMON_WVPL_WVPL_SDK_ENVIRONMENT_H_
|
||||||
#define SDK_EXTERNAL_COMMON_WVPL_WVPL_SDK_ENVIRONMENT_H_
|
#define SDK_EXTERNAL_COMMON_WVPL_WVPL_SDK_ENVIRONMENT_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "common/certificate_type.h"
|
#include "common/drm_root_certificate.h"
|
||||||
#include "sdk/external/common/wvpl/wvpl_types.h"
|
#include "sdk/external/common/wvpl/wvpl_types.h"
|
||||||
#include "protos/public/device_certificate_status.pb.h"
|
#include "protos/public/device_certificate_status.pb.h"
|
||||||
#include "protos/public/provisioned_device_info.pb.h"
|
#include "protos/public/provisioned_device_info.pb.h"
|
||||||
@@ -66,9 +67,10 @@ class WvPLSDKEnvironment {
|
|||||||
const std::string& service_certificate, const std::string& service_private_key,
|
const std::string& service_certificate, const std::string& service_private_key,
|
||||||
const std::string& service_private_key_passphrase);
|
const std::string& service_private_key_passphrase);
|
||||||
|
|
||||||
// Returns the DRM Root Certificate type. This would be a setting passed into
|
// Returns the DRM root certificate configured for this environment.
|
||||||
// the environment, by a derived class constructor.
|
const widevine::DrmRootCertificate* drm_root_certificate() const {
|
||||||
virtual std::string GetDrmCertificateType() { return drm_certificate_type_; }
|
return drm_root_certificate_.get();
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Return the signature for the provider specified in the |config_values|
|
// Return the signature for the provider specified in the |config_values|
|
||||||
@@ -83,6 +85,8 @@ class WvPLSDKEnvironment {
|
|||||||
const widevine::DeviceCertificateStatusList&
|
const widevine::DeviceCertificateStatusList&
|
||||||
certificate_status_list);
|
certificate_status_list);
|
||||||
|
|
||||||
|
WvPLStatus SetDeviceCertificateStatusList(const std::string& cert_list) const;
|
||||||
|
|
||||||
// Number of seconds until the certificate status list expires after its
|
// Number of seconds until the certificate status list expires after its
|
||||||
// creation time. Default value is 604800 seconds.
|
// creation time. Default value is 604800 seconds.
|
||||||
uint32_t device_certificate_expiration_seconds_ = 604800;
|
uint32_t device_certificate_expiration_seconds_ = 604800;
|
||||||
@@ -100,9 +104,8 @@ class WvPLSDKEnvironment {
|
|||||||
bool is_service_certificate_loaded_ = false;
|
bool is_service_certificate_loaded_ = false;
|
||||||
// If true, allow devices not in the certificate status list.
|
// If true, allow devices not in the certificate status list.
|
||||||
bool allow_unknown_device_ = false;
|
bool allow_unknown_device_ = false;
|
||||||
// DRM Certificate type.
|
// DRM root certificate used for verifying all other DRM certificates.
|
||||||
widevine::CertificateType certificate_type_ =
|
std::unique_ptr<widevine::DrmRootCertificate> drm_root_certificate_;
|
||||||
widevine::kCertificateTypeProduction;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
|
|||||||
54
sdk/external/common/wvpl/wvpl_sdk_session.cc
vendored
54
sdk/external/common/wvpl/wvpl_sdk_session.cc
vendored
@@ -10,14 +10,15 @@
|
|||||||
#include "glog/logging.h"
|
#include "glog/logging.h"
|
||||||
#include "util/status.h"
|
#include "util/status.h"
|
||||||
#include "absl/memory/memory.h"
|
#include "absl/memory/memory.h"
|
||||||
|
#include "common/client_cert.h"
|
||||||
#include "common/drm_service_certificate.h"
|
#include "common/drm_service_certificate.h"
|
||||||
#include "common/error_space.h"
|
#include "common/error_space.h"
|
||||||
#include "common/remote_attestation_verifier.h"
|
#include "common/remote_attestation_verifier.h"
|
||||||
#include "common/verified_media_pipeline.h"
|
#include "common/verified_media_pipeline.h"
|
||||||
#include "license_server_sdk/internal/client_cert.h"
|
|
||||||
#include "sdk/external/common/wvpl/wvpl_sdk_environment.h"
|
#include "sdk/external/common/wvpl/wvpl_sdk_environment.h"
|
||||||
#include "sdk/external/common/wvpl/wvpl_types.h"
|
#include "sdk/external/common/wvpl/wvpl_types.h"
|
||||||
#include "protos/public/errors.pb.h"
|
#include "protos/public/errors.pb.h"
|
||||||
|
#include "protos/public/provisioned_device_info.pb.h"
|
||||||
|
|
||||||
// TODO(user): Mark getProvisionedDeviceInfo as deprecated, move the
|
// TODO(user): Mark getProvisionedDeviceInfo as deprecated, move the
|
||||||
// implementation of isChromeCDM, getcontentid, parsePsshdata in wvpl_session
|
// implementation of isChromeCDM, getcontentid, parsePsshdata in wvpl_session
|
||||||
@@ -28,8 +29,16 @@
|
|||||||
// wvpl_sdk_session_test.cc.
|
// wvpl_sdk_session_test.cc.
|
||||||
// TODO(user): Remove sdk_license_request_ and both proxy and wvpl LSDK set
|
// TODO(user): Remove sdk_license_request_ and both proxy and wvpl LSDK set
|
||||||
// signed_message_request_from_cdm_ when create session.
|
// signed_message_request_from_cdm_ when create session.
|
||||||
|
// TODO(user): Move all the protected memeber variables to private and use
|
||||||
|
// getter and setter to access it.
|
||||||
|
// TODO(user): Try to avoid virtual private function like parsepsshdata.
|
||||||
|
// TODO(user): (b/119566765) Refactor ParseLicenseRequest and break it into
|
||||||
|
// different classes.
|
||||||
|
|
||||||
namespace util = widevine::util;
|
namespace util = widevine::util;
|
||||||
|
using widevine::ClientCert;
|
||||||
using widevine::ClientIdentification;
|
using widevine::ClientIdentification;
|
||||||
|
using widevine::DrmRootCertificate;
|
||||||
using widevine::DrmServiceCertificate;
|
using widevine::DrmServiceCertificate;
|
||||||
using widevine::error_space;
|
using widevine::error_space;
|
||||||
using widevine::KeyboxClientCert;
|
using widevine::KeyboxClientCert;
|
||||||
@@ -38,12 +47,14 @@ using widevine::LicenseRequest;
|
|||||||
using widevine::ProvisionedDeviceInfo;
|
using widevine::ProvisionedDeviceInfo;
|
||||||
using widevine::RemoteAttestationVerifier;
|
using widevine::RemoteAttestationVerifier;
|
||||||
using widevine::SessionInit;
|
using widevine::SessionInit;
|
||||||
using widevine::SessionState;
|
|
||||||
using widevine::SignedMessage;
|
using widevine::SignedMessage;
|
||||||
|
|
||||||
namespace widevine_server {
|
namespace widevine_server {
|
||||||
namespace wv_pl_sdk {
|
namespace wv_pl_sdk {
|
||||||
|
|
||||||
|
WvPLSDKSession::WvPLSDKSession(const DrmRootCertificate* drm_root_certificate)
|
||||||
|
: drm_root_certificate_(drm_root_certificate) {}
|
||||||
|
|
||||||
WvPLSDKSession::~WvPLSDKSession() {}
|
WvPLSDKSession::~WvPLSDKSession() {}
|
||||||
|
|
||||||
WvPLStatus WvPLSDKSession::AddKey(const WvPLKey& key) {
|
WvPLStatus WvPLSDKSession::AddKey(const WvPLKey& key) {
|
||||||
@@ -451,13 +462,22 @@ WvPLStatus WvPLSDKSession::ParseLicenseRequest() {
|
|||||||
}
|
}
|
||||||
has_client_id_ = true;
|
has_client_id_ = true;
|
||||||
}
|
}
|
||||||
if (client_id_.has_token()) {
|
if (client_id_.has_token() &&
|
||||||
|
client_id_.type() == ClientIdentification::KEYBOX) {
|
||||||
// Get system_id from token field in ClientIdentification.
|
// Get system_id from token field in ClientIdentification.
|
||||||
system_id_ = KeyboxClientCert::GetSystemId(client_id_.token());
|
SetSystemId(KeyboxClientCert::GetSystemId(client_id_.token()));
|
||||||
has_system_id_ = true;
|
}
|
||||||
|
if (!HasSystemId()) {
|
||||||
|
ClientCert* client_cert_ptr = nullptr;
|
||||||
|
status = ClientCert::Create(
|
||||||
|
drm_root_certificate_, sdk_license_request_->client_id().type(),
|
||||||
|
sdk_license_request_->client_id().token(), &client_cert_ptr);
|
||||||
|
std::unique_ptr<ClientCert> client_cert(client_cert_ptr);
|
||||||
|
if (client_cert != nullptr) {
|
||||||
|
SetSystemId(client_cert->system_id());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// TODO(user): Consider enforcing missing client id here.
|
// TODO(user): Consider enforcing missing client id here.
|
||||||
|
|
||||||
// Verifies platform for license requests and sets Platform Verification
|
// Verifies platform for license requests and sets Platform Verification
|
||||||
// status.
|
// status.
|
||||||
platform_verification_status_ = VerifyPlatform();
|
platform_verification_status_ = VerifyPlatform();
|
||||||
@@ -651,15 +671,14 @@ WvPLStatus WvPLSDKSession::GetDeviceInfo(WvPLDeviceInfo* device_info) const {
|
|||||||
return WvPLStatus(error_space, util::error::INVALID_ARGUMENT,
|
return WvPLStatus(error_space, util::error::INVALID_ARGUMENT,
|
||||||
"device_info is NULL");
|
"device_info is NULL");
|
||||||
}
|
}
|
||||||
if (!has_system_id_) {
|
if (!HasSystemId()) {
|
||||||
return WvPLStatus(
|
return WvPLStatus(
|
||||||
error_space, widevine::UNSUPPORTED_SYSTEM_ID,
|
error_space, widevine::UNSUPPORTED_SYSTEM_ID,
|
||||||
"Widevine SystemID does not exist because it is not found "
|
"Widevine SystemID does not exist because it is not found "
|
||||||
"in the license request");
|
"in the license request");
|
||||||
}
|
}
|
||||||
ProvisionedDeviceInfo provisioned_device_info;
|
ProvisionedDeviceInfo provisioned_device_info;
|
||||||
status = WvPLSDKEnvironment::LookupDeviceInfo(system_id_,
|
status = LookupDeviceInfo(GetSystemId(), &provisioned_device_info);
|
||||||
&provisioned_device_info);
|
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@@ -697,5 +716,22 @@ WvPLStatus WvPLSDKSession::GetDeviceInfo(WvPLDeviceInfo* device_info) const {
|
|||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WvPLStatus WvPLSDKSession::LookupDeviceInfo(
|
||||||
|
uint32_t system_id, ProvisionedDeviceInfo* provisioned_device_info) const {
|
||||||
|
return WvPLSDKEnvironment::LookupDeviceInfo(system_id,
|
||||||
|
provisioned_device_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WvPLSDKSession::SetSystemId(uint32_t system_id) {
|
||||||
|
system_id_ = absl::make_unique<uint32_t>(system_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WvPLSDKSession::HasSystemId() const { return system_id_ != nullptr; }
|
||||||
|
|
||||||
|
uint32_t WvPLSDKSession::GetSystemId() const {
|
||||||
|
CHECK(system_id_);
|
||||||
|
return *system_id_;
|
||||||
|
}
|
||||||
} // namespace wv_pl_sdk
|
} // namespace wv_pl_sdk
|
||||||
} // namespace widevine_server
|
} // namespace widevine_server
|
||||||
|
|||||||
30
sdk/external/common/wvpl/wvpl_sdk_session.h
vendored
30
sdk/external/common/wvpl/wvpl_sdk_session.h
vendored
@@ -9,6 +9,7 @@
|
|||||||
#ifndef SDK_EXTERNAL_COMMON_WVPL_WVPL_SDK_SESSION_H_
|
#ifndef SDK_EXTERNAL_COMMON_WVPL_WVPL_SDK_SESSION_H_
|
||||||
#define SDK_EXTERNAL_COMMON_WVPL_WVPL_SDK_SESSION_H_
|
#define SDK_EXTERNAL_COMMON_WVPL_WVPL_SDK_SESSION_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include "sdk/external/common/wvpl/wvpl_types.h"
|
#include "sdk/external/common/wvpl/wvpl_types.h"
|
||||||
#include "protos/public/client_identification.pb.h"
|
#include "protos/public/client_identification.pb.h"
|
||||||
#include "protos/public/device_certificate_status.pb.h"
|
#include "protos/public/device_certificate_status.pb.h"
|
||||||
@@ -17,13 +18,16 @@
|
|||||||
#include "protos/public/provisioned_device_info.pb.h"
|
#include "protos/public/provisioned_device_info.pb.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
|
class DrmRootCertificate;
|
||||||
class SessionInit;
|
class SessionInit;
|
||||||
}
|
} // namespace widevine
|
||||||
namespace widevine_server {
|
namespace widevine_server {
|
||||||
namespace wv_pl_sdk {
|
namespace wv_pl_sdk {
|
||||||
|
|
||||||
class WvPLSDKSession {
|
class WvPLSDKSession {
|
||||||
public:
|
public:
|
||||||
|
explicit WvPLSDKSession(
|
||||||
|
const widevine::DrmRootCertificate* drm_root_certificate);
|
||||||
virtual ~WvPLSDKSession() = 0;
|
virtual ~WvPLSDKSession() = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -102,7 +106,7 @@ class WvPLSDKSession {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint32_t system_id_ = 0xFFFFFFFF;
|
const widevine::DrmRootCertificate* drm_root_certificate_;
|
||||||
std::string user_agent_;
|
std::string user_agent_;
|
||||||
std::vector<WvPLKey> keys_;
|
std::vector<WvPLKey> keys_;
|
||||||
WvPLPlaybackPolicy policy_;
|
WvPLPlaybackPolicy policy_;
|
||||||
@@ -110,7 +114,6 @@ class WvPLSDKSession {
|
|||||||
WvPLWidevinePsshData pssh_data_;
|
WvPLWidevinePsshData pssh_data_;
|
||||||
widevine::ClientIdentification client_id_;
|
widevine::ClientIdentification client_id_;
|
||||||
bool has_pssh_data_ = false;
|
bool has_pssh_data_ = false;
|
||||||
bool has_system_id_ = false;
|
|
||||||
bool has_client_id_ = false;
|
bool has_client_id_ = false;
|
||||||
MessageType message_type_ = UNKNOWN;
|
MessageType message_type_ = UNKNOWN;
|
||||||
PlatformVerificationStatus platform_verification_status_ =
|
PlatformVerificationStatus platform_verification_status_ =
|
||||||
@@ -182,7 +185,28 @@ class WvPLSDKSession {
|
|||||||
void CopySessionState(const WvPLSessionState& wvpl_session_state,
|
void CopySessionState(const WvPLSessionState& wvpl_session_state,
|
||||||
widevine::SessionState* session_state);
|
widevine::SessionState* session_state);
|
||||||
|
|
||||||
|
// Set system_id value.
|
||||||
|
virtual void SetSystemId(uint32_t system_id);
|
||||||
|
|
||||||
|
// Return has_system_id_ value. True if session has system id.
|
||||||
|
virtual bool HasSystemId() const;
|
||||||
|
|
||||||
|
// Return system_id value in uint32_t. The function will crash if it does not
|
||||||
|
// have system_id.
|
||||||
|
virtual uint32_t GetSystemId() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use system_id to loop up device info.
|
||||||
|
*
|
||||||
|
* @return WvPLStatus - Status::OK if success, else error.
|
||||||
|
*/
|
||||||
|
virtual WvPLStatus LookupDeviceInfo(
|
||||||
|
uint32_t system_id,
|
||||||
|
widevine::ProvisionedDeviceInfo* provisioned_device_info) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::unique_ptr<uint32_t> system_id_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses WvPLWidevinePsshData in the new license request.
|
* Parses WvPLWidevinePsshData in the new license request.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ inline bool operator!=(const Status& s1, const Status& s2) {
|
|||||||
// Prints a human-readable representation of 'x' to 'os'.
|
// Prints a human-readable representation of 'x' to 'os'.
|
||||||
std::ostream& operator<<(std::ostream& os, const Status& x);
|
std::ostream& operator<<(std::ostream& os, const Status& x);
|
||||||
|
|
||||||
#define CHECK_OK(expression) CHECK_EQ(util::error::OK, expression.error_code())
|
#define CHECK_OK(expression) CHECK(expression.ok()) << expression.ToString()
|
||||||
|
|
||||||
|
|
||||||
} // namespace util
|
} // namespace util
|
||||||
|
|||||||
Reference in New Issue
Block a user