Fix media_cas_proxy_sdk build issue.
Add example binary for testing building the SDK after 'git clone' from our repo. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=227583629
This commit is contained in:
2
BUILD
2
BUILD
@@ -15,6 +15,8 @@ pkg_tar(
|
|||||||
strip_prefix = "/",
|
strip_prefix = "/",
|
||||||
files = [
|
files = [
|
||||||
"//common:binary_release_files",
|
"//common:binary_release_files",
|
||||||
|
"//example:binary_release_files",
|
||||||
|
"//protos/public:binary_release_files",
|
||||||
"//media_cas_proxy_sdk/external/common/wvpl:binary_release_files",
|
"//media_cas_proxy_sdk/external/common/wvpl:binary_release_files",
|
||||||
"//sdk/external/common/wvpl:binary_release_files",
|
"//sdk/external/common/wvpl:binary_release_files",
|
||||||
"//util:binary_release_files",
|
"//util:binary_release_files",
|
||||||
|
|||||||
56
common/BUILD
56
common/BUILD
@@ -16,6 +16,8 @@ filegroup(
|
|||||||
name = "binary_release_files",
|
name = "binary_release_files",
|
||||||
srcs = [
|
srcs = [
|
||||||
"certificate_type.h",
|
"certificate_type.h",
|
||||||
|
"drm_root_certificate.h",
|
||||||
|
"status.h",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -31,6 +33,27 @@ cc_library(
|
|||||||
hdrs = ["certificate_type.h"],
|
hdrs = ["certificate_type.h"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cc_library(
|
||||||
|
name = "status",
|
||||||
|
srcs = ["status.cc"],
|
||||||
|
hdrs = ["status.h"],
|
||||||
|
deps = [
|
||||||
|
"//base",
|
||||||
|
"@abseil_repo//absl/base:core_headers",
|
||||||
|
"@abseil_repo//absl/strings",
|
||||||
|
"//util:error_space",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc_test(
|
||||||
|
name = "status_test",
|
||||||
|
srcs = ["status_test.cc"],
|
||||||
|
deps = [
|
||||||
|
":status",
|
||||||
|
"//testing:gunit_main",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
cc_library(
|
cc_library(
|
||||||
name = "client_cert",
|
name = "client_cert",
|
||||||
srcs = ["client_cert.cc"],
|
srcs = ["client_cert.cc"],
|
||||||
@@ -41,7 +64,9 @@ cc_library(
|
|||||||
":error_space",
|
":error_space",
|
||||||
":random_util",
|
":random_util",
|
||||||
":rsa_key",
|
":rsa_key",
|
||||||
|
":sha_util",
|
||||||
":signing_key_util",
|
":signing_key_util",
|
||||||
|
":status",
|
||||||
":wvm_token_handler",
|
":wvm_token_handler",
|
||||||
"//base",
|
"//base",
|
||||||
"//strings",
|
"//strings",
|
||||||
@@ -49,7 +74,6 @@ cc_library(
|
|||||||
"@abseil_repo//absl/synchronization",
|
"@abseil_repo//absl/synchronization",
|
||||||
"@abseil_repo//absl/time",
|
"@abseil_repo//absl/time",
|
||||||
"//util/gtl:map_util",
|
"//util/gtl:map_util",
|
||||||
"//util:status",
|
|
||||||
"//protos/public:client_identification_proto",
|
"//protos/public:client_identification_proto",
|
||||||
"//protos/public:drm_certificate_proto",
|
"//protos/public:drm_certificate_proto",
|
||||||
"//protos/public:errors_proto",
|
"//protos/public:errors_proto",
|
||||||
@@ -65,6 +89,8 @@ cc_test(
|
|||||||
":client_cert",
|
":client_cert",
|
||||||
":drm_root_certificate",
|
":drm_root_certificate",
|
||||||
":error_space",
|
":error_space",
|
||||||
|
":sha_util",
|
||||||
|
":test_drm_certificates",
|
||||||
":wvm_test_keys",
|
":wvm_test_keys",
|
||||||
"//base",
|
"//base",
|
||||||
"//strings",
|
"//strings",
|
||||||
@@ -88,15 +114,16 @@ cc_library(
|
|||||||
":client_cert",
|
":client_cert",
|
||||||
":crypto_util",
|
":crypto_util",
|
||||||
":drm_root_certificate",
|
":drm_root_certificate",
|
||||||
|
":drm_service_certificate",
|
||||||
":error_space",
|
":error_space",
|
||||||
":random_util",
|
":random_util",
|
||||||
":rsa_key",
|
":rsa_key",
|
||||||
":signing_key_util",
|
":signing_key_util",
|
||||||
|
":status",
|
||||||
"//base",
|
"//base",
|
||||||
"@abseil_repo//absl/strings",
|
"@abseil_repo//absl/strings",
|
||||||
"@abseil_repo//absl/synchronization",
|
"@abseil_repo//absl/synchronization",
|
||||||
"//util/gtl:map_util",
|
"//util/gtl:map_util",
|
||||||
"//util:status",
|
|
||||||
"//protos/public:client_identification_proto",
|
"//protos/public:client_identification_proto",
|
||||||
"//protos/public:device_certificate_status_proto",
|
"//protos/public:device_certificate_status_proto",
|
||||||
"//protos/public:errors_proto",
|
"//protos/public:errors_proto",
|
||||||
@@ -132,12 +159,12 @@ cc_library(
|
|||||||
":error_space",
|
":error_space",
|
||||||
":rsa_key",
|
":rsa_key",
|
||||||
":sha_util",
|
":sha_util",
|
||||||
|
":status",
|
||||||
"//base",
|
"//base",
|
||||||
"@abseil_repo//absl/memory",
|
"@abseil_repo//absl/memory",
|
||||||
"@abseil_repo//absl/strings",
|
"@abseil_repo//absl/strings",
|
||||||
"@abseil_repo//absl/synchronization",
|
"@abseil_repo//absl/synchronization",
|
||||||
"//external:openssl",
|
"//external:openssl",
|
||||||
"//util:status",
|
|
||||||
"//protos/public:drm_certificate_proto",
|
"//protos/public:drm_certificate_proto",
|
||||||
"//protos/public:errors_proto",
|
"//protos/public:errors_proto",
|
||||||
"//protos/public:signed_drm_certificate_proto",
|
"//protos/public:signed_drm_certificate_proto",
|
||||||
@@ -171,9 +198,9 @@ cc_library(
|
|||||||
":aes_cbc_util",
|
":aes_cbc_util",
|
||||||
":drm_service_certificate",
|
":drm_service_certificate",
|
||||||
":error_space",
|
":error_space",
|
||||||
|
":status",
|
||||||
"//base",
|
"//base",
|
||||||
"@abseil_repo//absl/strings",
|
"@abseil_repo//absl/strings",
|
||||||
"//util:status",
|
|
||||||
"//protos/public:client_identification_proto",
|
"//protos/public:client_identification_proto",
|
||||||
"//protos/public:errors_proto",
|
"//protos/public:errors_proto",
|
||||||
],
|
],
|
||||||
@@ -393,8 +420,8 @@ cc_library(
|
|||||||
":aes_cbc_util",
|
":aes_cbc_util",
|
||||||
":rsa_key",
|
":rsa_key",
|
||||||
":sha_util",
|
":sha_util",
|
||||||
|
":status",
|
||||||
"//base",
|
"//base",
|
||||||
"//util:status",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -442,12 +469,12 @@ cc_library(
|
|||||||
":aes_cbc_util",
|
":aes_cbc_util",
|
||||||
":ecb_util",
|
":ecb_util",
|
||||||
":sha_util",
|
":sha_util",
|
||||||
|
":status",
|
||||||
"//base",
|
"//base",
|
||||||
"@abseil_repo//absl/strings",
|
"@abseil_repo//absl/strings",
|
||||||
"@abseil_repo//absl/synchronization",
|
"@abseil_repo//absl/synchronization",
|
||||||
"//util/endian",
|
"//util/endian",
|
||||||
"//util/gtl:map_util",
|
"//util/gtl:map_util",
|
||||||
"//util:status",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -481,7 +508,7 @@ cc_library(
|
|||||||
srcs = ["error_space.cc"],
|
srcs = ["error_space.cc"],
|
||||||
hdrs = ["error_space.h"],
|
hdrs = ["error_space.h"],
|
||||||
deps = [
|
deps = [
|
||||||
"//util:status",
|
"//util:error_space",
|
||||||
"//util:proto_status",
|
"//util:proto_status",
|
||||||
"//protos/public:errors_proto",
|
"//protos/public:errors_proto",
|
||||||
],
|
],
|
||||||
@@ -496,11 +523,11 @@ cc_library(
|
|||||||
":drm_service_certificate",
|
":drm_service_certificate",
|
||||||
":error_space",
|
":error_space",
|
||||||
":rsa_key",
|
":rsa_key",
|
||||||
|
":status",
|
||||||
":x509_cert",
|
":x509_cert",
|
||||||
"//base",
|
"//base",
|
||||||
"@abseil_repo//absl/strings",
|
"@abseil_repo//absl/strings",
|
||||||
"@abseil_repo//absl/synchronization",
|
"@abseil_repo//absl/synchronization",
|
||||||
"//util:status",
|
|
||||||
"//protos/public:client_identification_proto",
|
"//protos/public:client_identification_proto",
|
||||||
"//protos/public:errors_proto",
|
"//protos/public:errors_proto",
|
||||||
"//protos/public:remote_attestation_proto",
|
"//protos/public:remote_attestation_proto",
|
||||||
@@ -518,11 +545,11 @@ cc_library(
|
|||||||
":error_space",
|
":error_space",
|
||||||
":rsa_key",
|
":rsa_key",
|
||||||
":rsa_util",
|
":rsa_util",
|
||||||
|
":status",
|
||||||
"//base",
|
"//base",
|
||||||
"@abseil_repo//absl/strings",
|
"@abseil_repo//absl/strings",
|
||||||
"@abseil_repo//absl/synchronization",
|
"@abseil_repo//absl/synchronization",
|
||||||
"//util/gtl:map_util",
|
"//util/gtl:map_util",
|
||||||
"//util:status",
|
|
||||||
"//protos/public:client_identification_proto",
|
"//protos/public:client_identification_proto",
|
||||||
"//protos/public:drm_certificate_proto",
|
"//protos/public:drm_certificate_proto",
|
||||||
"//protos/public:errors_proto",
|
"//protos/public:errors_proto",
|
||||||
@@ -559,10 +586,10 @@ cc_library(
|
|||||||
srcs = ["verified_media_pipeline.cc"],
|
srcs = ["verified_media_pipeline.cc"],
|
||||||
hdrs = ["verified_media_pipeline.h"],
|
hdrs = ["verified_media_pipeline.h"],
|
||||||
deps = [
|
deps = [
|
||||||
|
":status",
|
||||||
":vmp_checker",
|
":vmp_checker",
|
||||||
"//base",
|
"//base",
|
||||||
"@abseil_repo//absl/strings",
|
"@abseil_repo//absl/strings",
|
||||||
"//util:status",
|
|
||||||
"//protos/public:license_protocol_proto",
|
"//protos/public:license_protocol_proto",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@@ -572,13 +599,14 @@ cc_library(
|
|||||||
srcs = ["x509_cert.cc"],
|
srcs = ["x509_cert.cc"],
|
||||||
hdrs = ["x509_cert.h"],
|
hdrs = ["x509_cert.h"],
|
||||||
deps = [
|
deps = [
|
||||||
|
":error_space",
|
||||||
":openssl_util",
|
":openssl_util",
|
||||||
":rsa_key",
|
":rsa_key",
|
||||||
|
":status",
|
||||||
"//base",
|
"//base",
|
||||||
"@abseil_repo//absl/strings",
|
"@abseil_repo//absl/strings",
|
||||||
"@abseil_repo//absl/synchronization",
|
"@abseil_repo//absl/synchronization",
|
||||||
"//external:openssl",
|
"//external:openssl",
|
||||||
"//util:status",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -588,9 +616,9 @@ cc_library(
|
|||||||
srcs = ["test_utils.cc"],
|
srcs = ["test_utils.cc"],
|
||||||
hdrs = ["test_utils.h"],
|
hdrs = ["test_utils.h"],
|
||||||
deps = [
|
deps = [
|
||||||
|
":status",
|
||||||
"//base",
|
"//base",
|
||||||
"//external:openssl",
|
"//external:openssl",
|
||||||
"//util:status",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -616,9 +644,9 @@ cc_library(
|
|||||||
":certificate_type",
|
":certificate_type",
|
||||||
":error_space",
|
":error_space",
|
||||||
":rsa_key",
|
":rsa_key",
|
||||||
|
":status",
|
||||||
":x509_cert",
|
":x509_cert",
|
||||||
"//base",
|
"//base",
|
||||||
"//util:status",
|
|
||||||
"//protos/public:errors_proto",
|
"//protos/public:errors_proto",
|
||||||
"//protos/public:verified_media_pipeline_proto",
|
"//protos/public:verified_media_pipeline_proto",
|
||||||
],
|
],
|
||||||
@@ -644,8 +672,8 @@ cc_library(
|
|||||||
srcs = ["string_util.cc"],
|
srcs = ["string_util.cc"],
|
||||||
hdrs = ["string_util.h"],
|
hdrs = ["string_util.h"],
|
||||||
deps = [
|
deps = [
|
||||||
|
":status",
|
||||||
"//base",
|
"//base",
|
||||||
"//util:status",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -17,19 +17,18 @@
|
|||||||
#include "absl/strings/escaping.h"
|
#include "absl/strings/escaping.h"
|
||||||
#include "absl/synchronization/mutex.h"
|
#include "absl/synchronization/mutex.h"
|
||||||
#include "util/gtl/map_util.h"
|
#include "util/gtl/map_util.h"
|
||||||
#include "util/status.h"
|
|
||||||
#include "common/crypto_util.h"
|
#include "common/crypto_util.h"
|
||||||
#include "common/drm_root_certificate.h"
|
#include "common/drm_root_certificate.h"
|
||||||
#include "common/error_space.h"
|
#include "common/error_space.h"
|
||||||
#include "common/random_util.h"
|
#include "common/random_util.h"
|
||||||
|
#include "common/sha_util.h"
|
||||||
#include "common/signing_key_util.h"
|
#include "common/signing_key_util.h"
|
||||||
|
#include "common/status.h"
|
||||||
#include "common/wvm_token_handler.h"
|
#include "common/wvm_token_handler.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"
|
||||||
|
|
||||||
// TODO(user): Get rid of this horror.
|
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@@ -37,45 +36,44 @@ const int kKeyboxSizeBytes = 72;
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// TODO(user): change to util::StatusOr<std::unique_ptr<ClientCert>>
|
|
||||||
// instead of ClientCert** to explicitly assigning ownership of the created
|
// instead of ClientCert** to explicitly assigning ownership of the created
|
||||||
// object to the caller.
|
// object to the caller.
|
||||||
|
|
||||||
util::Status ClientCert::Create(const DrmRootCertificate* root_certificate,
|
Status ClientCert::Create(const DrmRootCertificate* root_certificate,
|
||||||
ClientIdentification::TokenType token_type,
|
ClientIdentification::TokenType token_type,
|
||||||
const std::string& token, ClientCert** client_cert) {
|
const std::string& token, ClientCert** client_cert) {
|
||||||
DCHECK(client_cert);
|
DCHECK(client_cert);
|
||||||
if (token_type == ClientIdentification::KEYBOX) {
|
if (token_type == ClientIdentification::KEYBOX) {
|
||||||
*client_cert = nullptr;
|
*client_cert = nullptr;
|
||||||
if (token.size() < kKeyboxSizeBytes) {
|
if (token.size() < kKeyboxSizeBytes) {
|
||||||
return util::Status(error_space, INVALID_KEYBOX_TOKEN,
|
return Status(error_space, INVALID_KEYBOX_TOKEN,
|
||||||
"keybox-token-is-too-short");
|
"keybox-token-is-too-short");
|
||||||
}
|
}
|
||||||
return ClientCert::CreateWithKeybox(token, client_cert);
|
return ClientCert::CreateWithKeybox(token, client_cert);
|
||||||
} else if (token_type == ClientIdentification::DRM_DEVICE_CERTIFICATE) {
|
} else if (token_type == ClientIdentification::DRM_DEVICE_CERTIFICATE) {
|
||||||
return CreateWithDrmCertificate(root_certificate, token, client_cert);
|
return CreateWithDrmCertificate(root_certificate, token, client_cert);
|
||||||
} else {
|
} else {
|
||||||
return util::Status(error_space, util::error::UNIMPLEMENTED,
|
return Status(error_space, error::UNIMPLEMENTED,
|
||||||
"client-type-not-implemented");
|
"client-type-not-implemented");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status ClientCert::CreateWithKeybox(const std::string& keybox_token,
|
Status ClientCert::CreateWithKeybox(const std::string& keybox_token,
|
||||||
ClientCert** client_cert) {
|
ClientCert** client_cert) {
|
||||||
CHECK(client_cert);
|
CHECK(client_cert);
|
||||||
*client_cert = nullptr;
|
*client_cert = nullptr;
|
||||||
|
|
||||||
std::unique_ptr<KeyboxClientCert> new_client_cert(new KeyboxClientCert);
|
std::unique_ptr<KeyboxClientCert> new_client_cert(new KeyboxClientCert);
|
||||||
util::Status status = new_client_cert->Initialize(keybox_token);
|
Status status = new_client_cert->Initialize(keybox_token);
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
*client_cert = new_client_cert.release();
|
*client_cert = new_client_cert.release();
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status ClientCert::CreateWithDrmCertificate(
|
Status ClientCert::CreateWithDrmCertificate(
|
||||||
const DrmRootCertificate* root_certificate, const std::string& drm_certificate,
|
const DrmRootCertificate* root_certificate, const std::string& drm_certificate,
|
||||||
ClientCert** client_cert) {
|
ClientCert** client_cert) {
|
||||||
CHECK(client_cert);
|
CHECK(client_cert);
|
||||||
@@ -83,14 +81,14 @@ util::Status ClientCert::CreateWithDrmCertificate(
|
|||||||
|
|
||||||
std::unique_ptr<CertificateClientCert> new_client_cert(
|
std::unique_ptr<CertificateClientCert> new_client_cert(
|
||||||
new CertificateClientCert);
|
new CertificateClientCert);
|
||||||
util::Status status =
|
Status status =
|
||||||
new_client_cert->Initialize(root_certificate, drm_certificate);
|
new_client_cert->Initialize(root_certificate, drm_certificate);
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
*client_cert = new_client_cert.release();
|
*client_cert = new_client_cert.release();
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientCert::CreateSignature(const std::string& message, std::string* signature) {
|
void ClientCert::CreateSignature(const std::string& message, std::string* signature) {
|
||||||
@@ -110,8 +108,10 @@ void ClientCert::GenerateSigningKey(const std::string& message,
|
|||||||
DCHECK(!key().empty());
|
DCHECK(!key().empty());
|
||||||
using crypto_util::DeriveKey;
|
using crypto_util::DeriveKey;
|
||||||
using crypto_util::kSigningKeyLabel;
|
using crypto_util::kSigningKeyLabel;
|
||||||
set_signing_key(DeriveKey(key(), kSigningKeyLabel, message,
|
set_signing_key(
|
||||||
SigningKeyMaterialSize(protocol_version)));
|
DeriveKey(key(), kSigningKeyLabel,
|
||||||
|
protocol_version < VERSION_2_2 ? message : Sha512_Hash(message),
|
||||||
|
SigningKeyMaterialSizeBits(protocol_version)));
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyboxClientCert::KeyboxClientCert() {}
|
KeyboxClientCert::KeyboxClientCert() {}
|
||||||
@@ -139,51 +139,51 @@ uint32_t KeyboxClientCert::GetSystemId(const std::string& keybox_bytes) {
|
|||||||
return WvmTokenHandler::GetSystemId(keybox_bytes);
|
return WvmTokenHandler::GetSystemId(keybox_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status KeyboxClientCert::Initialize(const std::string& keybox_bytes) {
|
Status KeyboxClientCert::Initialize(const std::string& keybox_bytes) {
|
||||||
if (keybox_bytes.size() < kKeyboxSizeBytes) {
|
if (keybox_bytes.size() < kKeyboxSizeBytes) {
|
||||||
return util::Status(error_space, INVALID_KEYBOX_TOKEN,
|
return Status(error_space, INVALID_KEYBOX_TOKEN,
|
||||||
"keybox-token-is-too-short");
|
"keybox-token-is-too-short");
|
||||||
}
|
}
|
||||||
|
|
||||||
set_system_id(WvmTokenHandler::GetSystemId(keybox_bytes));
|
set_system_id(WvmTokenHandler::GetSystemId(keybox_bytes));
|
||||||
set_serial_number(WvmTokenHandler::GetEncryptedUniqueId(keybox_bytes));
|
set_serial_number(WvmTokenHandler::GetEncryptedUniqueId(keybox_bytes));
|
||||||
bool insecure_keybox = false;
|
bool insecure_keybox = false;
|
||||||
util::Status status = WvmTokenHandler::DecryptDeviceKey(
|
Status status = WvmTokenHandler::DecryptDeviceKey(keybox_bytes, &device_key_,
|
||||||
keybox_bytes, &device_key_, nullptr, &insecure_keybox);
|
nullptr, &insecure_keybox);
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
Errors new_code = status.error_code() == util::error::NOT_FOUND
|
Errors new_code = status.error_code() == error::NOT_FOUND
|
||||||
? MISSING_PRE_PROV_KEY
|
? MISSING_PRE_PROV_KEY
|
||||||
: KEYBOX_DECRYPT_ERROR;
|
: KEYBOX_DECRYPT_ERROR;
|
||||||
return util::Status(error_space, new_code, status.error_message());
|
return Status(error_space, new_code, status.error_message());
|
||||||
}
|
}
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status KeyboxClientCert::VerifySignature(
|
Status KeyboxClientCert::VerifySignature(const std::string& message,
|
||||||
const std::string& message, const std::string& signature,
|
const std::string& signature,
|
||||||
ProtocolVersion protocol_version) {
|
ProtocolVersion protocol_version) {
|
||||||
DCHECK(!signing_key().empty());
|
DCHECK(!signing_key().empty());
|
||||||
using crypto_util::VerifySignatureHmacSha256;
|
using crypto_util::VerifySignatureHmacSha256;
|
||||||
if (!VerifySignatureHmacSha256(
|
if (!VerifySignatureHmacSha256(
|
||||||
GetClientSigningKey(signing_key(), protocol_version), signature,
|
GetClientSigningKey(signing_key(), protocol_version), signature,
|
||||||
message)) {
|
message)) {
|
||||||
return util::Status(error_space, INVALID_SIGNATURE, "invalid-keybox-mac");
|
return Status(error_space, INVALID_SIGNATURE, "invalid-keybox-mac");
|
||||||
}
|
}
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
CertificateClientCert::CertificateClientCert() {}
|
CertificateClientCert::CertificateClientCert() {}
|
||||||
|
|
||||||
CertificateClientCert::~CertificateClientCert() {}
|
CertificateClientCert::~CertificateClientCert() {}
|
||||||
|
|
||||||
util::Status CertificateClientCert::Initialize(
|
Status CertificateClientCert::Initialize(
|
||||||
const DrmRootCertificate* drm_root_certificate,
|
const DrmRootCertificate* drm_root_certificate,
|
||||||
const std::string& serialized_certificate) {
|
const std::string& serialized_certificate) {
|
||||||
CHECK(drm_root_certificate);
|
CHECK(drm_root_certificate);
|
||||||
|
|
||||||
SignedDrmCertificate signed_device_cert;
|
SignedDrmCertificate signed_device_cert;
|
||||||
DrmCertificate device_cert;
|
DrmCertificate device_cert;
|
||||||
util::Status status = drm_root_certificate->VerifyCertificate(
|
Status status = drm_root_certificate->VerifyCertificate(
|
||||||
serialized_certificate, &signed_device_cert, &device_cert);
|
serialized_certificate, &signed_device_cert, &device_cert);
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
return status;
|
return status;
|
||||||
@@ -192,12 +192,12 @@ util::Status CertificateClientCert::Initialize(
|
|||||||
const SignedDrmCertificate& signer = signed_device_cert.signer();
|
const SignedDrmCertificate& signer = signed_device_cert.signer();
|
||||||
DrmCertificate model_certificate;
|
DrmCertificate model_certificate;
|
||||||
if (!model_certificate.ParseFromString(signer.drm_certificate())) {
|
if (!model_certificate.ParseFromString(signer.drm_certificate())) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"drm-certificate-invalid-signer");
|
"drm-certificate-invalid-signer");
|
||||||
}
|
}
|
||||||
if (!model_certificate.has_serial_number()) {
|
if (!model_certificate.has_serial_number()) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"missing-signer-serial-number");
|
"missing-signer-serial-number");
|
||||||
}
|
}
|
||||||
// Check to see if this model certificate is signed by a
|
// Check to see if this model certificate is signed by a
|
||||||
// provisioner (entity using Widevine Provisioning Server SDK).
|
// provisioner (entity using Widevine Provisioning Server SDK).
|
||||||
@@ -205,56 +205,58 @@ util::Status CertificateClientCert::Initialize(
|
|||||||
DrmCertificate provisioner_certificate;
|
DrmCertificate provisioner_certificate;
|
||||||
if (!provisioner_certificate.ParseFromString(
|
if (!provisioner_certificate.ParseFromString(
|
||||||
signer.signer().drm_certificate())) {
|
signer.signer().drm_certificate())) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"model-certificate-invalid-signer");
|
"model-certificate-invalid-signer");
|
||||||
}
|
}
|
||||||
if (provisioner_certificate.type() == DrmCertificate::PROVISIONER) {
|
if (provisioner_certificate.type() == DrmCertificate::PROVISIONER) {
|
||||||
set_signed_by_provisioner(true);
|
set_signed_by_provisioner(true);
|
||||||
} else {
|
} else {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"expected-provisioning-provider-certificate-type");
|
"expected-provisioning-provider-certificate-type");
|
||||||
}
|
}
|
||||||
if (!provisioner_certificate.has_provider_id() ||
|
if (!provisioner_certificate.has_provider_id() ||
|
||||||
provisioner_certificate.provider_id().empty()) {
|
provisioner_certificate.provider_id().empty()) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"missing-provisioning-service-id");
|
"missing-provisioning-service-id");
|
||||||
}
|
}
|
||||||
set_service_id(provisioner_certificate.provider_id());
|
set_service_id(provisioner_certificate.provider_id());
|
||||||
}
|
}
|
||||||
set_signer_serial_number(model_certificate.serial_number());
|
set_signer_serial_number(model_certificate.serial_number());
|
||||||
set_signer_creation_time_seconds(model_certificate.creation_time_seconds());
|
set_signer_creation_time_seconds(model_certificate.creation_time_seconds());
|
||||||
if (!model_certificate.has_system_id()) {
|
if (!model_certificate.has_system_id()) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"model-certificate-missing-system-id");
|
"model-certificate-missing-system-id");
|
||||||
}
|
}
|
||||||
set_system_id(model_certificate.system_id());
|
set_system_id(model_certificate.system_id());
|
||||||
set_serial_number(device_cert.serial_number());
|
set_serial_number(device_cert.serial_number());
|
||||||
set_public_key(device_cert.public_key());
|
set_public_key(device_cert.public_key());
|
||||||
rsa_public_key_.reset(RsaPublicKey::Create(public_key()));
|
rsa_public_key_.reset(RsaPublicKey::Create(public_key()));
|
||||||
if (rsa_public_key_ == nullptr) {
|
if (rsa_public_key_ == nullptr) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"drm-certificate-public-key-failed");
|
"drm-certificate-public-key-failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(user): Move this somewhere else. It is license protocol.
|
// TODO(user): Move this somewhere else. It is license protocol.
|
||||||
set_key(Random16Bytes());
|
set_key(Random16Bytes());
|
||||||
if (!rsa_public_key_->Encrypt(key(), &encrypted_session_key_)) {
|
if (!rsa_public_key_->Encrypt(key(), &encrypted_session_key_)) {
|
||||||
return util::Status(error_space, ENCRYPT_ERROR,
|
return Status(error_space, ENCRYPT_ERROR,
|
||||||
"drm-certificate-failed-encrypt-session-key");
|
"drm-certificate-failed-encrypt-session-key");
|
||||||
}
|
}
|
||||||
|
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status CertificateClientCert::VerifySignature(
|
Status CertificateClientCert::VerifySignature(
|
||||||
const std::string& message, const std::string& signature,
|
const std::string& message, const std::string& signature,
|
||||||
ProtocolVersion protocol_version) {
|
ProtocolVersion protocol_version) {
|
||||||
CHECK(rsa_public_key_);
|
CHECK(rsa_public_key_);
|
||||||
|
|
||||||
if (!rsa_public_key_->VerifySignature(message, signature)) {
|
if (!rsa_public_key_->VerifySignature(
|
||||||
return util::Status(error_space, INVALID_SIGNATURE, "");
|
protocol_version < VERSION_2_2 ? message : Sha512_Hash(message),
|
||||||
|
signature)) {
|
||||||
|
return Status(error_space, INVALID_SIGNATURE, "");
|
||||||
}
|
}
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "util/status.h"
|
|
||||||
#include "common/rsa_key.h"
|
#include "common/rsa_key.h"
|
||||||
|
#include "common/status.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"
|
||||||
|
|
||||||
@@ -29,15 +29,15 @@ class SignedDrmCertificate;
|
|||||||
class ClientCert {
|
class ClientCert {
|
||||||
public:
|
public:
|
||||||
virtual ~ClientCert() {}
|
virtual ~ClientCert() {}
|
||||||
static util::Status Create(
|
static Status Create(
|
||||||
const DrmRootCertificate* root_certificate,
|
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 CreateWithKeybox(const std::string& keybox_token,
|
static 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 CreateWithDrmCertificate(
|
static Status CreateWithDrmCertificate(
|
||||||
const DrmRootCertificate* root_certificate, const std::string& drm_certificate,
|
const DrmRootCertificate* root_certificate, const std::string& drm_certificate,
|
||||||
ClientCert** client_cert);
|
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().
|
||||||
@@ -46,9 +46,8 @@ class ClientCert {
|
|||||||
// 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 OK if signature
|
// classes information and the passed in message. Returns OK if signature
|
||||||
// is valid.
|
// is valid.
|
||||||
virtual util::Status VerifySignature(const std::string& message,
|
virtual Status VerifySignature(const std::string& message, const std::string& signature,
|
||||||
const std::string& signature,
|
ProtocolVersion protocol_version) = 0;
|
||||||
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,
|
||||||
@@ -118,10 +117,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);
|
||||||
|
|
||||||
util::Status Initialize(const std::string& keybox_bytes);
|
Status Initialize(const std::string& keybox_bytes);
|
||||||
|
|
||||||
util::Status VerifySignature(const std::string& message, const std::string& signature,
|
Status VerifySignature(const std::string& message, const std::string& signature,
|
||||||
ProtocolVersion protocol_version) override;
|
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_; }
|
||||||
@@ -148,8 +147,8 @@ class CertificateClientCert : public ClientCert {
|
|||||||
public:
|
public:
|
||||||
~CertificateClientCert() override;
|
~CertificateClientCert() override;
|
||||||
|
|
||||||
util::Status VerifySignature(const std::string& message, const std::string& signature,
|
Status VerifySignature(const std::string& message, const std::string& signature,
|
||||||
ProtocolVersion protocol_version) override;
|
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 {
|
||||||
@@ -162,8 +161,8 @@ class CertificateClientCert : public ClientCert {
|
|||||||
protected:
|
protected:
|
||||||
friend class ClientCert;
|
friend class ClientCert;
|
||||||
friend class MockCertificateClientCert;
|
friend class MockCertificateClientCert;
|
||||||
util::Status Initialize(const DrmRootCertificate* drm_root_certificate,
|
Status Initialize(const DrmRootCertificate* drm_root_certificate,
|
||||||
const std::string& serialized_certificate);
|
const std::string& serialized_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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
#include "common/drm_root_certificate.h"
|
#include "common/drm_root_certificate.h"
|
||||||
#include "common/error_space.h"
|
#include "common/error_space.h"
|
||||||
#include "common/rsa_test_keys.h"
|
#include "common/rsa_test_keys.h"
|
||||||
|
#include "common/sha_util.h"
|
||||||
|
#include "common/test_drm_certificates.h"
|
||||||
#include "common/wvm_test_keys.h"
|
#include "common/wvm_test_keys.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"
|
||||||
@@ -31,7 +33,7 @@
|
|||||||
|
|
||||||
// TODO(user): Change these tests to use on-the-fly generated intermediate
|
// TODO(user): Change these tests to use on-the-fly generated intermediate
|
||||||
// and device certificates based on RsaTestKeys.
|
// and device certificates based on RsaTestKeys.
|
||||||
// TODO(user): Add testcase(s) VerifySignature, CreateSignature,
|
// TODO(user): Add testcase(s) CreateSignature,
|
||||||
// and GenerateSigningKey.
|
// and GenerateSigningKey.
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
@@ -73,11 +75,10 @@ class ClientCertTest : public ::testing::Test {
|
|||||||
const std::string certificate_;
|
const std::string certificate_;
|
||||||
const std::string expected_serial_number_;
|
const std::string expected_serial_number_;
|
||||||
uint32_t expected_system_id_;
|
uint32_t expected_system_id_;
|
||||||
util::Status expected_status_;
|
Status expected_status_;
|
||||||
TestCertificateAndData(const std::string& certificate,
|
TestCertificateAndData(const std::string& certificate,
|
||||||
const std::string& expected_serial_number,
|
const std::string& expected_serial_number,
|
||||||
uint32_t expected_system_id,
|
uint32_t expected_system_id, Status expected_status)
|
||||||
util::Status expected_status)
|
|
||||||
: certificate_(certificate),
|
: certificate_(certificate),
|
||||||
expected_serial_number_(expected_serial_number),
|
expected_serial_number_(expected_serial_number),
|
||||||
expected_system_id_(expected_system_id),
|
expected_system_id_(expected_system_id),
|
||||||
@@ -111,7 +112,8 @@ class ClientCertTest : public ::testing::Test {
|
|||||||
SignedDrmCertificate* signer, uint32_t system_id,
|
SignedDrmCertificate* signer, uint32_t system_id,
|
||||||
const std::string& serial_number);
|
const std::string& serial_number);
|
||||||
|
|
||||||
RsaTestKeys test_keys_;
|
RsaTestKeys test_rsa_keys_;
|
||||||
|
TestDrmCertificates test_drm_certs_;
|
||||||
std::unique_ptr<DrmRootCertificate> root_cert_;
|
std::unique_ptr<DrmRootCertificate> root_cert_;
|
||||||
static bool setup_preprov_keys_;
|
static bool setup_preprov_keys_;
|
||||||
};
|
};
|
||||||
@@ -121,7 +123,7 @@ void ClientCertTest::TestBasicValidation(const TestTokenAndKeys& expectation,
|
|||||||
const bool expect_success,
|
const bool expect_success,
|
||||||
const bool compare_device_key) {
|
const bool compare_device_key) {
|
||||||
// Test validation of a valid request.
|
// Test validation of a valid request.
|
||||||
util::Status status;
|
Status status;
|
||||||
ClientCert* client_cert_ptr = nullptr;
|
ClientCert* client_cert_ptr = nullptr;
|
||||||
|
|
||||||
// Two ways to create a client cert object, test both.
|
// Two ways to create a client cert object, test both.
|
||||||
@@ -136,7 +138,7 @@ void ClientCertTest::TestBasicValidation(const TestTokenAndKeys& expectation,
|
|||||||
}
|
}
|
||||||
std::unique_ptr<ClientCert> keybox_cert(client_cert_ptr);
|
std::unique_ptr<ClientCert> keybox_cert(client_cert_ptr);
|
||||||
if (expect_success) {
|
if (expect_success) {
|
||||||
ASSERT_EQ(util::OkStatus(), status);
|
ASSERT_EQ(OkStatus(), status);
|
||||||
ASSERT_TRUE(keybox_cert.get());
|
ASSERT_TRUE(keybox_cert.get());
|
||||||
EXPECT_EQ(expectation.expected_system_id_, keybox_cert->system_id());
|
EXPECT_EQ(expectation.expected_system_id_, keybox_cert->system_id());
|
||||||
EXPECT_EQ(expectation.expected_serial_number_,
|
EXPECT_EQ(expectation.expected_serial_number_,
|
||||||
@@ -145,7 +147,7 @@ void ClientCertTest::TestBasicValidation(const TestTokenAndKeys& expectation,
|
|||||||
EXPECT_EQ(expectation.expected_device_key_, keybox_cert->key());
|
EXPECT_EQ(expectation.expected_device_key_, keybox_cert->key());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
EXPECT_NE(util::OkStatus(), status);
|
EXPECT_NE(OkStatus(), status);
|
||||||
EXPECT_FALSE(keybox_cert);
|
EXPECT_FALSE(keybox_cert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,7 +161,7 @@ void ClientCertTest::TestBasicValidationDrmCertificate(
|
|||||||
DrmRootCertificate::CreateByType(kCertificateTypeTesting, &root_cert_));
|
DrmRootCertificate::CreateByType(kCertificateTypeTesting, &root_cert_));
|
||||||
|
|
||||||
// Test validation of a valid request.
|
// Test validation of a valid request.
|
||||||
util::Status status;
|
Status status;
|
||||||
ClientCert* client_cert_ptr = nullptr;
|
ClientCert* client_cert_ptr = nullptr;
|
||||||
status = ClientCert::Create(root_cert_.get(),
|
status = ClientCert::Create(root_cert_.get(),
|
||||||
ClientIdentification::DRM_DEVICE_CERTIFICATE,
|
ClientIdentification::DRM_DEVICE_CERTIFICATE,
|
||||||
@@ -209,7 +211,7 @@ DrmCertificate* ClientCertTest::GenerateIntermediateCertificate(
|
|||||||
intermediate_certificate->set_type(DrmCertificate::DEVICE_MODEL);
|
intermediate_certificate->set_type(DrmCertificate::DEVICE_MODEL);
|
||||||
intermediate_certificate->set_serial_number(serial_number);
|
intermediate_certificate->set_serial_number(serial_number);
|
||||||
intermediate_certificate->set_public_key(
|
intermediate_certificate->set_public_key(
|
||||||
test_keys_.public_test_key_2_2048_bits());
|
test_rsa_keys_.public_test_key_2_2048_bits());
|
||||||
intermediate_certificate->set_system_id(system_id);
|
intermediate_certificate->set_system_id(system_id);
|
||||||
intermediate_certificate->set_creation_time_seconds(1234);
|
intermediate_certificate->set_creation_time_seconds(1234);
|
||||||
return intermediate_certificate.release();
|
return intermediate_certificate.release();
|
||||||
@@ -221,7 +223,7 @@ SignedDrmCertificate* ClientCertTest::GenerateSignedIntermediateCertificate(
|
|||||||
std::unique_ptr<DrmCertificate> intermediate_certificate(
|
std::unique_ptr<DrmCertificate> intermediate_certificate(
|
||||||
GenerateIntermediateCertificate(system_id, serial_number));
|
GenerateIntermediateCertificate(system_id, serial_number));
|
||||||
return SignCertificate(*intermediate_certificate, signer,
|
return SignCertificate(*intermediate_certificate, signer,
|
||||||
test_keys_.private_test_key_1_3072_bits());
|
test_rsa_keys_.private_test_key_1_3072_bits());
|
||||||
}
|
}
|
||||||
|
|
||||||
DrmCertificate* ClientCertTest::GenerateDrmCertificate(
|
DrmCertificate* ClientCertTest::GenerateDrmCertificate(
|
||||||
@@ -230,7 +232,7 @@ DrmCertificate* ClientCertTest::GenerateDrmCertificate(
|
|||||||
drm_certificate->set_type(DrmCertificate::DEVICE);
|
drm_certificate->set_type(DrmCertificate::DEVICE);
|
||||||
drm_certificate->set_serial_number(serial_number);
|
drm_certificate->set_serial_number(serial_number);
|
||||||
drm_certificate->set_system_id(system_id);
|
drm_certificate->set_system_id(system_id);
|
||||||
drm_certificate->set_public_key(test_keys_.public_test_key_3_2048_bits());
|
drm_certificate->set_public_key(test_rsa_keys_.public_test_key_3_2048_bits());
|
||||||
drm_certificate->set_creation_time_seconds(4321);
|
drm_certificate->set_creation_time_seconds(4321);
|
||||||
return drm_certificate.release();
|
return drm_certificate.release();
|
||||||
}
|
}
|
||||||
@@ -241,7 +243,7 @@ SignedDrmCertificate* ClientCertTest::GenerateSignedDrmCertificate(
|
|||||||
std::unique_ptr<DrmCertificate> drm_certificate(
|
std::unique_ptr<DrmCertificate> drm_certificate(
|
||||||
GenerateDrmCertificate(system_id, serial_number));
|
GenerateDrmCertificate(system_id, serial_number));
|
||||||
std::unique_ptr<SignedDrmCertificate> signed_drm_certificate(SignCertificate(
|
std::unique_ptr<SignedDrmCertificate> signed_drm_certificate(SignCertificate(
|
||||||
*drm_certificate, signer, test_keys_.private_test_key_2_2048_bits()));
|
*drm_certificate, signer, test_rsa_keys_.private_test_key_2_2048_bits()));
|
||||||
return signed_drm_certificate.release();
|
return signed_drm_certificate.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,7 +254,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_1_3072_bits());
|
test_rsa_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);
|
||||||
@@ -264,7 +266,7 @@ SignedDrmCertificate* ClientCertTest::GenerateSignedProvisionerCertificate(
|
|||||||
std::unique_ptr<DrmCertificate> provisioner_certificate(
|
std::unique_ptr<DrmCertificate> provisioner_certificate(
|
||||||
GenerateProvisionerCertificate(system_id, serial_number, service_id));
|
GenerateProvisionerCertificate(system_id, serial_number, service_id));
|
||||||
return SignCertificate(*provisioner_certificate, nullptr,
|
return SignCertificate(*provisioner_certificate, nullptr,
|
||||||
test_keys_.private_test_key_1_3072_bits());
|
test_rsa_keys_.private_test_key_1_3072_bits());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ClientCertTest, BasicValidation) {
|
TEST_F(ClientCertTest, BasicValidation) {
|
||||||
@@ -302,8 +304,7 @@ TEST_F(ClientCertTest, BasicCertValidation) {
|
|||||||
nullptr, system_id, serial_number),
|
nullptr, system_id, serial_number),
|
||||||
system_id, serial_number + "-device"));
|
system_id, serial_number + "-device"));
|
||||||
const TestCertificateAndData kValidCertificateAndExpectedData(
|
const TestCertificateAndData kValidCertificateAndExpectedData(
|
||||||
signed_cert->SerializeAsString(), serial_number, system_id,
|
signed_cert->SerializeAsString(), serial_number, system_id, OkStatus());
|
||||||
util::OkStatus());
|
|
||||||
const bool compare_data = true;
|
const bool compare_data = true;
|
||||||
TestBasicValidationDrmCertificate(kValidCertificateAndExpectedData,
|
TestBasicValidationDrmCertificate(kValidCertificateAndExpectedData,
|
||||||
compare_data);
|
compare_data);
|
||||||
@@ -347,7 +348,7 @@ TEST_F(ClientCertTest, InvalidCertificate) {
|
|||||||
new SignedDrmCertificate);
|
new SignedDrmCertificate);
|
||||||
invalid_drm_cert->set_drm_certificate("bad-serialized-cert");
|
invalid_drm_cert->set_drm_certificate("bad-serialized-cert");
|
||||||
GenerateSignature(invalid_drm_cert->drm_certificate(),
|
GenerateSignature(invalid_drm_cert->drm_certificate(),
|
||||||
test_keys_.private_test_key_2_2048_bits(),
|
test_rsa_keys_.private_test_key_2_2048_bits(),
|
||||||
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));
|
||||||
@@ -357,18 +358,18 @@ TEST_F(ClientCertTest, InvalidCertificate) {
|
|||||||
std::unique_ptr<SignedDrmCertificate> bad_device_public_key(SignCertificate(
|
std::unique_ptr<SignedDrmCertificate> bad_device_public_key(SignCertificate(
|
||||||
*dev_cert,
|
*dev_cert,
|
||||||
GenerateSignedIntermediateCertificate(nullptr, system_id, signer_sn),
|
GenerateSignedIntermediateCertificate(nullptr, system_id, signer_sn),
|
||||||
test_keys_.private_test_key_2_2048_bits()));
|
test_rsa_keys_.private_test_key_2_2048_bits()));
|
||||||
// Invalid serialized intermediate certificate.
|
// Invalid serialized intermediate certificate.
|
||||||
signed_signer.reset(
|
signed_signer.reset(
|
||||||
GenerateSignedIntermediateCertificate(nullptr, system_id, signer_sn));
|
GenerateSignedIntermediateCertificate(nullptr, system_id, signer_sn));
|
||||||
signed_signer->set_drm_certificate("bad-serialized-cert");
|
signed_signer->set_drm_certificate("bad-serialized-cert");
|
||||||
GenerateSignature(signed_signer->drm_certificate(),
|
GenerateSignature(signed_signer->drm_certificate(),
|
||||||
test_keys_.private_test_key_1_3072_bits(),
|
test_rsa_keys_.private_test_key_1_3072_bits(),
|
||||||
signed_signer->mutable_signature());
|
signed_signer->mutable_signature());
|
||||||
dev_cert.reset(GenerateDrmCertificate(system_id, device_sn));
|
dev_cert.reset(GenerateDrmCertificate(system_id, device_sn));
|
||||||
std::unique_ptr<SignedDrmCertificate> invalid_signer(
|
std::unique_ptr<SignedDrmCertificate> invalid_signer(
|
||||||
SignCertificate(*dev_cert, signed_signer.release(),
|
SignCertificate(*dev_cert, signed_signer.release(),
|
||||||
test_keys_.private_test_key_2_2048_bits()));
|
test_rsa_keys_.private_test_key_2_2048_bits()));
|
||||||
// Invalid signer public key.
|
// Invalid signer public key.
|
||||||
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));
|
||||||
@@ -376,8 +377,8 @@ TEST_F(ClientCertTest, InvalidCertificate) {
|
|||||||
std::unique_ptr<SignedDrmCertificate> bad_signer_public_key(SignCertificate(
|
std::unique_ptr<SignedDrmCertificate> bad_signer_public_key(SignCertificate(
|
||||||
*dev_cert,
|
*dev_cert,
|
||||||
SignCertificate(*signer_cert, nullptr,
|
SignCertificate(*signer_cert, nullptr,
|
||||||
test_keys_.private_test_key_1_3072_bits()),
|
test_rsa_keys_.private_test_key_1_3072_bits()),
|
||||||
test_keys_.private_test_key_2_2048_bits()));
|
test_rsa_keys_.private_test_key_2_2048_bits()));
|
||||||
// Invalid device certificate signature.
|
// Invalid device certificate signature.
|
||||||
std::unique_ptr<SignedDrmCertificate> bad_device_signature(
|
std::unique_ptr<SignedDrmCertificate> bad_device_signature(
|
||||||
GenerateSignedDrmCertificate(
|
GenerateSignedDrmCertificate(
|
||||||
@@ -391,8 +392,8 @@ TEST_F(ClientCertTest, InvalidCertificate) {
|
|||||||
std::unique_ptr<SignedDrmCertificate> missing_model_sn(SignCertificate(
|
std::unique_ptr<SignedDrmCertificate> missing_model_sn(SignCertificate(
|
||||||
*dev_cert,
|
*dev_cert,
|
||||||
SignCertificate(*signer_cert, nullptr,
|
SignCertificate(*signer_cert, nullptr,
|
||||||
test_keys_.private_test_key_1_3072_bits()),
|
test_rsa_keys_.private_test_key_1_3072_bits()),
|
||||||
test_keys_.private_test_key_2_2048_bits()));
|
test_rsa_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));
|
||||||
@@ -400,8 +401,8 @@ TEST_F(ClientCertTest, InvalidCertificate) {
|
|||||||
std::unique_ptr<SignedDrmCertificate> missing_signer_sn(SignCertificate(
|
std::unique_ptr<SignedDrmCertificate> missing_signer_sn(SignCertificate(
|
||||||
*dev_cert,
|
*dev_cert,
|
||||||
SignCertificate(*signer_cert, nullptr,
|
SignCertificate(*signer_cert, nullptr,
|
||||||
test_keys_.private_test_key_1_3072_bits()),
|
test_rsa_keys_.private_test_key_1_3072_bits()),
|
||||||
test_keys_.private_test_key_2_2048_bits()));
|
test_rsa_keys_.private_test_key_2_2048_bits()));
|
||||||
// Invalid serialized intermediate certificate.
|
// Invalid serialized intermediate certificate.
|
||||||
dev_cert.reset(GenerateDrmCertificate(system_id, device_sn));
|
dev_cert.reset(GenerateDrmCertificate(system_id, device_sn));
|
||||||
signed_signer.reset(
|
signed_signer.reset(
|
||||||
@@ -409,37 +410,36 @@ TEST_F(ClientCertTest, InvalidCertificate) {
|
|||||||
signed_signer->set_signature("bad-signature");
|
signed_signer->set_signature("bad-signature");
|
||||||
std::unique_ptr<SignedDrmCertificate> bad_signer_signature(
|
std::unique_ptr<SignedDrmCertificate> bad_signer_signature(
|
||||||
SignCertificate(*dev_cert, signed_signer.release(),
|
SignCertificate(*dev_cert, signed_signer.release(),
|
||||||
test_keys_.private_test_key_2_2048_bits()));
|
test_rsa_keys_.private_test_key_2_2048_bits()));
|
||||||
|
|
||||||
const TestCertificateAndData kInvalidCertificate[] = {
|
const TestCertificateAndData kInvalidCertificate[] = {
|
||||||
TestCertificateAndData("f", "", 0,
|
TestCertificateAndData("f", "", 0,
|
||||||
util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"invalid-signed-drm-certificate")),
|
"invalid-signed-drm-certificate")),
|
||||||
TestCertificateAndData(invalid_drm_cert->SerializeAsString(), "", 0,
|
TestCertificateAndData(invalid_drm_cert->SerializeAsString(), "", 0,
|
||||||
util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"invalid-drm-certificate")),
|
"invalid-drm-certificate")),
|
||||||
TestCertificateAndData(bad_device_public_key->SerializeAsString(), "", 0,
|
TestCertificateAndData(bad_device_public_key->SerializeAsString(), "", 0,
|
||||||
util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"drm-certificate-public-key-failed")),
|
"drm-certificate-public-key-failed")),
|
||||||
TestCertificateAndData(invalid_signer->SerializeAsString(), "", 0,
|
TestCertificateAndData(invalid_signer->SerializeAsString(), "", 0,
|
||||||
util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"invalid-signer-certificate")),
|
"invalid-signer-certificate")),
|
||||||
TestCertificateAndData(bad_signer_public_key->SerializeAsString(), "", 0,
|
TestCertificateAndData(bad_signer_public_key->SerializeAsString(), "", 0,
|
||||||
util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"invalid-leaf-signer-public-key")),
|
"invalid-leaf-signer-public-key")),
|
||||||
TestCertificateAndData(bad_device_signature->SerializeAsString(), "", 0,
|
TestCertificateAndData(bad_device_signature->SerializeAsString(), "", 0,
|
||||||
util::Status(error_space, INVALID_SIGNATURE,
|
Status(error_space, INVALID_SIGNATURE,
|
||||||
"cache-miss-invalid-signature")),
|
"cache-miss-invalid-signature")),
|
||||||
TestCertificateAndData(
|
TestCertificateAndData(missing_model_sn->SerializeAsString(), "", 0,
|
||||||
missing_model_sn->SerializeAsString(), "", 0,
|
Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
"model-certificate-missing-system-id")),
|
||||||
"model-certificate-missing-system-id")),
|
|
||||||
TestCertificateAndData(missing_signer_sn->SerializeAsString(), "", 0,
|
TestCertificateAndData(missing_signer_sn->SerializeAsString(), "", 0,
|
||||||
util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"missing-signer-serial-number")),
|
"missing-signer-serial-number")),
|
||||||
TestCertificateAndData(bad_signer_signature->SerializeAsString(), "", 0,
|
TestCertificateAndData(bad_signer_signature->SerializeAsString(), "", 0,
|
||||||
util::Status(error_space, INVALID_SIGNATURE,
|
Status(error_space, INVALID_SIGNATURE,
|
||||||
"cache-miss-invalid-signature")),
|
"cache-miss-invalid-signature")),
|
||||||
};
|
};
|
||||||
|
|
||||||
for (size_t i = 0; i < ABSL_ARRAYSIZE(kInvalidCertificate); ++i) {
|
for (size_t i = 0; i < ABSL_ARRAYSIZE(kInvalidCertificate); ++i) {
|
||||||
@@ -454,7 +454,7 @@ TEST_F(ClientCertTest, MissingPreProvKey) {
|
|||||||
"beaa24924907e128f9ff49b54a165cd9c33e6547537eb4d29fb7e8df3c2c1cd9"
|
"beaa24924907e128f9ff49b54a165cd9c33e6547537eb4d29fb7e8df3c2c1cd9"
|
||||||
"2517a12f4922953e"));
|
"2517a12f4922953e"));
|
||||||
ClientCert* client_cert_ptr = nullptr;
|
ClientCert* client_cert_ptr = nullptr;
|
||||||
util::Status status = ClientCert::CreateWithKeybox(token, &client_cert_ptr);
|
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());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -563,4 +563,55 @@ TEST_F(ClientCertTest, InvalidProvisionerDeviceCertChain) {
|
|||||||
EXPECT_FALSE(client_cert_ptr);
|
EXPECT_FALSE(client_cert_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ClientCertTest, Protocol21WithDrmCert) {
|
||||||
|
const char message[] = "A weekend wasted is a weekend well spent.";
|
||||||
|
|
||||||
|
ClientCert* client_cert_ptr = nullptr;
|
||||||
|
ASSERT_OK(ClientCert::Create(
|
||||||
|
root_cert_.get(), ClientIdentification::DRM_DEVICE_CERTIFICATE,
|
||||||
|
test_drm_certs_.test_user_device_certificate(), &client_cert_ptr));
|
||||||
|
std::unique_ptr<ClientCert> client_cert(client_cert_ptr);
|
||||||
|
|
||||||
|
std::unique_ptr<RsaPrivateKey> private_key(
|
||||||
|
RsaPrivateKey::Create(test_rsa_keys_.private_test_key_3_2048_bits()));
|
||||||
|
ASSERT_TRUE(private_key);
|
||||||
|
|
||||||
|
// Success
|
||||||
|
std::string signature;
|
||||||
|
ASSERT_TRUE(private_key->GenerateSignature(message, &signature));
|
||||||
|
EXPECT_OK(client_cert->VerifySignature(message, signature, VERSION_2_1));
|
||||||
|
|
||||||
|
// Failure
|
||||||
|
ASSERT_EQ(256, signature.size());
|
||||||
|
++signature[127];
|
||||||
|
EXPECT_FALSE(
|
||||||
|
client_cert->VerifySignature(message, signature, VERSION_2_1).ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ClientCertTest, Protocol22WithDrmCert) {
|
||||||
|
const char message[] = "There is nothing permanent except change.";
|
||||||
|
const std::string message_hash(Sha512_Hash(message));
|
||||||
|
|
||||||
|
ClientCert* client_cert_ptr = nullptr;
|
||||||
|
ASSERT_OK(ClientCert::Create(
|
||||||
|
root_cert_.get(), ClientIdentification::DRM_DEVICE_CERTIFICATE,
|
||||||
|
test_drm_certs_.test_user_device_certificate(), &client_cert_ptr));
|
||||||
|
std::unique_ptr<ClientCert> client_cert(client_cert_ptr);
|
||||||
|
|
||||||
|
std::unique_ptr<RsaPrivateKey> private_key(
|
||||||
|
RsaPrivateKey::Create(test_rsa_keys_.private_test_key_3_2048_bits()));
|
||||||
|
ASSERT_TRUE(private_key);
|
||||||
|
|
||||||
|
// Success
|
||||||
|
std::string signature;
|
||||||
|
ASSERT_TRUE(private_key->GenerateSignature(message_hash, &signature));
|
||||||
|
EXPECT_OK(client_cert->VerifySignature(message, signature, VERSION_2_2));
|
||||||
|
|
||||||
|
// Failure
|
||||||
|
ASSERT_EQ(256, signature.size());
|
||||||
|
++signature[127];
|
||||||
|
EXPECT_FALSE(
|
||||||
|
client_cert->VerifySignature(message, signature, VERSION_2_2).ok());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
|
|||||||
@@ -51,39 +51,39 @@ std::string GetClientInfo(const ClientIdentification& client_id,
|
|||||||
return default_value;
|
return default_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status DecryptEncryptedClientIdentification(
|
Status DecryptEncryptedClientIdentification(
|
||||||
const EncryptedClientIdentification& encrypted_client_id,
|
const EncryptedClientIdentification& encrypted_client_id,
|
||||||
ClientIdentification* client_id) {
|
ClientIdentification* client_id) {
|
||||||
return DrmServiceCertificate::DecryptClientIdentification(encrypted_client_id,
|
return DrmServiceCertificate::DecryptClientIdentification(encrypted_client_id,
|
||||||
client_id);
|
client_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status DecryptEncryptedClientIdentification(
|
Status DecryptEncryptedClientIdentification(
|
||||||
const EncryptedClientIdentification& encrypted_client_id,
|
const EncryptedClientIdentification& encrypted_client_id,
|
||||||
const std::string& privacy_key, ClientIdentification* client_id) {
|
const std::string& privacy_key, ClientIdentification* client_id) {
|
||||||
DCHECK(client_id);
|
DCHECK(client_id);
|
||||||
if (!encrypted_client_id.has_encrypted_client_id() ||
|
if (!encrypted_client_id.has_encrypted_client_id() ||
|
||||||
encrypted_client_id.encrypted_client_id().empty()) {
|
encrypted_client_id.encrypted_client_id().empty()) {
|
||||||
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
|
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
|
||||||
"missing-encrypted-client-id");
|
"missing-encrypted-client-id");
|
||||||
}
|
}
|
||||||
if (!encrypted_client_id.has_encrypted_client_id_iv() ||
|
if (!encrypted_client_id.has_encrypted_client_id_iv() ||
|
||||||
encrypted_client_id.encrypted_client_id_iv().empty()) {
|
encrypted_client_id.encrypted_client_id_iv().empty()) {
|
||||||
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
|
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
|
||||||
"missing-encrypted-client-id-iv");
|
"missing-encrypted-client-id-iv");
|
||||||
}
|
}
|
||||||
std::string serialized_client_id(crypto_util::DecryptAesCbc(
|
std::string serialized_client_id(crypto_util::DecryptAesCbc(
|
||||||
privacy_key, encrypted_client_id.encrypted_client_id_iv(),
|
privacy_key, encrypted_client_id.encrypted_client_id_iv(),
|
||||||
encrypted_client_id.encrypted_client_id()));
|
encrypted_client_id.encrypted_client_id()));
|
||||||
if (serialized_client_id.empty()) {
|
if (serialized_client_id.empty()) {
|
||||||
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
|
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
|
||||||
"client-id-decryption-failed");
|
"client-id-decryption-failed");
|
||||||
}
|
}
|
||||||
if (!client_id->ParseFromString(serialized_client_id)) {
|
if (!client_id->ParseFromString(serialized_client_id)) {
|
||||||
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
|
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
|
||||||
"client-id-parse-failed");
|
"client-id-parse-failed");
|
||||||
}
|
}
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
#define COMMON_CLIENT_ID_UTIL_H_
|
#define COMMON_CLIENT_ID_UTIL_H_
|
||||||
|
|
||||||
#include "absl/strings/string_view.h"
|
#include "absl/strings/string_view.h"
|
||||||
#include "util/status.h"
|
#include "common/status.h"
|
||||||
#include "protos/public/client_identification.pb.h"
|
#include "protos/public/client_identification.pb.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
@@ -43,16 +43,16 @@ std::string GetClientInfo(const ClientIdentification& client_id,
|
|||||||
// |client_id| using the private key for the service certificate which was
|
// |client_id| using the private key for the service certificate which was
|
||||||
// used to encrypt the information.
|
// used to encrypt the information.
|
||||||
// |client_id| is owned by caller.
|
// |client_id| is owned by caller.
|
||||||
// Returns util::Status::OK, if successful, else an error.
|
// Returns Status::OK, if successful, else an error.
|
||||||
util::Status DecryptEncryptedClientIdentification(
|
Status DecryptEncryptedClientIdentification(
|
||||||
const EncryptedClientIdentification& encrypted_client_id,
|
const EncryptedClientIdentification& encrypted_client_id,
|
||||||
ClientIdentification* client_id);
|
ClientIdentification* client_id);
|
||||||
|
|
||||||
// Decrypts the encrypted client identification in |encrypted_client_id| into
|
// Decrypts the encrypted client identification in |encrypted_client_id| into
|
||||||
// |client_id| using |privacy_key|.
|
// |client_id| using |privacy_key|.
|
||||||
// |client_id| is owned by caller.
|
// |client_id| is owned by caller.
|
||||||
// Returns util::Status::OK, if successful, else an error.
|
// Returns Status::OK, if successful, else an error.
|
||||||
util::Status DecryptEncryptedClientIdentification(
|
Status DecryptEncryptedClientIdentification(
|
||||||
const EncryptedClientIdentification& encrypted_client_id,
|
const EncryptedClientIdentification& encrypted_client_id,
|
||||||
const std::string& privacy_key, ClientIdentification* client_id);
|
const std::string& privacy_key, ClientIdentification* client_id);
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,8 @@
|
|||||||
namespace widevine {
|
namespace widevine {
|
||||||
namespace crypto_util {
|
namespace crypto_util {
|
||||||
|
|
||||||
const char kEncryptionKeyLabel[] = "ENCRYPTION";
|
const char kWrappingKeyLabel[] = "ENCRYPTION";
|
||||||
const int kEncryptionKeySizeBits = 128;
|
const int kWrappingKeySizeBits = 128;
|
||||||
const char kSigningKeyLabel[] = "AUTHENTICATION";
|
const char kSigningKeyLabel[] = "AUTHENTICATION";
|
||||||
const int kSigningKeySizeBits = 256;
|
const int kSigningKeySizeBits = 256;
|
||||||
const size_t kSigningKeySizeBytes = 32;
|
const size_t kSigningKeySizeBytes = 32;
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ namespace crypto_util {
|
|||||||
|
|
||||||
// Default constants used for key derivation for encryption and signing.
|
// Default constants used for key derivation for encryption and signing.
|
||||||
// TODO(user): These are duplicated in session.cc in the sdk. de-dup.
|
// TODO(user): These are duplicated in session.cc in the sdk. de-dup.
|
||||||
extern const char kEncryptionKeyLabel[];
|
extern const char kWrappingKeyLabel[];
|
||||||
extern const int kEncryptionKeySizeBits;
|
extern const int kWrappingKeySizeBits;
|
||||||
extern const char kSigningKeyLabel[];
|
extern const char kSigningKeyLabel[];
|
||||||
extern const int kSigningKeySizeBits;
|
extern const int kSigningKeySizeBits;
|
||||||
extern const size_t kSigningKeySizeBytes;
|
extern const size_t kSigningKeySizeBytes;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#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/client_cert.h"
|
||||||
|
#include "common/drm_service_certificate.h"
|
||||||
#include "common/error_space.h"
|
#include "common/error_space.h"
|
||||||
#include "common/rsa_key.h"
|
#include "common/rsa_key.h"
|
||||||
#include "protos/public/client_identification.pb.h"
|
#include "protos/public/client_identification.pb.h"
|
||||||
@@ -51,47 +52,47 @@ DeviceStatusList::DeviceStatusList()
|
|||||||
|
|
||||||
DeviceStatusList::~DeviceStatusList() {}
|
DeviceStatusList::~DeviceStatusList() {}
|
||||||
|
|
||||||
util::Status DeviceStatusList::UpdateStatusList(
|
Status DeviceStatusList::UpdateStatusList(
|
||||||
const std::string& root_certificate_public_key,
|
const std::string& root_certificate_public_key,
|
||||||
const std::string& serialized_certificate_status_list,
|
const std::string& serialized_certificate_status_list,
|
||||||
uint32_t expiration_period_seconds) {
|
uint32_t expiration_period_seconds) {
|
||||||
SignedDeviceCertificateStatusList signed_certificate_status_list;
|
SignedDeviceCertificateStatusList signed_certificate_status_list;
|
||||||
if (!signed_certificate_status_list.ParseFromString(
|
if (!signed_certificate_status_list.ParseFromString(
|
||||||
serialized_certificate_status_list)) {
|
serialized_certificate_status_list)) {
|
||||||
return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
|
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
|
||||||
"signed-certificate-status-list-parse-error");
|
"signed-certificate-status-list-parse-error");
|
||||||
}
|
}
|
||||||
if (!signed_certificate_status_list.has_certificate_status_list()) {
|
if (!signed_certificate_status_list.has_certificate_status_list()) {
|
||||||
return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
|
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
|
||||||
"missing-status-list");
|
"missing-status-list");
|
||||||
}
|
}
|
||||||
if (!signed_certificate_status_list.has_signature()) {
|
if (!signed_certificate_status_list.has_signature()) {
|
||||||
return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
|
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
|
||||||
"missing-status-list-signature");
|
"missing-status-list-signature");
|
||||||
}
|
}
|
||||||
std::unique_ptr<RsaPublicKey> root_key(
|
std::unique_ptr<RsaPublicKey> root_key(
|
||||||
RsaPublicKey::Create(root_certificate_public_key));
|
RsaPublicKey::Create(root_certificate_public_key));
|
||||||
if (root_key == nullptr) {
|
if (root_key == nullptr) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"invalid-root-public-key");
|
"invalid-root-public-key");
|
||||||
}
|
}
|
||||||
if (!root_key->VerifySignature(
|
if (!root_key->VerifySignature(
|
||||||
signed_certificate_status_list.certificate_status_list(),
|
signed_certificate_status_list.certificate_status_list(),
|
||||||
signed_certificate_status_list.signature())) {
|
signed_certificate_status_list.signature())) {
|
||||||
return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
|
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
|
||||||
"invalid-status-list-signature");
|
"invalid-status-list-signature");
|
||||||
}
|
}
|
||||||
DeviceCertificateStatusList certificate_status_list;
|
DeviceCertificateStatusList certificate_status_list;
|
||||||
if (!certificate_status_list.ParseFromString(
|
if (!certificate_status_list.ParseFromString(
|
||||||
signed_certificate_status_list.certificate_status_list())) {
|
signed_certificate_status_list.certificate_status_list())) {
|
||||||
return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
|
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
|
||||||
"certificate-status-list-parse-error");
|
"certificate-status-list-parse-error");
|
||||||
}
|
}
|
||||||
if (expiration_period_seconds &&
|
if (expiration_period_seconds &&
|
||||||
(GetCurrentTime() > (certificate_status_list.creation_time_seconds() +
|
(GetCurrentTime() > (certificate_status_list.creation_time_seconds() +
|
||||||
expiration_period_seconds))) {
|
expiration_period_seconds))) {
|
||||||
return util::Status(error_space, EXPIRED_CERTIFICATE_STATUS_LIST,
|
return Status(error_space, EXPIRED_CERTIFICATE_STATUS_LIST,
|
||||||
"certificate-status-list-expired");
|
"certificate-status-list-expired");
|
||||||
}
|
}
|
||||||
|
|
||||||
absl::WriterMutexLock lock(&status_map_lock_);
|
absl::WriterMutexLock lock(&status_map_lock_);
|
||||||
@@ -105,44 +106,44 @@ util::Status DeviceStatusList::UpdateStatusList(
|
|||||||
if (device_info.has_system_id()) {
|
if (device_info.has_system_id()) {
|
||||||
device_status_map_[device_info.system_id()] = cert_status;
|
device_status_map_[device_info.system_id()] = cert_status;
|
||||||
} else {
|
} else {
|
||||||
return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
|
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
|
||||||
"device-info-missing-system-id");
|
"device-info-missing-system-id");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
creation_time_seconds_ = certificate_status_list.creation_time_seconds();
|
creation_time_seconds_ = certificate_status_list.creation_time_seconds();
|
||||||
expiration_period_seconds_ = expiration_period_seconds;
|
expiration_period_seconds_ = expiration_period_seconds;
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status DeviceStatusList::GetCertStatus(
|
Status DeviceStatusList::GetCertStatus(const ClientCert& client_cert,
|
||||||
const ClientCert& client_cert, ProvisionedDeviceInfo* device_info) {
|
ProvisionedDeviceInfo* device_info) {
|
||||||
CHECK(device_info);
|
CHECK(device_info);
|
||||||
|
|
||||||
// Keybox checks.
|
// Keybox checks.
|
||||||
if (client_cert.type() == ClientIdentification::KEYBOX) {
|
if (client_cert.type() == ClientIdentification::KEYBOX) {
|
||||||
if (!KeyboxClientCert::IsSystemIdKnown(client_cert.system_id())) {
|
if (!KeyboxClientCert::IsSystemIdKnown(client_cert.system_id())) {
|
||||||
return util::Status(error_space, UNSUPPORTED_SYSTEM_ID,
|
return Status(error_space, UNSUPPORTED_SYSTEM_ID,
|
||||||
"keybox-unsupported-system-id");
|
"keybox-unsupported-system-id");
|
||||||
}
|
}
|
||||||
// Get device information from certificate status list if available.
|
// Get device information from certificate status list if available.
|
||||||
if (!GetDeviceInfo(client_cert, device_info)) {
|
if (!GetDeviceInfo(client_cert, device_info)) {
|
||||||
device_info->Clear();
|
device_info->Clear();
|
||||||
}
|
}
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
// DRM certificate checks.
|
// DRM certificate checks.
|
||||||
if (client_cert.type() != ClientIdentification::DRM_DEVICE_CERTIFICATE) {
|
if (client_cert.type() != ClientIdentification::DRM_DEVICE_CERTIFICATE) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"device-certificate-unsupported-token-type");
|
"device-certificate-unsupported-token-type");
|
||||||
}
|
}
|
||||||
absl::ReaderMutexLock lock(&status_map_lock_);
|
absl::ReaderMutexLock lock(&status_map_lock_);
|
||||||
if (expiration_period_seconds_ &&
|
if (expiration_period_seconds_ &&
|
||||||
(GetCurrentTime() >
|
(GetCurrentTime() >
|
||||||
(creation_time_seconds_ + expiration_period_seconds_))) {
|
(creation_time_seconds_ + expiration_period_seconds_))) {
|
||||||
return util::Status(error_space, EXPIRED_CERTIFICATE_STATUS_LIST,
|
return Status(error_space, EXPIRED_CERTIFICATE_STATUS_LIST,
|
||||||
"certificate-status-list-expired");
|
"certificate-status-list-expired");
|
||||||
}
|
}
|
||||||
DeviceCertificateStatus* device_cert_status =
|
DeviceCertificateStatus* device_cert_status =
|
||||||
gtl::FindOrNull(device_status_map_, client_cert.system_id());
|
gtl::FindOrNull(device_status_map_, client_cert.system_id());
|
||||||
@@ -154,15 +155,15 @@ util::Status DeviceStatusList::GetCertStatus(
|
|||||||
LOG(WARNING) << "Allowing REVOKED device: "
|
LOG(WARNING) << "Allowing REVOKED device: "
|
||||||
<< device_info->ShortDebugString();
|
<< device_info->ShortDebugString();
|
||||||
} else {
|
} else {
|
||||||
return util::Status(error_space, DRM_DEVICE_CERTIFICATE_REVOKED,
|
return Status(error_space, DRM_DEVICE_CERTIFICATE_REVOKED,
|
||||||
"device-certificate-revoked");
|
"device-certificate-revoked");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((device_cert_status->status() ==
|
if ((device_cert_status->status() ==
|
||||||
DeviceCertificateStatus::STATUS_TEST_ONLY) &&
|
DeviceCertificateStatus::STATUS_TEST_ONLY) &&
|
||||||
!allow_test_only_devices_) {
|
!allow_test_only_devices_) {
|
||||||
return util::Status(error_space, DEVELOPMENT_CERTIFICATE_NOT_ALLOWED,
|
return Status(error_space, DEVELOPMENT_CERTIFICATE_NOT_ALLOWED,
|
||||||
"test-only-drm-certificate-not-allowed");
|
"test-only-drm-certificate-not-allowed");
|
||||||
}
|
}
|
||||||
if (!client_cert.signed_by_provisioner() &&
|
if (!client_cert.signed_by_provisioner() &&
|
||||||
(client_cert.signer_serial_number() !=
|
(client_cert.signer_serial_number() !=
|
||||||
@@ -174,21 +175,21 @@ util::Status DeviceStatusList::GetCertStatus(
|
|||||||
// list is older than the certificate, the certificate is for all purposes
|
// list is older than the certificate, the certificate is for all purposes
|
||||||
// unknown.
|
// unknown.
|
||||||
if (client_cert.signer_creation_time_seconds() < creation_time_seconds_) {
|
if (client_cert.signer_creation_time_seconds() < creation_time_seconds_) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"intermediate-certificate-serial-number-mismatch");
|
"intermediate-certificate-serial-number-mismatch");
|
||||||
}
|
}
|
||||||
return util::Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN,
|
return Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN,
|
||||||
"device-certificate-status-unknown");
|
"device-certificate-status-unknown");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!allow_unknown_devices_) {
|
if (!allow_unknown_devices_) {
|
||||||
return util::Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN,
|
return Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN,
|
||||||
"device-certificate-status-unknown");
|
"device-certificate-status-unknown");
|
||||||
}
|
}
|
||||||
device_info->Clear();
|
device_info->Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeviceStatusList::GetDeviceInfo(const ClientCert& client_cert,
|
bool DeviceStatusList::GetDeviceInfo(const ClientCert& client_cert,
|
||||||
@@ -246,18 +247,18 @@ bool DeviceStatusList::IsRevokedSystemIdAllowed(uint32_t system_id) {
|
|||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status DeviceStatusList::ExtractFromProvisioningServiceResponse(
|
Status DeviceStatusList::ExtractFromProvisioningServiceResponse(
|
||||||
const std::string& certificate_provisioning_service_response,
|
const std::string& certificate_provisioning_service_response,
|
||||||
std::string* signed_certificate_status_list, std::string* certificate_status_list) {
|
std::string* signed_certificate_status_list, std::string* certificate_status_list) {
|
||||||
util::Status status = util::OkStatus();
|
Status status = OkStatus();
|
||||||
size_t signed_list_start =
|
size_t signed_list_start =
|
||||||
certificate_provisioning_service_response.find(kSignedList);
|
certificate_provisioning_service_response.find(kSignedList);
|
||||||
if (signed_list_start != std::string::npos) {
|
if (signed_list_start != std::string::npos) {
|
||||||
size_t signed_list_end = certificate_provisioning_service_response.find(
|
size_t signed_list_end = certificate_provisioning_service_response.find(
|
||||||
kSignedListTerminator, signed_list_start);
|
kSignedListTerminator, signed_list_start);
|
||||||
if (signed_list_end == std::string::npos) {
|
if (signed_list_end == std::string::npos) {
|
||||||
return util::Status(
|
return Status(
|
||||||
error_space, util::error::INVALID_ARGUMENT,
|
error_space, error::INVALID_ARGUMENT,
|
||||||
"Unable to parse the certificate_provisioning_service_response. "
|
"Unable to parse the certificate_provisioning_service_response. "
|
||||||
"SignedList not terminated.");
|
"SignedList not terminated.");
|
||||||
}
|
}
|
||||||
@@ -283,8 +284,8 @@ util::Status DeviceStatusList::ExtractFromProvisioningServiceResponse(
|
|||||||
if (!absl::WebSafeBase64Unescape(signed_list,
|
if (!absl::WebSafeBase64Unescape(signed_list,
|
||||||
signed_certificate_status_list)) {
|
signed_certificate_status_list)) {
|
||||||
if (!absl::Base64Unescape(signed_list, signed_certificate_status_list)) {
|
if (!absl::Base64Unescape(signed_list, signed_certificate_status_list)) {
|
||||||
return util::Status(error_space, util::error::INVALID_ARGUMENT,
|
return Status(error_space, error::INVALID_ARGUMENT,
|
||||||
"Base64 decode of signedlist failed.");
|
"Base64 decode of signedlist failed.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -294,28 +295,68 @@ util::Status DeviceStatusList::ExtractFromProvisioningServiceResponse(
|
|||||||
signed_certificate_status_list)) {
|
signed_certificate_status_list)) {
|
||||||
if (!absl::Base64Unescape(certificate_provisioning_service_response,
|
if (!absl::Base64Unescape(certificate_provisioning_service_response,
|
||||||
signed_certificate_status_list)) {
|
signed_certificate_status_list)) {
|
||||||
return util::Status(error_space, util::error::INVALID_ARGUMENT,
|
return Status(error_space, error::INVALID_ARGUMENT,
|
||||||
"Base64 decode of certList failed.");
|
"Base64 decode of certList failed.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SignedDeviceCertificateStatusList signed_status_list;
|
SignedDeviceCertificateStatusList signed_status_list;
|
||||||
if (!signed_status_list.ParseFromString(*signed_certificate_status_list)) {
|
if (!signed_status_list.ParseFromString(*signed_certificate_status_list)) {
|
||||||
return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
|
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
|
||||||
"signed-certificate-status-list-parse-error");
|
"signed-certificate-status-list-parse-error");
|
||||||
}
|
}
|
||||||
if (!signed_status_list.has_certificate_status_list()) {
|
if (!signed_status_list.has_certificate_status_list()) {
|
||||||
return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
|
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
|
||||||
"missing-status-list");
|
"missing-status-list");
|
||||||
}
|
}
|
||||||
DeviceCertificateStatusList device_certificate_status_list;
|
DeviceCertificateStatusList device_certificate_status_list;
|
||||||
if (!device_certificate_status_list.ParseFromString(
|
if (!device_certificate_status_list.ParseFromString(
|
||||||
signed_status_list.certificate_status_list())) {
|
signed_status_list.certificate_status_list())) {
|
||||||
return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
|
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
|
||||||
"certificate-status-list-parse-error");
|
"certificate-status-list-parse-error");
|
||||||
}
|
}
|
||||||
*certificate_status_list = signed_status_list.certificate_status_list();
|
*certificate_status_list = signed_status_list.certificate_status_list();
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Status DeviceStatusList::GenerateSignedDeviceCertificateStatusListRequest(
|
||||||
|
const std::string& version,
|
||||||
|
std::string* signed_device_certificate_status_list_request) {
|
||||||
|
if (version.empty()) {
|
||||||
|
return Status(error_space, error::INVALID_ARGUMENT, "SDK version is empty");
|
||||||
|
}
|
||||||
|
DCHECK(signed_device_certificate_status_list_request);
|
||||||
|
if (signed_device_certificate_status_list_request == nullptr) {
|
||||||
|
return Status(error_space, error::INVALID_ARGUMENT,
|
||||||
|
"Signed_device_certificate_status_list_request is empty");
|
||||||
|
}
|
||||||
|
// Construct SignedDeviceCertificateStatusListRequest.
|
||||||
|
DeviceCertificateStatusListRequest request;
|
||||||
|
request.set_sdk_version(version);
|
||||||
|
request.set_sdk_time_seconds(DeviceStatusList::Instance()->GetCurrentTime());
|
||||||
|
std::string device_certificate_status_list_request;
|
||||||
|
request.SerializeToString(&device_certificate_status_list_request);
|
||||||
|
SignedDeviceCertificateStatusListRequest signed_request;
|
||||||
|
signed_request.set_device_certificate_status_list_request(
|
||||||
|
device_certificate_status_list_request);
|
||||||
|
const DrmServiceCertificate* sc =
|
||||||
|
DrmServiceCertificate::GetDefaultDrmServiceCertificate();
|
||||||
|
if (sc == nullptr) {
|
||||||
|
signed_device_certificate_status_list_request->clear();
|
||||||
|
return Status(error_space, widevine::INVALID_SERVICE_CERTIFICATE,
|
||||||
|
"Drm service certificate is not loaded.");
|
||||||
|
}
|
||||||
|
const RsaPrivateKey* private_key = sc->private_key();
|
||||||
|
if (private_key == nullptr) {
|
||||||
|
return Status(error_space, widevine::INVALID_SERVICE_CERTIFICATE,
|
||||||
|
"Private key in the service certificate is null.");
|
||||||
|
}
|
||||||
|
std::string signature;
|
||||||
|
private_key->GenerateSignature(device_certificate_status_list_request,
|
||||||
|
&signature);
|
||||||
|
signed_request.set_signature(signature);
|
||||||
|
signed_request.SerializeToString(
|
||||||
|
signed_device_certificate_status_list_request);
|
||||||
|
return OkStatus();
|
||||||
|
}
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
#include "base/macros.h"
|
#include "base/macros.h"
|
||||||
#include "absl/synchronization/mutex.h"
|
#include "absl/synchronization/mutex.h"
|
||||||
#include "util/status.h"
|
#include "common/status.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"
|
||||||
|
|
||||||
@@ -37,12 +37,12 @@ class DeviceStatusList {
|
|||||||
DeviceStatusList();
|
DeviceStatusList();
|
||||||
virtual ~DeviceStatusList();
|
virtual ~DeviceStatusList();
|
||||||
|
|
||||||
// Takes |signed_certificate_status_list| and copies to an internal map of
|
// Takes |serialized_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.
|
||||||
util::Status UpdateStatusList(const std::string& root_certificate_public_key,
|
Status UpdateStatusList(const std::string& root_certificate_public_key,
|
||||||
const std::string& signed_certificate_status_list,
|
const std::string& serialized_certificate_status_list,
|
||||||
uint32_t expiration_period_seconds);
|
uint32_t expiration_period_seconds);
|
||||||
void set_allow_unknown_devices(bool flag) { allow_unknown_devices_ = flag; }
|
void set_allow_unknown_devices(bool flag) { allow_unknown_devices_ = flag; }
|
||||||
bool allow_unknown_devices() const { return allow_unknown_devices_; }
|
bool allow_unknown_devices() const { return allow_unknown_devices_; }
|
||||||
void set_allow_test_only_devices(bool allow) {
|
void set_allow_test_only_devices(bool allow) {
|
||||||
@@ -58,9 +58,8 @@ class DeviceStatusList {
|
|||||||
// DRM_DEVICE_CERTIFICATE_UNKNOWN
|
// DRM_DEVICE_CERTIFICATE_UNKNOWN
|
||||||
// If status is OK, a copy of the provisioned device info is copied
|
// If status is OK, a copy of the provisioned device info is copied
|
||||||
// into |device_info|. Caller owns |device_info| and it must not be null.
|
// into |device_info|. Caller owns |device_info| and it must not be null.
|
||||||
util::Status GetCertStatus(
|
Status GetCertStatus(const ClientCert& client_cert,
|
||||||
const ClientCert& client_cert,
|
widevine::ProvisionedDeviceInfo* device_info);
|
||||||
widevine::ProvisionedDeviceInfo* device_info);
|
|
||||||
// Returns true if the pre-provisioning key or certificate for the specified
|
// Returns true if the pre-provisioning key or certificate for the specified
|
||||||
// system ID are active (not disallowed or revoked).
|
// system ID are active (not disallowed or revoked).
|
||||||
bool IsSystemIdActive(uint32_t system_id);
|
bool IsSystemIdActive(uint32_t system_id);
|
||||||
@@ -86,9 +85,19 @@ class DeviceStatusList {
|
|||||||
* @param certificate_status_list
|
* @param certificate_status_list
|
||||||
* @return WvPLStatus - Status::OK if success, else error.
|
* @return WvPLStatus - Status::OK if success, else error.
|
||||||
*/
|
*/
|
||||||
static util::Status ExtractFromProvisioningServiceResponse(
|
static Status ExtractFromProvisioningServiceResponse(
|
||||||
const std::string& certificate_provisioning_service_response,
|
const std::string& certificate_provisioning_service_response,
|
||||||
std::string* signed_certificate_status_list, std::string* certificate_status_list);
|
std::string* signed_certificate_status_list, std::string* certificate_status_list);
|
||||||
|
/**
|
||||||
|
* Constructs signed device certificate status list request string.
|
||||||
|
*
|
||||||
|
* @param signed_device_certificate_status_list_request
|
||||||
|
* @param version
|
||||||
|
* @return Status - Status::OK if success, else error.
|
||||||
|
*/
|
||||||
|
static Status GenerateSignedDeviceCertificateStatusListRequest(
|
||||||
|
const std::string& version,
|
||||||
|
std::string* signed_device_certificate_status_list_request);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Returns true if the system ID is allowed to be revoked.
|
// Returns true if the system ID is allowed to be revoked.
|
||||||
|
|||||||
@@ -114,10 +114,9 @@ class DeviceStatusListTest : public ::testing::Test {
|
|||||||
ASSERT_TRUE(
|
ASSERT_TRUE(
|
||||||
signed_cert_status_list_.SerializeToString(&serialized_status_list_));
|
signed_cert_status_list_.SerializeToString(&serialized_status_list_));
|
||||||
|
|
||||||
ASSERT_EQ(util::OkStatus(),
|
ASSERT_EQ(OkStatus(), device_status_list_.UpdateStatusList(
|
||||||
device_status_list_.UpdateStatusList(
|
test_keys_.public_test_key_1_3072_bits(),
|
||||||
test_keys_.public_test_key_1_3072_bits(),
|
serialized_status_list_, kDefaultExpirePeriod));
|
||||||
serialized_status_list_, kDefaultExpirePeriod));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceStatusList device_status_list_;
|
DeviceStatusList device_status_list_;
|
||||||
@@ -140,7 +139,7 @@ TEST_F(DeviceStatusListTest, CheckForValidAndRevokedCert) {
|
|||||||
.WillRepeatedly(Return(kValidCertSystemId));
|
.WillRepeatedly(Return(kValidCertSystemId));
|
||||||
EXPECT_CALL(valid_client_cert, signer_serial_number())
|
EXPECT_CALL(valid_client_cert, signer_serial_number())
|
||||||
.WillRepeatedly(ReturnRef(valid_drm_serial_number));
|
.WillRepeatedly(ReturnRef(valid_drm_serial_number));
|
||||||
EXPECT_EQ(util::OkStatus(),
|
EXPECT_EQ(OkStatus(),
|
||||||
device_status_list_.GetCertStatus(valid_client_cert, &device_info));
|
device_status_list_.GetCertStatus(valid_client_cert, &device_info));
|
||||||
EXPECT_TRUE(device_info.has_model());
|
EXPECT_TRUE(device_info.has_model());
|
||||||
EXPECT_EQ(kDeviceModel, device_info.model());
|
EXPECT_EQ(kDeviceModel, device_info.model());
|
||||||
@@ -191,8 +190,8 @@ TEST_F(DeviceStatusListTest, TestOnlyCertNotAllowed) {
|
|||||||
.WillRepeatedly(Return(kTestOnlyCertSystemId));
|
.WillRepeatedly(Return(kTestOnlyCertSystemId));
|
||||||
EXPECT_CALL(test_only_client_cert, signer_serial_number())
|
EXPECT_CALL(test_only_client_cert, signer_serial_number())
|
||||||
.WillRepeatedly(ReturnRef(test_only_drm_serial_number));
|
.WillRepeatedly(ReturnRef(test_only_drm_serial_number));
|
||||||
EXPECT_EQ(util::OkStatus(), device_status_list_.GetCertStatus(
|
EXPECT_EQ(OkStatus(), device_status_list_.GetCertStatus(test_only_client_cert,
|
||||||
test_only_client_cert, &device_info));
|
&device_info));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DeviceStatusListTest, ValidAndUnknownKeybox) {
|
TEST_F(DeviceStatusListTest, ValidAndUnknownKeybox) {
|
||||||
@@ -208,8 +207,8 @@ TEST_F(DeviceStatusListTest, ValidAndUnknownKeybox) {
|
|||||||
.WillRepeatedly(Return(ClientIdentification::KEYBOX));
|
.WillRepeatedly(Return(ClientIdentification::KEYBOX));
|
||||||
EXPECT_CALL(valid_client_keybox, system_id())
|
EXPECT_CALL(valid_client_keybox, system_id())
|
||||||
.WillRepeatedly(Return(kValidCertSystemId));
|
.WillRepeatedly(Return(kValidCertSystemId));
|
||||||
EXPECT_EQ(util::OkStatus(), device_status_list_.GetCertStatus(
|
EXPECT_EQ(OkStatus(), device_status_list_.GetCertStatus(valid_client_keybox,
|
||||||
valid_client_keybox, &device_info));
|
&device_info));
|
||||||
EXPECT_TRUE(device_info.has_model());
|
EXPECT_TRUE(device_info.has_model());
|
||||||
EXPECT_EQ(kDeviceModel, device_info.model());
|
EXPECT_EQ(kDeviceModel, device_info.model());
|
||||||
|
|
||||||
@@ -249,7 +248,7 @@ TEST_F(DeviceStatusListTest, SignerSerialNumberMismatch) {
|
|||||||
// We allow this case only for certs signed by a provisioner cert.
|
// We allow this case only for certs signed by a provisioner cert.
|
||||||
EXPECT_CALL(older_client_cert, signed_by_provisioner())
|
EXPECT_CALL(older_client_cert, signed_by_provisioner())
|
||||||
.WillOnce(Return(true));
|
.WillOnce(Return(true));
|
||||||
EXPECT_EQ(util::OkStatus(),
|
EXPECT_EQ(OkStatus(),
|
||||||
device_status_list_.GetCertStatus(older_client_cert, &device_info));
|
device_status_list_.GetCertStatus(older_client_cert, &device_info));
|
||||||
EXPECT_TRUE(device_info.has_system_id());
|
EXPECT_TRUE(device_info.has_system_id());
|
||||||
EXPECT_EQ(kValidCertSystemId, device_info.system_id());
|
EXPECT_EQ(kValidCertSystemId, device_info.system_id());
|
||||||
@@ -314,9 +313,9 @@ TEST_F(DeviceStatusListTest, ExpiredStatusListOnSet) {
|
|||||||
.Times(2)
|
.Times(2)
|
||||||
.WillOnce(Return(kStatusListCreationTime + 100))
|
.WillOnce(Return(kStatusListCreationTime + 100))
|
||||||
.WillOnce(Return(kStatusListCreationTime + 101));
|
.WillOnce(Return(kStatusListCreationTime + 101));
|
||||||
EXPECT_EQ(util::OkStatus(), mock_device_status_list.UpdateStatusList(
|
EXPECT_EQ(OkStatus(), mock_device_status_list.UpdateStatusList(
|
||||||
test_keys_.public_test_key_1_3072_bits(),
|
test_keys_.public_test_key_1_3072_bits(),
|
||||||
serialized_status_list_, 100));
|
serialized_status_list_, 100));
|
||||||
EXPECT_EQ(EXPIRED_CERTIFICATE_STATUS_LIST,
|
EXPECT_EQ(EXPIRED_CERTIFICATE_STATUS_LIST,
|
||||||
mock_device_status_list
|
mock_device_status_list
|
||||||
.UpdateStatusList(test_keys_.public_test_key_1_3072_bits(),
|
.UpdateStatusList(test_keys_.public_test_key_1_3072_bits(),
|
||||||
@@ -331,9 +330,9 @@ TEST_F(DeviceStatusListTest, ExpiredStatusListOnCertCheck) {
|
|||||||
.WillOnce(Return(kStatusListCreationTime + 100))
|
.WillOnce(Return(kStatusListCreationTime + 100))
|
||||||
.WillOnce(Return(kStatusListCreationTime + 100))
|
.WillOnce(Return(kStatusListCreationTime + 100))
|
||||||
.WillOnce(Return(kStatusListCreationTime + 101));
|
.WillOnce(Return(kStatusListCreationTime + 101));
|
||||||
EXPECT_EQ(util::OkStatus(), mock_device_status_list.UpdateStatusList(
|
EXPECT_EQ(OkStatus(), mock_device_status_list.UpdateStatusList(
|
||||||
test_keys_.public_test_key_1_3072_bits(),
|
test_keys_.public_test_key_1_3072_bits(),
|
||||||
serialized_status_list_, 100));
|
serialized_status_list_, 100));
|
||||||
|
|
||||||
ProvisionedDeviceInfo device_info;
|
ProvisionedDeviceInfo device_info;
|
||||||
MockCertificateClientCert valid_client_cert;
|
MockCertificateClientCert valid_client_cert;
|
||||||
@@ -346,8 +345,8 @@ TEST_F(DeviceStatusListTest, ExpiredStatusListOnCertCheck) {
|
|||||||
.WillRepeatedly(ReturnRef(valid_drm_serial_number));
|
.WillRepeatedly(ReturnRef(valid_drm_serial_number));
|
||||||
EXPECT_CALL(valid_client_cert, signer_creation_time_seconds())
|
EXPECT_CALL(valid_client_cert, signer_creation_time_seconds())
|
||||||
.WillRepeatedly(Return(kStatusListCreationTime - 1));
|
.WillRepeatedly(Return(kStatusListCreationTime - 1));
|
||||||
EXPECT_EQ(util::OkStatus(), mock_device_status_list.GetCertStatus(
|
EXPECT_EQ(OkStatus(), mock_device_status_list.GetCertStatus(valid_client_cert,
|
||||||
valid_client_cert, &device_info));
|
&device_info));
|
||||||
|
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
EXPIRED_CERTIFICATE_STATUS_LIST,
|
EXPIRED_CERTIFICATE_STATUS_LIST,
|
||||||
|
|||||||
@@ -265,10 +265,10 @@ class VerifiedCertSignatureCache {
|
|||||||
|
|
||||||
// Checks cache, on miss, uses public key. If successful, adds to
|
// Checks cache, on miss, uses public key. If successful, adds to
|
||||||
// cache.
|
// cache.
|
||||||
util::Status VerifySignature(const std::string& cert, const std::string& serial_number,
|
Status VerifySignature(const std::string& cert, const std::string& serial_number,
|
||||||
const std::string& signature,
|
const std::string& signature,
|
||||||
const std::string& signer_public_key,
|
const std::string& signer_public_key,
|
||||||
const std::string& signer_serial_number) {
|
const std::string& signer_serial_number) {
|
||||||
{
|
{
|
||||||
VerifiedCertSignatures::iterator cached_signature;
|
VerifiedCertSignatures::iterator cached_signature;
|
||||||
absl::ReaderMutexLock read_lock(&signature_cache_mutex_);
|
absl::ReaderMutexLock read_lock(&signature_cache_mutex_);
|
||||||
@@ -279,11 +279,11 @@ class VerifiedCertSignatureCache {
|
|||||||
(signature != cached_signature->second.signature) ||
|
(signature != cached_signature->second.signature) ||
|
||||||
(signer_serial_number != cached_signature->second.signer_serial)) {
|
(signer_serial_number != cached_signature->second.signer_serial)) {
|
||||||
// Cached signature mismatch.
|
// Cached signature mismatch.
|
||||||
return util::Status(error_space, INVALID_SIGNATURE,
|
return Status(error_space, INVALID_SIGNATURE,
|
||||||
"cached-signature-mismatch");
|
"cached-signature-mismatch");
|
||||||
}
|
}
|
||||||
// Cached signature match.
|
// Cached signature match.
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,12 +291,12 @@ class VerifiedCertSignatureCache {
|
|||||||
std::unique_ptr<RsaPublicKey> signer_key(
|
std::unique_ptr<RsaPublicKey> signer_key(
|
||||||
key_factory_->CreateFromPkcs1PublicKey(signer_public_key));
|
key_factory_->CreateFromPkcs1PublicKey(signer_public_key));
|
||||||
if (!signer_key) {
|
if (!signer_key) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"invalid-signer-public-key");
|
"invalid-signer-public-key");
|
||||||
}
|
}
|
||||||
if (!signer_key->VerifySignature(cert, signature)) {
|
if (!signer_key->VerifySignature(cert, signature)) {
|
||||||
return util::Status(error_space, INVALID_SIGNATURE,
|
return Status(error_space, INVALID_SIGNATURE,
|
||||||
"cache-miss-invalid-signature");
|
"cache-miss-invalid-signature");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add signature to cache.
|
// Add signature to cache.
|
||||||
@@ -304,7 +304,7 @@ class VerifiedCertSignatureCache {
|
|||||||
signature_cache_.emplace(
|
signature_cache_.emplace(
|
||||||
serial_number,
|
serial_number,
|
||||||
VerifiedCertSignature(cert, signature, signer_serial_number));
|
VerifiedCertSignature(cert, signature, signer_serial_number));
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -313,7 +313,7 @@ class VerifiedCertSignatureCache {
|
|||||||
const RsaKeyFactory* key_factory_;
|
const RsaKeyFactory* key_factory_;
|
||||||
};
|
};
|
||||||
|
|
||||||
util::Status DrmRootCertificate::CreateByType(
|
Status DrmRootCertificate::CreateByType(
|
||||||
CertificateType cert_type, std::unique_ptr<DrmRootCertificate>* cert) {
|
CertificateType cert_type, std::unique_ptr<DrmRootCertificate>* cert) {
|
||||||
CHECK(cert);
|
CHECK(cert);
|
||||||
|
|
||||||
@@ -321,7 +321,7 @@ util::Status DrmRootCertificate::CreateByType(
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<DrmRootCertificate> DrmRootCertificate::CreateByType(
|
std::unique_ptr<DrmRootCertificate> DrmRootCertificate::CreateByType(
|
||||||
CertificateType cert_type, util::Status* status) {
|
CertificateType cert_type, Status* status) {
|
||||||
CHECK(status);
|
CHECK(status);
|
||||||
|
|
||||||
std::unique_ptr<DrmRootCertificate> new_root_cert;
|
std::unique_ptr<DrmRootCertificate> new_root_cert;
|
||||||
@@ -329,7 +329,7 @@ std::unique_ptr<DrmRootCertificate> DrmRootCertificate::CreateByType(
|
|||||||
return new_root_cert;
|
return new_root_cert;
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status DrmRootCertificate::CreateByTypeString(
|
Status DrmRootCertificate::CreateByTypeString(
|
||||||
const std::string& cert_type_string, std::unique_ptr<DrmRootCertificate>* cert) {
|
const std::string& cert_type_string, std::unique_ptr<DrmRootCertificate>* cert) {
|
||||||
CHECK(cert);
|
CHECK(cert);
|
||||||
|
|
||||||
@@ -341,17 +341,16 @@ util::Status DrmRootCertificate::CreateByTypeString(
|
|||||||
} else if (cert_type_string == kTestingString) {
|
} else if (cert_type_string == kTestingString) {
|
||||||
cert_type = kCertificateTypeTesting;
|
cert_type = kCertificateTypeTesting;
|
||||||
} else {
|
} else {
|
||||||
return util::Status(
|
return Status(error_space, INVALID_PARAMETER,
|
||||||
error_space, INVALID_PARAMETER,
|
absl::StrCat("invalid-certificate-type ", cert_type_string));
|
||||||
absl::StrCat("invalid-certificate-type ", cert_type_string));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return CreateByType(cert_type, cert);
|
return CreateByType(cert_type, cert);
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status DrmRootCertificate::Create(
|
Status DrmRootCertificate::Create(CertificateType cert_type,
|
||||||
CertificateType cert_type, std::unique_ptr<RsaKeyFactory> key_factory,
|
std::unique_ptr<RsaKeyFactory> key_factory,
|
||||||
std::unique_ptr<DrmRootCertificate>* cert) {
|
std::unique_ptr<DrmRootCertificate>* cert) {
|
||||||
DCHECK(cert);
|
DCHECK(cert);
|
||||||
|
|
||||||
std::string serialized_certificate;
|
std::string serialized_certificate;
|
||||||
@@ -375,49 +374,48 @@ util::Status DrmRootCertificate::Create(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return util::Status(error_space, INVALID_PARAMETER,
|
return Status(error_space, INVALID_PARAMETER, "invalid-certificate-type");
|
||||||
"invalid-certificate-type");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SignedDrmCertificate signed_root_cert;
|
SignedDrmCertificate signed_root_cert;
|
||||||
if (!signed_root_cert.ParseFromString(serialized_certificate)) {
|
if (!signed_root_cert.ParseFromString(serialized_certificate)) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"signed-root-cert-deserialize-fail");
|
"signed-root-cert-deserialize-fail");
|
||||||
}
|
}
|
||||||
DrmCertificate root_cert;
|
DrmCertificate root_cert;
|
||||||
if (!signed_root_cert.has_drm_certificate()) {
|
if (!signed_root_cert.has_drm_certificate()) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"missing-root-device-certificate");
|
"missing-root-device-certificate");
|
||||||
}
|
}
|
||||||
if (!root_cert.ParseFromString(signed_root_cert.drm_certificate())) {
|
if (!root_cert.ParseFromString(signed_root_cert.drm_certificate())) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"root-cert-deserialize-fail");
|
"root-cert-deserialize-fail");
|
||||||
}
|
}
|
||||||
if (!root_cert.has_public_key()) {
|
if (!root_cert.has_public_key()) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"missing-root-cert-public-key");
|
"missing-root-cert-public-key");
|
||||||
}
|
}
|
||||||
if (!signed_root_cert.has_signature()) {
|
if (!signed_root_cert.has_signature()) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return 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(
|
||||||
key_factory->CreateFromPkcs1PublicKey(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 Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"invalid-root-public-key");
|
"invalid-root-public-key");
|
||||||
}
|
}
|
||||||
if (!public_key->VerifySignature(signed_root_cert.drm_certificate(),
|
if (!public_key->VerifySignature(signed_root_cert.drm_certificate(),
|
||||||
signed_root_cert.signature())) {
|
signed_root_cert.signature())) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"invalid-root-certificate-signature");
|
"invalid-root-certificate-signature");
|
||||||
}
|
}
|
||||||
|
|
||||||
cert->reset(new DrmRootCertificate(
|
cert->reset(new DrmRootCertificate(
|
||||||
cert_type, serialized_certificate, root_cert.serial_number(),
|
cert_type, serialized_certificate, root_cert.serial_number(),
|
||||||
root_cert.public_key(), std::move(key_factory)));
|
root_cert.public_key(), std::move(key_factory)));
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
DrmRootCertificate::DrmRootCertificate(
|
DrmRootCertificate::DrmRootCertificate(
|
||||||
@@ -437,7 +435,7 @@ std::string DrmRootCertificate::GetDigest() const {
|
|||||||
return absl::BytesToHexString(Sha256_Hash(serialized_certificate_));
|
return absl::BytesToHexString(Sha256_Hash(serialized_certificate_));
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status DrmRootCertificate::VerifyCertificate(
|
Status DrmRootCertificate::VerifyCertificate(
|
||||||
const std::string& serialized_certificate,
|
const std::string& serialized_certificate,
|
||||||
SignedDrmCertificate* signed_certificate,
|
SignedDrmCertificate* signed_certificate,
|
||||||
DrmCertificate* certificate) const {
|
DrmCertificate* certificate) const {
|
||||||
@@ -447,8 +445,8 @@ util::Status DrmRootCertificate::VerifyCertificate(
|
|||||||
signed_certificate = local_signed_certificate.get();
|
signed_certificate = local_signed_certificate.get();
|
||||||
}
|
}
|
||||||
if (!signed_certificate->ParseFromString(serialized_certificate)) {
|
if (!signed_certificate->ParseFromString(serialized_certificate)) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"invalid-signed-drm-certificate");
|
"invalid-signed-drm-certificate");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<DrmCertificate> local_certificate;
|
std::unique_ptr<DrmCertificate> local_certificate;
|
||||||
@@ -458,20 +456,19 @@ util::Status DrmRootCertificate::VerifyCertificate(
|
|||||||
}
|
}
|
||||||
if (signed_certificate->drm_certificate().empty() ||
|
if (signed_certificate->drm_certificate().empty() ||
|
||||||
!certificate->ParseFromString(signed_certificate->drm_certificate())) {
|
!certificate->ParseFromString(signed_certificate->drm_certificate())) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"invalid-drm-certificate");
|
"invalid-drm-certificate");
|
||||||
}
|
}
|
||||||
if (certificate->serial_number().empty()) {
|
if (certificate->serial_number().empty()) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"missing-serial-number");
|
"missing-serial-number");
|
||||||
}
|
}
|
||||||
if (!certificate->has_creation_time_seconds()) {
|
if (!certificate->has_creation_time_seconds()) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"missing-creation-time");
|
"missing-creation-time");
|
||||||
}
|
}
|
||||||
if (certificate->public_key().empty()) {
|
if (certificate->public_key().empty()) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return Status(error_space, INVALID_DRM_CERTIFICATE, "missing-public-key");
|
||||||
"missing-public-key");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify signature chain, but do not use cache for leaf certificates.
|
// Verify signature chain, but do not use cache for leaf certificates.
|
||||||
@@ -485,7 +482,7 @@ util::Status DrmRootCertificate::VerifyCertificate(
|
|||||||
// the case of device-unique device certificates.
|
// the case of device-unique device certificates.
|
||||||
// Signatures for root-signed certificates are always cached, even if they are
|
// Signatures for root-signed certificates are always cached, even if they are
|
||||||
// leaf certificates. For example service, and provisioner certificates.
|
// leaf certificates. For example service, and provisioner certificates.
|
||||||
util::Status DrmRootCertificate::VerifySignatures(
|
Status DrmRootCertificate::VerifySignatures(
|
||||||
const SignedDrmCertificate& signed_cert, const std::string& cert_serial_number,
|
const SignedDrmCertificate& signed_cert, const std::string& cert_serial_number,
|
||||||
bool use_cache) const {
|
bool use_cache) const {
|
||||||
if (!signed_cert.has_signer()) {
|
if (!signed_cert.has_signer()) {
|
||||||
@@ -497,12 +494,12 @@ util::Status DrmRootCertificate::VerifySignatures(
|
|||||||
|
|
||||||
DrmCertificate signer;
|
DrmCertificate signer;
|
||||||
if (!signer.ParseFromString(signed_cert.signer().drm_certificate())) {
|
if (!signer.ParseFromString(signed_cert.signer().drm_certificate())) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"invalid-signer-certificate");
|
"invalid-signer-certificate");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify the signer before verifying signed_cert.
|
// Verify the signer before verifying signed_cert.
|
||||||
util::Status status =
|
Status status =
|
||||||
VerifySignatures(signed_cert.signer(), signer.serial_number(), kUseCache);
|
VerifySignatures(signed_cert.signer(), signer.serial_number(), kUseCache);
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
return status;
|
return status;
|
||||||
@@ -519,17 +516,17 @@ util::Status DrmRootCertificate::VerifySignatures(
|
|||||||
std::unique_ptr<RsaPublicKey> signer_public_key(
|
std::unique_ptr<RsaPublicKey> signer_public_key(
|
||||||
key_factory_->CreateFromPkcs1PublicKey(signer.public_key()));
|
key_factory_->CreateFromPkcs1PublicKey(signer.public_key()));
|
||||||
if (!signer_public_key) {
|
if (!signer_public_key) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"invalid-leaf-signer-public-key");
|
"invalid-leaf-signer-public-key");
|
||||||
}
|
}
|
||||||
if (!signer_public_key->VerifySignature(signed_cert.drm_certificate(),
|
if (!signer_public_key->VerifySignature(signed_cert.drm_certificate(),
|
||||||
signed_cert.signature())) {
|
signed_cert.signature())) {
|
||||||
return util::Status(error_space, INVALID_SIGNATURE,
|
return Status(error_space, INVALID_SIGNATURE,
|
||||||
"cache-miss-invalid-signature");
|
"cache-miss-invalid-signature");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "base/macros.h"
|
#include "base/macros.h"
|
||||||
#include "util/status.h"
|
#include "common/status.h"
|
||||||
|
|
||||||
#include "common/certificate_type.h"
|
#include "common/certificate_type.h"
|
||||||
|
|
||||||
@@ -42,13 +42,13 @@ class DrmRootCertificate {
|
|||||||
// 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 const DrmRootCertificate* if successful. The caller assumes
|
// created const DrmRootCertificate* if successful. The caller assumes
|
||||||
// ownership of the new DrmRootCertificate. This method returns
|
// ownership of the new DrmRootCertificate. This method returns
|
||||||
// util::Status::OK on success, or appropriate error status otherwise.
|
// Status::OK on success, or appropriate error status otherwise.
|
||||||
static util::Status CreateByType(CertificateType cert_type,
|
static Status CreateByType(CertificateType cert_type,
|
||||||
std::unique_ptr<DrmRootCertificate>* cert);
|
std::unique_ptr<DrmRootCertificate>* cert);
|
||||||
|
|
||||||
// Variant on the method above to make CLIF happy until b/110539622 is fixed.
|
// Variant on the method above to make CLIF happy until b/110539622 is fixed.
|
||||||
static std::unique_ptr<DrmRootCertificate> CreateByType(
|
static std::unique_ptr<DrmRootCertificate> CreateByType(
|
||||||
CertificateType cert_type, util::Status* status);
|
CertificateType cert_type, Status* status);
|
||||||
|
|
||||||
// Creates a DrmRootCertificate object given a certificate type std::string, which
|
// Creates a DrmRootCertificate object given a certificate type std::string, which
|
||||||
// must be one of "prod", "qa", or "test".
|
// must be one of "prod", "qa", or "test".
|
||||||
@@ -56,19 +56,16 @@ class DrmRootCertificate {
|
|||||||
// 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 const DrmRootCertificate* if successful. The caller assumes
|
// created const DrmRootCertificate* if successful. The caller assumes
|
||||||
// ownership of the new DrmRootCertificate. This method returns
|
// ownership of the new DrmRootCertificate. This method returns
|
||||||
// util::Status::OK on success, or appropriate error status otherwise.
|
// Status::OK on success, or appropriate error status otherwise.
|
||||||
static util::Status CreateByTypeString(
|
static Status CreateByTypeString(const std::string& cert_type_string,
|
||||||
const std::string& cert_type_string,
|
std::unique_ptr<DrmRootCertificate>* cert);
|
||||||
std::unique_ptr<DrmRootCertificate>* cert);
|
|
||||||
|
|
||||||
// |certificate| will contgain the DRM certificate upon successful return.
|
// |certificate| will contgain the DRM certificate upon successful return.
|
||||||
// May be null.
|
// May be null.
|
||||||
// Returns util::Status::OK if successful, or an appropriate error code
|
// Returns Status::OK if successful, or an appropriate error code otherwise.
|
||||||
// otherwise.
|
virtual Status VerifyCertificate(const std::string& serialized_certificate,
|
||||||
virtual util::Status VerifyCertificate(
|
SignedDrmCertificate* signed_certificate,
|
||||||
const std::string& serialized_certificate,
|
DrmCertificate* certificate) const;
|
||||||
SignedDrmCertificate* signed_certificate,
|
|
||||||
DrmCertificate* certificate) const;
|
|
||||||
|
|
||||||
// Returns the hex-encoded SHA-256 digest for this certificate.
|
// Returns the hex-encoded SHA-256 digest for this certificate.
|
||||||
virtual std::string GetDigest() const;
|
virtual std::string GetDigest() const;
|
||||||
@@ -86,13 +83,13 @@ class DrmRootCertificate {
|
|||||||
private:
|
private:
|
||||||
friend class DrmRootCertificateTest;
|
friend class DrmRootCertificateTest;
|
||||||
|
|
||||||
static util::Status Create(CertificateType cert_type,
|
static Status Create(CertificateType cert_type,
|
||||||
std::unique_ptr<RsaKeyFactory> key_factory,
|
std::unique_ptr<RsaKeyFactory> key_factory,
|
||||||
std::unique_ptr<DrmRootCertificate>* cert);
|
std::unique_ptr<DrmRootCertificate>* cert);
|
||||||
|
|
||||||
util::Status VerifySignatures(const SignedDrmCertificate& signed_cert,
|
Status VerifySignatures(const SignedDrmCertificate& signed_cert,
|
||||||
const std::string& cert_serial_number,
|
const std::string& cert_serial_number,
|
||||||
bool use_cache) const;
|
bool use_cache) const;
|
||||||
|
|
||||||
CertificateType type_;
|
CertificateType type_;
|
||||||
std::string serialized_certificate_;
|
std::string serialized_certificate_;
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ TEST(DrmRootCertificateCreateTest, TestCertificate) {
|
|||||||
"49f917b1bdfed78002a58e799a58e940"
|
"49f917b1bdfed78002a58e799a58e940"
|
||||||
"1fffaaed9d8d80752782b066757e2c8c");
|
"1fffaaed9d8d80752782b066757e2c8c");
|
||||||
std::unique_ptr<DrmRootCertificate> root_cert;
|
std::unique_ptr<DrmRootCertificate> root_cert;
|
||||||
ASSERT_EQ(util::OkStatus(), DrmRootCertificate::CreateByType(
|
ASSERT_EQ(OkStatus(), DrmRootCertificate::CreateByType(
|
||||||
kCertificateTypeTesting, &root_cert));
|
kCertificateTypeTesting, &root_cert));
|
||||||
ASSERT_TRUE(root_cert != nullptr);
|
ASSERT_TRUE(root_cert != nullptr);
|
||||||
EXPECT_EQ(kTestCertificateHash, root_cert->GetDigest());
|
EXPECT_EQ(kTestCertificateHash, root_cert->GetDigest());
|
||||||
}
|
}
|
||||||
@@ -44,8 +44,8 @@ TEST(DrmRootCertificateCreateTest, DevCertificate) {
|
|||||||
"0e25ee95476a770f30b98ac5ef778b3f"
|
"0e25ee95476a770f30b98ac5ef778b3f"
|
||||||
"137b66c29385b84f547a361b4724b17d");
|
"137b66c29385b84f547a361b4724b17d");
|
||||||
std::unique_ptr<DrmRootCertificate> root_cert;
|
std::unique_ptr<DrmRootCertificate> root_cert;
|
||||||
ASSERT_EQ(util::OkStatus(), DrmRootCertificate::CreateByType(
|
ASSERT_EQ(OkStatus(), DrmRootCertificate::CreateByType(
|
||||||
kCertificateTypeDevelopment, &root_cert));
|
kCertificateTypeDevelopment, &root_cert));
|
||||||
ASSERT_TRUE(root_cert != nullptr);
|
ASSERT_TRUE(root_cert != nullptr);
|
||||||
EXPECT_EQ(kDevelopmentCertificateHash, root_cert->GetDigest());
|
EXPECT_EQ(kDevelopmentCertificateHash, root_cert->GetDigest());
|
||||||
}
|
}
|
||||||
@@ -55,8 +55,8 @@ TEST(DrmRootCertificateCreateTest, ProdCertificate) {
|
|||||||
"d62fdabc9286648a81f7d3bedaf2f5a5"
|
"d62fdabc9286648a81f7d3bedaf2f5a5"
|
||||||
"27bbad39bc38da034ba98a21569adb9b");
|
"27bbad39bc38da034ba98a21569adb9b");
|
||||||
std::unique_ptr<DrmRootCertificate> root_cert;
|
std::unique_ptr<DrmRootCertificate> root_cert;
|
||||||
ASSERT_EQ(util::OkStatus(), DrmRootCertificate::CreateByType(
|
ASSERT_EQ(OkStatus(), DrmRootCertificate::CreateByType(
|
||||||
kCertificateTypeProduction, &root_cert));
|
kCertificateTypeProduction, &root_cert));
|
||||||
ASSERT_TRUE(root_cert != nullptr);
|
ASSERT_TRUE(root_cert != nullptr);
|
||||||
EXPECT_EQ(kProductionCertificateHash, root_cert->GetDigest());
|
EXPECT_EQ(kProductionCertificateHash, root_cert->GetDigest());
|
||||||
}
|
}
|
||||||
@@ -111,8 +111,8 @@ class DrmRootCertificateTest : public testing::Test {
|
|||||||
drm_certificates_[2].set_public_key(
|
drm_certificates_[2].set_public_key(
|
||||||
test_keys_.public_test_key_3_2048_bits());
|
test_keys_.public_test_key_3_2048_bits());
|
||||||
|
|
||||||
ASSERT_EQ(util::OkStatus(), DrmRootCertificate::CreateByType(
|
ASSERT_EQ(OkStatus(), DrmRootCertificate::CreateByType(
|
||||||
kCertificateTypeTesting, &root_cert_));
|
kCertificateTypeTesting, &root_cert_));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateSignedDrmCertificate() {
|
void GenerateSignedDrmCertificate() {
|
||||||
@@ -144,7 +144,7 @@ class DrmRootCertificateTest : public testing::Test {
|
|||||||
|
|
||||||
TEST_F(DrmRootCertificateTest, SuccessNoOutput) {
|
TEST_F(DrmRootCertificateTest, SuccessNoOutput) {
|
||||||
GenerateSignedDrmCertificate();
|
GenerateSignedDrmCertificate();
|
||||||
ASSERT_EQ(util::OkStatus(),
|
ASSERT_EQ(OkStatus(),
|
||||||
root_cert_->VerifyCertificate(
|
root_cert_->VerifyCertificate(
|
||||||
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
||||||
}
|
}
|
||||||
@@ -153,25 +153,25 @@ TEST_F(DrmRootCertificateTest, SuccessWithOutput) {
|
|||||||
GenerateSignedDrmCertificate();
|
GenerateSignedDrmCertificate();
|
||||||
SignedDrmCertificate out_signed_cert;
|
SignedDrmCertificate out_signed_cert;
|
||||||
DrmCertificate out_cert;
|
DrmCertificate out_cert;
|
||||||
ASSERT_EQ(util::OkStatus(), root_cert_->VerifyCertificate(
|
ASSERT_EQ(OkStatus(), root_cert_->VerifyCertificate(
|
||||||
signed_drm_certificate_.SerializeAsString(),
|
signed_drm_certificate_.SerializeAsString(),
|
||||||
&out_signed_cert, &out_cert));
|
&out_signed_cert, &out_cert));
|
||||||
EXPECT_TRUE(
|
EXPECT_TRUE(
|
||||||
MessageDifferencer::Equals(out_signed_cert, signed_drm_certificate_));
|
MessageDifferencer::Equals(out_signed_cert, signed_drm_certificate_));
|
||||||
EXPECT_TRUE(MessageDifferencer::Equals(out_cert, drm_certificates_[2]));
|
EXPECT_TRUE(MessageDifferencer::Equals(out_cert, drm_certificates_[2]));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DrmRootCertificateTest, InvalidSignedDrmCertificate) {
|
TEST_F(DrmRootCertificateTest, InvalidSignedDrmCertificate) {
|
||||||
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
EXPECT_EQ(Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"invalid-signed-drm-certificate"),
|
"invalid-signed-drm-certificate"),
|
||||||
root_cert_->VerifyCertificate("pure garbage", nullptr, nullptr));
|
root_cert_->VerifyCertificate("pure garbage", nullptr, nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DrmRootCertificateTest, InvalidSignerCertificate) {
|
TEST_F(DrmRootCertificateTest, InvalidSignerCertificate) {
|
||||||
GenerateSignedDrmCertificate();
|
GenerateSignedDrmCertificate();
|
||||||
signed_drm_certificate_.mutable_signer()->set_drm_certificate("more garbage");
|
signed_drm_certificate_.mutable_signer()->set_drm_certificate("more garbage");
|
||||||
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
EXPECT_EQ(Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"invalid-signer-certificate"),
|
"invalid-signer-certificate"),
|
||||||
root_cert_->VerifyCertificate(
|
root_cert_->VerifyCertificate(
|
||||||
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
||||||
}
|
}
|
||||||
@@ -179,86 +179,84 @@ TEST_F(DrmRootCertificateTest, InvalidSignerCertificate) {
|
|||||||
TEST_F(DrmRootCertificateTest, MissingDrmCertificate) {
|
TEST_F(DrmRootCertificateTest, MissingDrmCertificate) {
|
||||||
GenerateSignedDrmCertificate();
|
GenerateSignedDrmCertificate();
|
||||||
signed_drm_certificate_.clear_drm_certificate();
|
signed_drm_certificate_.clear_drm_certificate();
|
||||||
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
EXPECT_EQ(
|
||||||
"invalid-drm-certificate"),
|
Status(error_space, INVALID_DRM_CERTIFICATE, "invalid-drm-certificate"),
|
||||||
root_cert_->VerifyCertificate(
|
root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(),
|
||||||
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
nullptr, nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DrmRootCertificateTest, InvalidDrmCertificate) {
|
TEST_F(DrmRootCertificateTest, InvalidDrmCertificate) {
|
||||||
GenerateSignedDrmCertificate();
|
GenerateSignedDrmCertificate();
|
||||||
signed_drm_certificate_.set_drm_certificate("junk");
|
signed_drm_certificate_.set_drm_certificate("junk");
|
||||||
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
EXPECT_EQ(
|
||||||
"invalid-drm-certificate"),
|
Status(error_space, INVALID_DRM_CERTIFICATE, "invalid-drm-certificate"),
|
||||||
root_cert_->VerifyCertificate(
|
root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(),
|
||||||
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
nullptr, nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DrmRootCertificateTest, InvalidPublicKey) {
|
TEST_F(DrmRootCertificateTest, InvalidPublicKey) {
|
||||||
drm_certificates_[0].set_public_key("rubbish");
|
drm_certificates_[0].set_public_key("rubbish");
|
||||||
GenerateSignedDrmCertificate();
|
GenerateSignedDrmCertificate();
|
||||||
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
EXPECT_EQ(
|
||||||
"invalid-signer-public-key"),
|
Status(error_space, INVALID_DRM_CERTIFICATE, "invalid-signer-public-key"),
|
||||||
root_cert_->VerifyCertificate(
|
root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(),
|
||||||
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
nullptr, nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DrmRootCertificateTest, MissingPublicKey) {
|
TEST_F(DrmRootCertificateTest, MissingPublicKey) {
|
||||||
drm_certificates_[2].clear_public_key();
|
drm_certificates_[2].clear_public_key();
|
||||||
GenerateSignedDrmCertificate();
|
GenerateSignedDrmCertificate();
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(Status(error_space, INVALID_DRM_CERTIFICATE, "missing-public-key"),
|
||||||
util::Status(error_space, INVALID_DRM_CERTIFICATE, "missing-public-key"),
|
root_cert_->VerifyCertificate(
|
||||||
root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(),
|
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
||||||
nullptr, nullptr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DrmRootCertificateTest, MissingCreationTime) {
|
TEST_F(DrmRootCertificateTest, MissingCreationTime) {
|
||||||
drm_certificates_[2].clear_creation_time_seconds();
|
drm_certificates_[2].clear_creation_time_seconds();
|
||||||
GenerateSignedDrmCertificate();
|
GenerateSignedDrmCertificate();
|
||||||
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
EXPECT_EQ(
|
||||||
"missing-creation-time"),
|
Status(error_space, INVALID_DRM_CERTIFICATE, "missing-creation-time"),
|
||||||
root_cert_->VerifyCertificate(
|
root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(),
|
||||||
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
nullptr, nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DrmRootCertificateTest, MissingSerialNumber) {
|
TEST_F(DrmRootCertificateTest, MissingSerialNumber) {
|
||||||
drm_certificates_[2].set_serial_number("");
|
drm_certificates_[2].set_serial_number("");
|
||||||
GenerateSignedDrmCertificate();
|
GenerateSignedDrmCertificate();
|
||||||
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
EXPECT_EQ(
|
||||||
"missing-serial-number"),
|
Status(error_space, INVALID_DRM_CERTIFICATE, "missing-serial-number"),
|
||||||
root_cert_->VerifyCertificate(
|
root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(),
|
||||||
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
nullptr, nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DrmRootCertificateTest, InvalidSignatureWithNoCache) {
|
TEST_F(DrmRootCertificateTest, InvalidSignatureWithNoCache) {
|
||||||
GenerateSignedDrmCertificate();
|
GenerateSignedDrmCertificate();
|
||||||
signed_drm_certificate_.mutable_signer()->set_signature(
|
signed_drm_certificate_.mutable_signer()->set_signature(
|
||||||
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
|
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
|
||||||
EXPECT_EQ(util::Status(error_space, INVALID_SIGNATURE,
|
EXPECT_EQ(
|
||||||
"cache-miss-invalid-signature"),
|
Status(error_space, INVALID_SIGNATURE, "cache-miss-invalid-signature"),
|
||||||
root_cert_->VerifyCertificate(
|
root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(),
|
||||||
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
nullptr, nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DrmRootCertificateTest, InvalidSignatureWithCache) {
|
TEST_F(DrmRootCertificateTest, InvalidSignatureWithCache) {
|
||||||
GenerateSignedDrmCertificate();
|
GenerateSignedDrmCertificate();
|
||||||
// Verify and cache.
|
// Verify and cache.
|
||||||
ASSERT_EQ(util::OkStatus(),
|
ASSERT_EQ(OkStatus(),
|
||||||
root_cert_->VerifyCertificate(
|
root_cert_->VerifyCertificate(
|
||||||
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
||||||
|
|
||||||
// Verify success using cache.
|
// Verify success using cache.
|
||||||
ASSERT_EQ(util::OkStatus(),
|
ASSERT_EQ(OkStatus(),
|
||||||
root_cert_->VerifyCertificate(
|
root_cert_->VerifyCertificate(
|
||||||
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
||||||
|
|
||||||
// Verify failure using cache.
|
// Verify failure using cache.
|
||||||
signed_drm_certificate_.mutable_signer()->set_signature(
|
signed_drm_certificate_.mutable_signer()->set_signature(
|
||||||
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
|
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(Status(error_space, INVALID_SIGNATURE, "cached-signature-mismatch"),
|
||||||
util::Status(error_space, INVALID_SIGNATURE, "cached-signature-mismatch"),
|
root_cert_->VerifyCertificate(
|
||||||
root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(),
|
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
||||||
nullptr, nullptr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
|
|||||||
@@ -107,41 +107,41 @@ DrmServiceCertificateMap* DrmServiceCertificateMap::GetInstance() {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
util::Status DrmServiceCertificate::AddDrmServiceCertificate(
|
Status DrmServiceCertificate::AddDrmServiceCertificate(
|
||||||
const DrmRootCertificate* root_cert, 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) {
|
||||||
DrmCertificate drm_cert;
|
DrmCertificate drm_cert;
|
||||||
util::Status status =
|
Status status =
|
||||||
root_cert->VerifyCertificate(service_certificate, nullptr, &drm_cert);
|
root_drm_cert->VerifyCertificate(service_certificate, nullptr, &drm_cert);
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (drm_cert.type() != DrmCertificate::SERVICE) {
|
if (drm_cert.type() != DrmCertificate::SERVICE) {
|
||||||
return util::Status(error_space, INVALID_SERVICE_CERTIFICATE,
|
return Status(error_space, INVALID_SERVICE_CERTIFICATE,
|
||||||
"not-service-certificate");
|
"not-service-certificate");
|
||||||
}
|
}
|
||||||
if (drm_cert.provider_id().empty()) {
|
if (drm_cert.provider_id().empty()) {
|
||||||
return util::Status(error_space, INVALID_SERVICE_CERTIFICATE,
|
return Status(error_space, INVALID_SERVICE_CERTIFICATE,
|
||||||
"missing-certificate-service-id");
|
"missing-certificate-service-id");
|
||||||
}
|
}
|
||||||
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) {
|
||||||
return util::Status(error_space, INVALID_SERVICE_CERTIFICATE,
|
return Status(error_space, INVALID_SERVICE_CERTIFICATE,
|
||||||
"invalid-certificate-public-key");
|
"invalid-certificate-public-key");
|
||||||
}
|
}
|
||||||
std::string pkcs1_key;
|
std::string pkcs1_key;
|
||||||
if (!rsa_util::EncryptedPrivateKeyInfoToRsaPrivateKey(
|
if (!rsa_util::EncryptedPrivateKeyInfoToRsaPrivateKey(
|
||||||
service_private_key, service_private_key_passphrase, &pkcs1_key)) {
|
service_private_key, service_private_key_passphrase, &pkcs1_key)) {
|
||||||
return util::Status(error_space, INVALID_SERVICE_PRIVATE_KEY,
|
return Status(error_space, INVALID_SERVICE_PRIVATE_KEY,
|
||||||
"key-decryption-failed");
|
"key-decryption-failed");
|
||||||
}
|
}
|
||||||
std::unique_ptr<RsaPrivateKey> private_key(RsaPrivateKey::Create(pkcs1_key));
|
std::unique_ptr<RsaPrivateKey> private_key(RsaPrivateKey::Create(pkcs1_key));
|
||||||
if (private_key == nullptr) {
|
if (private_key == nullptr) {
|
||||||
return util::Status(error_space, INVALID_SERVICE_PRIVATE_KEY,
|
return Status(error_space, INVALID_SERVICE_PRIVATE_KEY,
|
||||||
"invalid-private-key");
|
"invalid-private-key");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<DrmServiceCertificate> new_cert(new DrmServiceCertificate(
|
std::unique_ptr<DrmServiceCertificate> new_cert(new DrmServiceCertificate(
|
||||||
@@ -150,7 +150,7 @@ util::Status DrmServiceCertificate::AddDrmServiceCertificate(
|
|||||||
std::move(private_key)));
|
std::move(private_key)));
|
||||||
DrmServiceCertificateMap::GetInstance()->AddCert(std::move(new_cert));
|
DrmServiceCertificateMap::GetInstance()->AddCert(std::move(new_cert));
|
||||||
|
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
const DrmServiceCertificate*
|
const DrmServiceCertificate*
|
||||||
@@ -171,7 +171,7 @@ const DrmServiceCertificate* DrmServiceCertificate::GetDrmServiceCertificate(
|
|||||||
return DrmServiceCertificateMap::GetInstance()->GetCert(serial_number);
|
return DrmServiceCertificateMap::GetInstance()->GetCert(serial_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status DrmServiceCertificate::SetDefaultDrmServiceCertificate(
|
Status DrmServiceCertificate::SetDefaultDrmServiceCertificate(
|
||||||
const DrmRootCertificate* root_drm_cert, 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) {
|
||||||
@@ -181,36 +181,36 @@ util::Status DrmServiceCertificate::SetDefaultDrmServiceCertificate(
|
|||||||
service_private_key_passphrase);
|
service_private_key_passphrase);
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status DrmServiceCertificate::DecryptClientIdentification(
|
Status DrmServiceCertificate::DecryptClientIdentification(
|
||||||
const EncryptedClientIdentification& encrypted_client_id,
|
const EncryptedClientIdentification& encrypted_client_id,
|
||||||
ClientIdentification* client_id) {
|
ClientIdentification* client_id) {
|
||||||
DCHECK(client_id);
|
DCHECK(client_id);
|
||||||
if (encrypted_client_id.service_certificate_serial_number().empty()) {
|
if (encrypted_client_id.service_certificate_serial_number().empty()) {
|
||||||
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
|
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
|
||||||
"missing-service-certificate-serial-number");
|
"missing-service-certificate-serial-number");
|
||||||
}
|
}
|
||||||
if (encrypted_client_id.provider_id().empty()) {
|
if (encrypted_client_id.provider_id().empty()) {
|
||||||
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
|
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
|
||||||
"missing-service-id");
|
"missing-service-id");
|
||||||
}
|
}
|
||||||
if (encrypted_client_id.encrypted_client_id().empty()) {
|
if (encrypted_client_id.encrypted_client_id().empty()) {
|
||||||
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
|
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
|
||||||
"missing-encrypted-client-id");
|
"missing-encrypted-client-id");
|
||||||
}
|
}
|
||||||
if (encrypted_client_id.encrypted_client_id_iv().empty()) {
|
if (encrypted_client_id.encrypted_client_id_iv().empty()) {
|
||||||
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
|
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
|
||||||
"missing-encrypted-client-id-iv");
|
"missing-encrypted-client-id-iv");
|
||||||
}
|
}
|
||||||
if (encrypted_client_id.encrypted_privacy_key().empty()) {
|
if (encrypted_client_id.encrypted_privacy_key().empty()) {
|
||||||
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
|
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
|
||||||
"missing-encrypted-privacy-key");
|
"missing-encrypted-privacy-key");
|
||||||
}
|
}
|
||||||
std::string privacy_key;
|
std::string privacy_key;
|
||||||
std::string provider_id;
|
std::string provider_id;
|
||||||
const DrmServiceCertificate* cert = GetDrmServiceCertificate(
|
const DrmServiceCertificate* cert = GetDrmServiceCertificate(
|
||||||
encrypted_client_id.service_certificate_serial_number());
|
encrypted_client_id.service_certificate_serial_number());
|
||||||
if (!cert) {
|
if (!cert) {
|
||||||
return util::Status(
|
return Status(
|
||||||
error_space, SERVICE_CERTIFICATE_NOT_FOUND,
|
error_space, SERVICE_CERTIFICATE_NOT_FOUND,
|
||||||
"service-certificate-not-found (SN " +
|
"service-certificate-not-found (SN " +
|
||||||
absl::BytesToHexString(
|
absl::BytesToHexString(
|
||||||
@@ -219,56 +219,56 @@ util::Status DrmServiceCertificate::DecryptClientIdentification(
|
|||||||
}
|
}
|
||||||
if (!cert->private_key()->Decrypt(encrypted_client_id.encrypted_privacy_key(),
|
if (!cert->private_key()->Decrypt(encrypted_client_id.encrypted_privacy_key(),
|
||||||
&privacy_key)) {
|
&privacy_key)) {
|
||||||
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
|
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
|
||||||
"privacy-key-decryption-failed");
|
"privacy-key-decryption-failed");
|
||||||
}
|
}
|
||||||
if (cert->provider_id() != encrypted_client_id.provider_id()) {
|
if (cert->provider_id() != encrypted_client_id.provider_id()) {
|
||||||
return util::Status(error_space, SERVICE_CERTIFICATE_NOT_FOUND,
|
return Status(error_space, SERVICE_CERTIFICATE_NOT_FOUND,
|
||||||
std::string("provider-id-mismatch (") + cert->provider_id() +
|
std::string("provider-id-mismatch (") + cert->provider_id() +
|
||||||
" / " + encrypted_client_id.provider_id() + ")");
|
" / " + encrypted_client_id.provider_id() + ")");
|
||||||
}
|
}
|
||||||
std::string serialized_client_id(crypto_util::DecryptAesCbc(
|
std::string serialized_client_id(crypto_util::DecryptAesCbc(
|
||||||
privacy_key, encrypted_client_id.encrypted_client_id_iv(),
|
privacy_key, encrypted_client_id.encrypted_client_id_iv(),
|
||||||
encrypted_client_id.encrypted_client_id()));
|
encrypted_client_id.encrypted_client_id()));
|
||||||
if (serialized_client_id.empty()) {
|
if (serialized_client_id.empty()) {
|
||||||
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
|
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
|
||||||
"client-id-decryption-failed");
|
"client-id-decryption-failed");
|
||||||
}
|
}
|
||||||
if (!client_id->ParseFromString(serialized_client_id)) {
|
if (!client_id->ParseFromString(serialized_client_id)) {
|
||||||
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
|
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
|
||||||
"client-id-parse-failed");
|
"client-id-parse-failed");
|
||||||
}
|
}
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrmServiceCertificate::ResetServiceCertificates() {
|
void DrmServiceCertificate::ResetServiceCertificates() {
|
||||||
DrmServiceCertificateMap::GetInstance()->Reset();
|
DrmServiceCertificateMap::GetInstance()->Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status DrmServiceCertificate::ValidateDrmServiceCertificate() {
|
Status DrmServiceCertificate::ValidateDrmServiceCertificate() {
|
||||||
const DrmServiceCertificate* service_certificate =
|
const DrmServiceCertificate* service_certificate =
|
||||||
GetDefaultDrmServiceCertificate();
|
GetDefaultDrmServiceCertificate();
|
||||||
if (!service_certificate) {
|
if (!service_certificate) {
|
||||||
return util::Status(error_space, SERVICE_CERTIFICATE_NOT_FOUND,
|
return Status(error_space, SERVICE_CERTIFICATE_NOT_FOUND,
|
||||||
"drm service certificate is not found.");
|
"drm service certificate is not found.");
|
||||||
}
|
}
|
||||||
SignedDrmCertificate signed_cert;
|
SignedDrmCertificate signed_cert;
|
||||||
if (!signed_cert.ParseFromString(service_certificate->certificate())) {
|
if (!signed_cert.ParseFromString(service_certificate->certificate())) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"signed drm service certificate is failed to parse.");
|
"signed drm service certificate is failed to parse.");
|
||||||
}
|
}
|
||||||
DrmCertificate drm_cert;
|
DrmCertificate drm_cert;
|
||||||
if (!drm_cert.ParseFromString(signed_cert.drm_certificate())) {
|
if (!drm_cert.ParseFromString(signed_cert.drm_certificate())) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"Drm service certificate is failed to parse.");
|
"Drm service certificate is failed to parse.");
|
||||||
}
|
}
|
||||||
if (!drm_cert.has_creation_time_seconds()) {
|
if (!drm_cert.has_creation_time_seconds()) {
|
||||||
return util::Status(error_space, INVALID_SERVICE_CERTIFICATE,
|
return Status(error_space, INVALID_SERVICE_CERTIFICATE,
|
||||||
"missing certificate creation time");
|
"missing certificate creation time");
|
||||||
}
|
}
|
||||||
// TODO(user): Check creation_time_seconds field in DrmCertificate and also
|
// TODO(user): Check creation_time_seconds field in DrmCertificate and also
|
||||||
// export the absl/time dependency through moe.
|
// export the absl/time dependency through moe.
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
DrmServiceCertificate::DrmServiceCertificate(
|
DrmServiceCertificate::DrmServiceCertificate(
|
||||||
|
|||||||
@@ -18,9 +18,9 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include "base/macros.h"
|
#include "base/macros.h"
|
||||||
#include "util/status.h"
|
|
||||||
#include "common/certificate_type.h"
|
#include "common/certificate_type.h"
|
||||||
#include "common/rsa_key.h"
|
#include "common/rsa_key.h"
|
||||||
|
#include "common/status.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
class RequestInspectorTest;
|
class RequestInspectorTest;
|
||||||
@@ -48,7 +48,7 @@ class DrmServiceCertificate {
|
|||||||
// If the default service certificate is not set, this certificate will be
|
// If the default service certificate is not set, this certificate will be
|
||||||
// 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 Status AddDrmServiceCertificate(
|
||||||
const DrmRootCertificate* root_drm_cert,
|
const DrmRootCertificate* root_drm_cert,
|
||||||
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);
|
||||||
@@ -56,7 +56,7 @@ class DrmServiceCertificate {
|
|||||||
// 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 Status SetDefaultDrmServiceCertificate(
|
||||||
const DrmRootCertificate* root_drm_cert,
|
const DrmRootCertificate* root_drm_cert,
|
||||||
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);
|
||||||
@@ -79,7 +79,7 @@ class DrmServiceCertificate {
|
|||||||
// certificate which was used to encrypt the information. |client_id| must
|
// certificate which was used to encrypt the information. |client_id| must
|
||||||
// not be NULL. Returns status::OK if successful, or an appropriate error
|
// not be NULL. Returns status::OK if successful, or an appropriate error
|
||||||
// otherwise. This method is thread-safe.
|
// otherwise. This method is thread-safe.
|
||||||
static util::Status DecryptClientIdentification(
|
static Status DecryptClientIdentification(
|
||||||
const EncryptedClientIdentification& encrypted_client_id,
|
const EncryptedClientIdentification& encrypted_client_id,
|
||||||
ClientIdentification* client_id);
|
ClientIdentification* client_id);
|
||||||
|
|
||||||
@@ -93,18 +93,18 @@ class DrmServiceCertificate {
|
|||||||
// status::OK if successful, or in case of error, contact
|
// status::OK if successful, or in case of error, contact
|
||||||
// widevine-tam@google.com to get the next valid service certificate renewed
|
// widevine-tam@google.com to get the next valid service certificate renewed
|
||||||
// via get deviceCertificate StatusList.
|
// via get deviceCertificate StatusList.
|
||||||
static util::Status ValidateDrmServiceCertificate();
|
static Status ValidateDrmServiceCertificate();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class DrmServiceCertificateTest;
|
friend class DrmServiceCertificateTest;
|
||||||
friend class widevine::RequestInspectorTest;
|
friend class widevine::RequestInspectorTest;
|
||||||
|
|
||||||
static util::Status AddDrmServiceCertificate(
|
static Status AddDrmServiceCertificate(
|
||||||
const std::string& root_public_key, const std::string& service_certificate,
|
const std::string& root_public_key, 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);
|
||||||
|
|
||||||
static util::Status SetDefaultDrmServiceCertificate(
|
static Status SetDefaultDrmServiceCertificate(
|
||||||
const std::string& root_public_key, const std::string& service_certificate,
|
const std::string& root_public_key, 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);
|
||||||
|
|||||||
@@ -69,9 +69,9 @@ class DrmServiceCertificateTest : public ::testing::Test {
|
|||||||
return serialized_cert;
|
return serialized_cert;
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status SetDefaultDrmServiceCertificate(const std::string& serial_number,
|
Status SetDefaultDrmServiceCertificate(const std::string& serial_number,
|
||||||
const std::string& provider_id,
|
const std::string& provider_id,
|
||||||
uint32_t creation_time_seconds) {
|
uint32_t creation_time_seconds) {
|
||||||
std::string signed_cert(GenerateDrmServiceCertificate(
|
std::string signed_cert(GenerateDrmServiceCertificate(
|
||||||
serial_number, provider_id, creation_time_seconds,
|
serial_number, provider_id, creation_time_seconds,
|
||||||
test_keys_.public_test_key_2_2048_bits()));
|
test_keys_.public_test_key_2_2048_bits()));
|
||||||
@@ -79,15 +79,15 @@ class DrmServiceCertificateTest : public ::testing::Test {
|
|||||||
if (!rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo(
|
if (!rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo(
|
||||||
test_keys_.private_test_key_2_2048_bits(), kPassphrase,
|
test_keys_.private_test_key_2_2048_bits(), kPassphrase,
|
||||||
&encrypted_private_key)) {
|
&encrypted_private_key)) {
|
||||||
return util::Status(util::error::INTERNAL, "");
|
return Status(error::INTERNAL, "");
|
||||||
}
|
}
|
||||||
return DrmServiceCertificate::SetDefaultDrmServiceCertificate(
|
return DrmServiceCertificate::SetDefaultDrmServiceCertificate(
|
||||||
root_cert_.get(), signed_cert, encrypted_private_key, kPassphrase);
|
root_cert_.get(), signed_cert, encrypted_private_key, kPassphrase);
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status AddDrmServiceCertificate(const std::string& serial_number,
|
Status AddDrmServiceCertificate(const std::string& serial_number,
|
||||||
const std::string& provider_id,
|
const std::string& provider_id,
|
||||||
uint32_t creation_time_seconds) {
|
uint32_t creation_time_seconds) {
|
||||||
std::string signed_cert(GenerateDrmServiceCertificate(
|
std::string signed_cert(GenerateDrmServiceCertificate(
|
||||||
serial_number, provider_id, creation_time_seconds,
|
serial_number, provider_id, creation_time_seconds,
|
||||||
test_keys_.public_test_key_2_2048_bits()));
|
test_keys_.public_test_key_2_2048_bits()));
|
||||||
@@ -95,7 +95,7 @@ class DrmServiceCertificateTest : public ::testing::Test {
|
|||||||
if (!rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo(
|
if (!rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo(
|
||||||
test_keys_.private_test_key_2_2048_bits(), kPassphrase,
|
test_keys_.private_test_key_2_2048_bits(), kPassphrase,
|
||||||
&encrypted_private_key)) {
|
&encrypted_private_key)) {
|
||||||
return util::Status(util::error::INTERNAL, "");
|
return Status(error::INTERNAL, "");
|
||||||
}
|
}
|
||||||
return DrmServiceCertificate::AddDrmServiceCertificate(
|
return DrmServiceCertificate::AddDrmServiceCertificate(
|
||||||
root_cert_.get(), signed_cert, encrypted_private_key, kPassphrase);
|
root_cert_.get(), signed_cert, encrypted_private_key, kPassphrase);
|
||||||
@@ -140,9 +140,8 @@ TEST_F(DrmServiceCertificateTest, BasicClientIdDecrypt) {
|
|||||||
test_keys_.public_test_key_2_2048_bits(),
|
test_keys_.public_test_key_2_2048_bits(),
|
||||||
&encrypted_client_id);
|
&encrypted_client_id);
|
||||||
ClientIdentification decrypted_client_id;
|
ClientIdentification decrypted_client_id;
|
||||||
EXPECT_EQ(util::OkStatus(),
|
EXPECT_EQ(OkStatus(), DrmServiceCertificate::DecryptClientIdentification(
|
||||||
DrmServiceCertificate::DecryptClientIdentification(
|
encrypted_client_id, &decrypted_client_id));
|
||||||
encrypted_client_id, &decrypted_client_id));
|
|
||||||
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_,
|
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_,
|
||||||
decrypted_client_id));
|
decrypted_client_id));
|
||||||
}
|
}
|
||||||
@@ -220,27 +219,24 @@ TEST_F(DrmServiceCertificateTest, MultipleCertsPerService) {
|
|||||||
test_keys_.public_test_key_2_2048_bits(),
|
test_keys_.public_test_key_2_2048_bits(),
|
||||||
&encrypted_client_id);
|
&encrypted_client_id);
|
||||||
ClientIdentification decrypted_client_id;
|
ClientIdentification decrypted_client_id;
|
||||||
EXPECT_EQ(util::OkStatus(),
|
EXPECT_EQ(OkStatus(), DrmServiceCertificate::DecryptClientIdentification(
|
||||||
DrmServiceCertificate::DecryptClientIdentification(
|
encrypted_client_id, &decrypted_client_id));
|
||||||
encrypted_client_id, &decrypted_client_id));
|
|
||||||
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_,
|
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_,
|
||||||
decrypted_client_id));
|
decrypted_client_id));
|
||||||
|
|
||||||
EncryptClientIdentification(serial_number2, provider_id,
|
EncryptClientIdentification(serial_number2, provider_id,
|
||||||
test_keys_.public_test_key_2_2048_bits(),
|
test_keys_.public_test_key_2_2048_bits(),
|
||||||
&encrypted_client_id);
|
&encrypted_client_id);
|
||||||
EXPECT_EQ(util::OkStatus(),
|
EXPECT_EQ(OkStatus(), DrmServiceCertificate::DecryptClientIdentification(
|
||||||
DrmServiceCertificate::DecryptClientIdentification(
|
encrypted_client_id, &decrypted_client_id));
|
||||||
encrypted_client_id, &decrypted_client_id));
|
|
||||||
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_,
|
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_,
|
||||||
decrypted_client_id));
|
decrypted_client_id));
|
||||||
|
|
||||||
EncryptClientIdentification(serial_number3, provider_id,
|
EncryptClientIdentification(serial_number3, provider_id,
|
||||||
test_keys_.public_test_key_2_2048_bits(),
|
test_keys_.public_test_key_2_2048_bits(),
|
||||||
&encrypted_client_id);
|
&encrypted_client_id);
|
||||||
EXPECT_EQ(util::OkStatus(),
|
EXPECT_EQ(OkStatus(), DrmServiceCertificate::DecryptClientIdentification(
|
||||||
DrmServiceCertificate::DecryptClientIdentification(
|
encrypted_client_id, &decrypted_client_id));
|
||||||
encrypted_client_id, &decrypted_client_id));
|
|
||||||
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_,
|
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_,
|
||||||
decrypted_client_id));
|
decrypted_client_id));
|
||||||
|
|
||||||
@@ -292,9 +288,8 @@ TEST_F(DrmServiceCertificateTest, InvalidEncryptedClientIdentification) {
|
|||||||
test_keys_.public_test_key_2_2048_bits(),
|
test_keys_.public_test_key_2_2048_bits(),
|
||||||
&encrypted_client_id);
|
&encrypted_client_id);
|
||||||
ClientIdentification decrypted_client_id;
|
ClientIdentification decrypted_client_id;
|
||||||
ASSERT_EQ(util::OkStatus(),
|
ASSERT_EQ(OkStatus(), DrmServiceCertificate::DecryptClientIdentification(
|
||||||
DrmServiceCertificate::DecryptClientIdentification(
|
encrypted_client_id, &decrypted_client_id));
|
||||||
encrypted_client_id, &decrypted_client_id));
|
|
||||||
ASSERT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_,
|
ASSERT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_,
|
||||||
decrypted_client_id));
|
decrypted_client_id));
|
||||||
|
|
||||||
@@ -310,9 +305,8 @@ TEST_F(DrmServiceCertificateTest, InvalidEncryptedClientIdentification) {
|
|||||||
|
|
||||||
invalid = encrypted_client_id;
|
invalid = encrypted_client_id;
|
||||||
++(*invalid.mutable_encrypted_client_id_iv())[4];
|
++(*invalid.mutable_encrypted_client_id_iv())[4];
|
||||||
EXPECT_NE(util::OkStatus(),
|
EXPECT_NE(OkStatus(), DrmServiceCertificate::DecryptClientIdentification(
|
||||||
DrmServiceCertificate::DecryptClientIdentification(
|
invalid, &decrypted_client_id));
|
||||||
invalid, &decrypted_client_id));
|
|
||||||
|
|
||||||
invalid.clear_encrypted_client_id_iv();
|
invalid.clear_encrypted_client_id_iv();
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
@@ -324,9 +318,8 @@ TEST_F(DrmServiceCertificateTest, InvalidEncryptedClientIdentification) {
|
|||||||
|
|
||||||
invalid = encrypted_client_id;
|
invalid = encrypted_client_id;
|
||||||
++(*invalid.mutable_encrypted_client_id())[0];
|
++(*invalid.mutable_encrypted_client_id())[0];
|
||||||
EXPECT_NE(util::OkStatus(),
|
EXPECT_NE(OkStatus(), DrmServiceCertificate::DecryptClientIdentification(
|
||||||
DrmServiceCertificate::DecryptClientIdentification(
|
invalid, &decrypted_client_id));
|
||||||
invalid, &decrypted_client_id));
|
|
||||||
|
|
||||||
invalid.clear_encrypted_client_id();
|
invalid.clear_encrypted_client_id();
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
@@ -349,9 +342,8 @@ TEST_F(DrmServiceCertificateTest, PrivateKeyDecryptError) {
|
|||||||
test_keys_.public_test_key_2_2048_bits(),
|
test_keys_.public_test_key_2_2048_bits(),
|
||||||
&encrypted_client_id);
|
&encrypted_client_id);
|
||||||
ClientIdentification decrypted_client_id;
|
ClientIdentification decrypted_client_id;
|
||||||
ASSERT_EQ(util::OkStatus(),
|
ASSERT_EQ(OkStatus(), DrmServiceCertificate::DecryptClientIdentification(
|
||||||
DrmServiceCertificate::DecryptClientIdentification(
|
encrypted_client_id, &decrypted_client_id));
|
||||||
encrypted_client_id, &decrypted_client_id));
|
|
||||||
ASSERT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_,
|
ASSERT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_,
|
||||||
decrypted_client_id));
|
decrypted_client_id));
|
||||||
|
|
||||||
|
|||||||
@@ -113,99 +113,99 @@ void RemoteAttestationVerifier::EnableTestDrmCertificates(bool enable) {
|
|||||||
ca_.reset();
|
ca_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status RemoteAttestationVerifier::VerifyRemoteAttestation(
|
Status RemoteAttestationVerifier::VerifyRemoteAttestation(
|
||||||
const std::string& message, const RemoteAttestation& remote_attestation,
|
const std::string& message, const RemoteAttestation& remote_attestation,
|
||||||
std::string* remote_attestation_cert_sn) {
|
std::string* remote_attestation_cert_sn) {
|
||||||
DCHECK(remote_attestation_cert_sn);
|
DCHECK(remote_attestation_cert_sn);
|
||||||
|
|
||||||
// Sanity check RemoteAttestation.
|
// Sanity check RemoteAttestation.
|
||||||
if (!remote_attestation.has_certificate()) {
|
if (!remote_attestation.has_certificate()) {
|
||||||
return (util::Status(error_space, INVALID_MESSAGE,
|
return (Status(error_space, INVALID_MESSAGE,
|
||||||
"remote-attestation-certificate-missing"));
|
"remote-attestation-certificate-missing"));
|
||||||
}
|
}
|
||||||
if (!remote_attestation.has_salt()) {
|
if (!remote_attestation.has_salt()) {
|
||||||
return (util::Status(error_space, INVALID_MESSAGE,
|
return (Status(error_space, INVALID_MESSAGE,
|
||||||
"remote-attestation-salt-missing"));
|
"remote-attestation-salt-missing"));
|
||||||
}
|
}
|
||||||
if (!remote_attestation.has_signature()) {
|
if (!remote_attestation.has_signature()) {
|
||||||
return (util::Status(error_space, INVALID_MESSAGE,
|
return (Status(error_space, INVALID_MESSAGE,
|
||||||
"remote-attestation-signature-missing"));
|
"remote-attestation-signature-missing"));
|
||||||
}
|
}
|
||||||
// Decrypt ClientIdentification containing remote attestation certificate.
|
// Decrypt ClientIdentification containing remote attestation certificate.
|
||||||
// A service cert would be looked up first, then that cert will be used
|
// A service cert would be looked up first, then that cert will be used
|
||||||
// to decrypt the ClientIdentification.
|
// to decrypt the ClientIdentification.
|
||||||
ClientIdentification client_id;
|
ClientIdentification client_id;
|
||||||
util::Status status = DrmServiceCertificate::DecryptClientIdentification(
|
Status status = DrmServiceCertificate::DecryptClientIdentification(
|
||||||
remote_attestation.certificate(), &client_id);
|
remote_attestation.certificate(), &client_id);
|
||||||
if (!status.ok()) return status;
|
if (!status.ok()) return status;
|
||||||
|
|
||||||
if (client_id.type() !=
|
if (client_id.type() !=
|
||||||
ClientIdentification::REMOTE_ATTESTATION_CERTIFICATE) {
|
ClientIdentification::REMOTE_ATTESTATION_CERTIFICATE) {
|
||||||
return (util::Status(error_space, INVALID_MESSAGE,
|
return (Status(error_space, INVALID_MESSAGE,
|
||||||
std::string("remote-attestation-invalid-client-id-type (") +
|
std::string("remote-attestation-invalid-client-id-type (") +
|
||||||
absl::StrCat(client_id.type()) + ")"));
|
absl::StrCat(client_id.type()) + ")"));
|
||||||
}
|
}
|
||||||
return VerifyRemoteAttestation(message, remote_attestation, client_id,
|
return VerifyRemoteAttestation(message, remote_attestation, client_id,
|
||||||
remote_attestation_cert_sn);
|
remote_attestation_cert_sn);
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status RemoteAttestationVerifier::VerifyRemoteAttestation(
|
Status RemoteAttestationVerifier::VerifyRemoteAttestation(
|
||||||
const std::string& message, const RemoteAttestation& remote_attestation,
|
const std::string& message, const RemoteAttestation& remote_attestation,
|
||||||
const std::string& privacy_key) {
|
const std::string& privacy_key) {
|
||||||
// Sanity check RemoteAttestation.
|
// Sanity check RemoteAttestation.
|
||||||
if (!remote_attestation.has_certificate()) {
|
if (!remote_attestation.has_certificate()) {
|
||||||
return (util::Status(error_space, INVALID_MESSAGE,
|
return (Status(error_space, INVALID_MESSAGE,
|
||||||
"remote-attestation-certificate-missing"));
|
"remote-attestation-certificate-missing"));
|
||||||
}
|
}
|
||||||
if (!remote_attestation.has_salt()) {
|
if (!remote_attestation.has_salt()) {
|
||||||
return (util::Status(error_space, INVALID_MESSAGE,
|
return (Status(error_space, INVALID_MESSAGE,
|
||||||
"remote-attestation-salt-missing"));
|
"remote-attestation-salt-missing"));
|
||||||
}
|
}
|
||||||
if (!remote_attestation.has_signature()) {
|
if (!remote_attestation.has_signature()) {
|
||||||
return (util::Status(error_space, INVALID_MESSAGE,
|
return (Status(error_space, INVALID_MESSAGE,
|
||||||
"remote-attestation-signature-missing"));
|
"remote-attestation-signature-missing"));
|
||||||
}
|
}
|
||||||
// Decrypt ClientIdentification containing remote attestation certificate,
|
// Decrypt ClientIdentification containing remote attestation certificate,
|
||||||
// directly using an explicitly provided key |privacy_key|.
|
// directly using an explicitly provided key |privacy_key|.
|
||||||
ClientIdentification client_id;
|
ClientIdentification client_id;
|
||||||
util::Status status = DecryptEncryptedClientIdentification(
|
Status status = DecryptEncryptedClientIdentification(
|
||||||
remote_attestation.certificate(), privacy_key, &client_id);
|
remote_attestation.certificate(), privacy_key, &client_id);
|
||||||
if (!status.ok()) return status;
|
if (!status.ok()) return status;
|
||||||
|
|
||||||
if (client_id.type() !=
|
if (client_id.type() !=
|
||||||
ClientIdentification::REMOTE_ATTESTATION_CERTIFICATE) {
|
ClientIdentification::REMOTE_ATTESTATION_CERTIFICATE) {
|
||||||
return (util::Status(error_space, INVALID_MESSAGE,
|
return (Status(error_space, INVALID_MESSAGE,
|
||||||
std::string("remote-attestation-invalid-client-id-type (") +
|
std::string("remote-attestation-invalid-client-id-type (") +
|
||||||
absl::StrCat(client_id.type()) + ")"));
|
absl::StrCat(client_id.type()) + ")"));
|
||||||
}
|
}
|
||||||
std::string remote_attestation_cert_sn;
|
std::string remote_attestation_cert_sn;
|
||||||
return VerifyRemoteAttestation(message, remote_attestation, client_id,
|
return VerifyRemoteAttestation(message, remote_attestation, client_id,
|
||||||
&remote_attestation_cert_sn);
|
&remote_attestation_cert_sn);
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status RemoteAttestationVerifier::VerifyRemoteAttestation(
|
Status RemoteAttestationVerifier::VerifyRemoteAttestation(
|
||||||
const std::string& message, const RemoteAttestation& remote_attestation,
|
const std::string& message, const RemoteAttestation& remote_attestation,
|
||||||
const ClientIdentification& client_id, std::string* remote_attestation_cert_sn) {
|
const ClientIdentification& client_id, std::string* remote_attestation_cert_sn) {
|
||||||
if (!client_id.has_token()) {
|
if (!client_id.has_token()) {
|
||||||
return (util::Status(error_space, INVALID_MESSAGE,
|
return (Status(error_space, INVALID_MESSAGE,
|
||||||
"remote-attestation-token-missing"));
|
"remote-attestation-token-missing"));
|
||||||
}
|
}
|
||||||
// Load and verify the certificate chain.
|
// Load and verify the certificate chain.
|
||||||
std::unique_ptr<X509CertChain> cert_chain(new X509CertChain);
|
std::unique_ptr<X509CertChain> cert_chain(new X509CertChain);
|
||||||
util::Status status = cert_chain->LoadPem(client_id.token());
|
Status status = cert_chain->LoadPem(client_id.token());
|
||||||
if (!status.ok()) return status;
|
if (!status.ok()) return status;
|
||||||
|
|
||||||
if (cert_chain->GetNumCerts() < 1) {
|
if (cert_chain->GetNumCerts() < 1) {
|
||||||
return (util::Status(error_space, INVALID_MESSAGE,
|
return (Status(error_space, INVALID_MESSAGE,
|
||||||
"remote-attestation-empty-certificate-chain"));
|
"remote-attestation-empty-certificate-chain"));
|
||||||
}
|
}
|
||||||
std::string device_mode_string =
|
std::string device_mode_string =
|
||||||
cert_chain->GetCert(0)->GetSubjectNameField(kDeviceModeFieldName);
|
cert_chain->GetCert(0)->GetSubjectNameField(kDeviceModeFieldName);
|
||||||
if (device_mode_string != kExpectedDeviceMode) {
|
if (device_mode_string != kExpectedDeviceMode) {
|
||||||
return (util::Status(error_space, REMOTE_ATTESTATION_FAILED,
|
return (Status(error_space, REMOTE_ATTESTATION_FAILED,
|
||||||
std::string("remote-attestation-device-not-verified (") +
|
std::string("remote-attestation-device-not-verified (") +
|
||||||
device_mode_string + " / " + kDeviceModeFieldName +
|
device_mode_string + " / " + kDeviceModeFieldName +
|
||||||
")"));
|
")"));
|
||||||
}
|
}
|
||||||
ca_mutex_.ReaderLock();
|
ca_mutex_.ReaderLock();
|
||||||
if (ca_ == NULL) {
|
if (ca_ == NULL) {
|
||||||
@@ -217,10 +217,9 @@ util::Status RemoteAttestationVerifier::VerifyRemoteAttestation(
|
|||||||
status = ca_->VerifyCertChain(*cert_chain);
|
status = ca_->VerifyCertChain(*cert_chain);
|
||||||
ca_mutex_.ReaderUnlock();
|
ca_mutex_.ReaderUnlock();
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
return (util::Status(
|
return (Status(error_space, REMOTE_ATTESTATION_FAILED,
|
||||||
error_space, REMOTE_ATTESTATION_FAILED,
|
std::string("remote-attestation-cert-chain-validation-failed: ") +
|
||||||
std::string("remote-attestation-cert-chain-validation-failed: ") +
|
status.error_message()));
|
||||||
status.error_message()));
|
|
||||||
}
|
}
|
||||||
// Verify the remote attestation signature.
|
// Verify the remote attestation signature.
|
||||||
std::unique_ptr<RsaPublicKey> leaf_key;
|
std::unique_ptr<RsaPublicKey> leaf_key;
|
||||||
@@ -232,30 +231,30 @@ util::Status RemoteAttestationVerifier::VerifyRemoteAttestation(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!leaf_key) {
|
if (!leaf_key) {
|
||||||
return util::Status(error_space, REMOTE_ATTESTATION_FAILED,
|
return Status(error_space, REMOTE_ATTESTATION_FAILED,
|
||||||
"remote-attestation-cert-chain-no-leaf");
|
"remote-attestation-cert-chain-no-leaf");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!leaf_key->VerifySignatureSha256Pkcs7(message_with_salt,
|
if (!leaf_key->VerifySignatureSha256Pkcs7(message_with_salt,
|
||||||
remote_attestation.signature())) {
|
remote_attestation.signature())) {
|
||||||
return (util::Status(error_space, REMOTE_ATTESTATION_FAILED,
|
return (Status(error_space, REMOTE_ATTESTATION_FAILED,
|
||||||
"remote-attestation-signature-verification-failed: "));
|
"remote-attestation-signature-verification-failed: "));
|
||||||
}
|
}
|
||||||
|
|
||||||
*remote_attestation_cert_sn = cert_chain->GetCert(0)->GetSerialNumber();
|
*remote_attestation_cert_sn = cert_chain->GetCert(0)->GetSerialNumber();
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status RemoteAttestationVerifier::LoadCa() {
|
Status RemoteAttestationVerifier::LoadCa() {
|
||||||
absl::WriterMutexLock lock(&ca_mutex_);
|
absl::WriterMutexLock lock(&ca_mutex_);
|
||||||
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
|
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
|
||||||
util::Status status = ca_cert->LoadDer(absl::HexStringToBytes(
|
Status status = ca_cert->LoadDer(absl::HexStringToBytes(
|
||||||
enable_test_certificates_ ? kTestRootCaDerCert : kProdRootCaDerCert));
|
enable_test_certificates_ ? kTestRootCaDerCert : kProdRootCaDerCert));
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
ca_.reset(new X509CA(ca_cert.release()));
|
ca_.reset(new X509CA(ca_cert.release()));
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
#include "base/macros.h"
|
#include "base/macros.h"
|
||||||
#include "base/thread_annotations.h"
|
#include "base/thread_annotations.h"
|
||||||
#include "absl/synchronization/mutex.h"
|
#include "absl/synchronization/mutex.h"
|
||||||
#include "util/status.h"
|
#include "common/status.h"
|
||||||
#include "common/x509_cert.h"
|
#include "common/x509_cert.h"
|
||||||
#include "protos/public/client_identification.pb.h"
|
#include "protos/public/client_identification.pb.h"
|
||||||
#include "protos/public/remote_attestation.pb.h"
|
#include "protos/public/remote_attestation.pb.h"
|
||||||
@@ -50,9 +50,9 @@ class RemoteAttestationVerifier {
|
|||||||
// return will contain the serial number for the client's remote attestation
|
// return will contain the serial number for the client's remote attestation
|
||||||
// certificate.
|
// certificate.
|
||||||
// This method is thread-safe.
|
// This method is thread-safe.
|
||||||
util::Status VerifyRemoteAttestation(
|
Status VerifyRemoteAttestation(const std::string& message,
|
||||||
const std::string& message, const RemoteAttestation& remote_attestation,
|
const RemoteAttestation& remote_attestation,
|
||||||
std::string* remote_attestation_cert_sn);
|
std::string* remote_attestation_cert_sn);
|
||||||
|
|
||||||
// Call to verify a RemoteAttestation challenge response, used in certificate
|
// Call to verify a RemoteAttestation challenge response, used in certificate
|
||||||
// provisioning protocol.
|
// provisioning protocol.
|
||||||
@@ -61,9 +61,9 @@ class RemoteAttestationVerifier {
|
|||||||
// |privacy_key| is used to decrypt the EncryptedClientIdentification within
|
// |privacy_key| is used to decrypt the EncryptedClientIdentification within
|
||||||
// the |remote_attestation| message.
|
// the |remote_attestation| message.
|
||||||
// This method is thread-safe.
|
// This method is thread-safe.
|
||||||
util::Status VerifyRemoteAttestation(
|
Status VerifyRemoteAttestation(const std::string& message,
|
||||||
const std::string& message, const RemoteAttestation& remote_attestation,
|
const RemoteAttestation& remote_attestation,
|
||||||
const std::string& privacy_key);
|
const std::string& privacy_key);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Common subroutine to perform the verification.
|
// Common subroutine to perform the verification.
|
||||||
@@ -73,12 +73,12 @@ class RemoteAttestationVerifier {
|
|||||||
// |remote_attestation_cert_sn| is a pointer to a std::string which on successful
|
// |remote_attestation_cert_sn| is a pointer to a std::string which on successful
|
||||||
// return will contain the serial number for the client's remote attestation
|
// return will contain the serial number for the client's remote attestation
|
||||||
// certificate.
|
// certificate.
|
||||||
util::Status VerifyRemoteAttestation(
|
Status VerifyRemoteAttestation(const std::string& message,
|
||||||
const std::string& message, const RemoteAttestation& remote_attestation,
|
const RemoteAttestation& remote_attestation,
|
||||||
const ClientIdentification& client_id,
|
const ClientIdentification& client_id,
|
||||||
std::string* remote_attestation_cert_sn);
|
std::string* remote_attestation_cert_sn);
|
||||||
|
|
||||||
util::Status LoadCa();
|
Status LoadCa();
|
||||||
|
|
||||||
bool enable_test_certificates_;
|
bool enable_test_certificates_;
|
||||||
absl::Mutex ca_mutex_;
|
absl::Mutex ca_mutex_;
|
||||||
|
|||||||
@@ -29,6 +29,14 @@ std::string Sha256_Hash(const std::string& message) {
|
|||||||
return digest;
|
return digest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Sha512_Hash(const std::string& message) {
|
||||||
|
std::string digest;
|
||||||
|
digest.resize(SHA512_DIGEST_LENGTH);
|
||||||
|
SHA512(reinterpret_cast<const uint8_t*>(message.data()), message.size(),
|
||||||
|
reinterpret_cast<uint8_t*>(&digest[0]));
|
||||||
|
return digest;
|
||||||
|
}
|
||||||
|
|
||||||
std::string GenerateSha1Uuid(const std::string& name_space, const std::string& name) {
|
std::string GenerateSha1Uuid(const std::string& name_space, const std::string& name) {
|
||||||
// X.667 14 Setting the fields of a name-based UUID.
|
// X.667 14 Setting the fields of a name-based UUID.
|
||||||
// - Allocate a UUID to use as a "name space identifier" for all UUIDs
|
// - Allocate a UUID to use as a "name space identifier" for all UUIDs
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ std::string Sha1_Hash(const std::string& message);
|
|||||||
// Calculates SHA256 hash.
|
// Calculates SHA256 hash.
|
||||||
std::string Sha256_Hash(const std::string& message);
|
std::string Sha256_Hash(const std::string& message);
|
||||||
|
|
||||||
|
// Calculate SHA512 hash.
|
||||||
|
std::string Sha512_Hash(const std::string& message);
|
||||||
|
|
||||||
// Generates a UUID as specified in ITU-T X.667 ch. 14, SHA-1 name-based,
|
// Generates a UUID as specified in ITU-T X.667 ch. 14, SHA-1 name-based,
|
||||||
// 16-byte binary representation. Name_space is a GUID prefix; name is a unique
|
// 16-byte binary representation. Name_space is a GUID prefix; name is a unique
|
||||||
// name in the namespace.
|
// name in the namespace.
|
||||||
|
|||||||
@@ -48,6 +48,18 @@ TEST(ShaUtilTest, Sha256) {
|
|||||||
Sha256_Hash("random data"));
|
Sha256_Hash("random data"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ShaUtilTest, Sha512) {
|
||||||
|
const uint8_t kExpected[] = {
|
||||||
|
0x8f, 0x49, 0x93, 0x1f, 0x4d, 0x4a, 0x67, 0x6f, 0x9a, 0x7e, 0x62,
|
||||||
|
0x60, 0xea, 0xe1, 0x54, 0xfe, 0xe2, 0x75, 0x3c, 0xec, 0x3b, 0xb2,
|
||||||
|
0x2e, 0xd7, 0x51, 0xcc, 0x39, 0xf9, 0x89, 0x69, 0xad, 0xd0, 0x14,
|
||||||
|
0xaa, 0xbe, 0x40, 0xce, 0xe3, 0xab, 0xef, 0x10, 0x2f, 0x24, 0x0e,
|
||||||
|
0xd8, 0x26, 0x7b, 0xb5, 0x7d, 0x86, 0xce, 0xbd, 0xd7, 0x32, 0x86,
|
||||||
|
0x3a, 0x5e, 0x9e, 0x8d, 0x23, 0x77, 0x10, 0x80, 0x0c};
|
||||||
|
EXPECT_EQ(std::string(kExpected, kExpected + sizeof(kExpected)),
|
||||||
|
Sha512_Hash("random data"));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(ShaUtilTest, GenerateSha1Uuid) {
|
TEST(ShaUtilTest, GenerateSha1Uuid) {
|
||||||
std::string name_space =
|
std::string name_space =
|
||||||
absl::HexStringToBytes("4d20ad7dd95bc4b250fae56fb143e774");
|
absl::HexStringToBytes("4d20ad7dd95bc4b250fae56fb143e774");
|
||||||
|
|||||||
@@ -11,55 +11,50 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "util/status.h"
|
|
||||||
#include "common/aes_cbc_util.h"
|
#include "common/aes_cbc_util.h"
|
||||||
#include "common/rsa_key.h"
|
#include "common/rsa_key.h"
|
||||||
#include "common/sha_util.h"
|
#include "common/sha_util.h"
|
||||||
|
#include "common/status.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
namespace signature_util {
|
namespace signature_util {
|
||||||
|
|
||||||
util::Status GenerateAesSignature(const std::string& message, const std::string& aes_key,
|
Status GenerateAesSignature(const std::string& message, const std::string& aes_key,
|
||||||
const std::string& aes_iv, std::string* signature) {
|
const std::string& aes_iv, std::string* signature) {
|
||||||
if (signature == nullptr) {
|
if (signature == nullptr) {
|
||||||
return util::Status(util::error::INVALID_ARGUMENT, "signature is nullptr");
|
return Status(error::INVALID_ARGUMENT, "signature is nullptr");
|
||||||
}
|
}
|
||||||
std::string hash = Sha1_Hash(message);
|
std::string hash = Sha1_Hash(message);
|
||||||
if (hash.empty()) {
|
if (hash.empty()) {
|
||||||
return util::Status(util::error::INTERNAL, "Computed hash is empty");
|
return Status(error::INTERNAL, "Computed hash is empty");
|
||||||
}
|
}
|
||||||
std::string sig = crypto_util::EncryptAesCbc(aes_key, aes_iv, hash);
|
std::string sig = crypto_util::EncryptAesCbc(aes_key, aes_iv, hash);
|
||||||
if (sig.empty()) {
|
if (sig.empty()) {
|
||||||
return util::Status(util::error::INTERNAL,
|
return Status(error::INTERNAL, "Computed AES signature is empty");
|
||||||
"Computed AES signature is empty");
|
|
||||||
}
|
}
|
||||||
*signature = sig;
|
*signature = sig;
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status GenerateRsaSignature(const std::string& message,
|
Status GenerateRsaSignature(const std::string& message, const std::string& private_key,
|
||||||
const std::string& private_key,
|
std::string* signature) {
|
||||||
std::string* signature) {
|
|
||||||
if (signature == nullptr) {
|
if (signature == nullptr) {
|
||||||
return util::Status(util::error::INVALID_ARGUMENT, "signature is nullptr");
|
return Status(error::INVALID_ARGUMENT, "signature is nullptr");
|
||||||
}
|
}
|
||||||
std::unique_ptr<RsaPrivateKey> rsa_private_key(
|
std::unique_ptr<RsaPrivateKey> rsa_private_key(
|
||||||
RsaPrivateKey::Create(private_key));
|
RsaPrivateKey::Create(private_key));
|
||||||
if (rsa_private_key == nullptr) {
|
if (rsa_private_key == nullptr) {
|
||||||
return util::Status(util::error::INTERNAL,
|
return Status(error::INTERNAL, "Failed to construct a RsaPrivateKey");
|
||||||
"Failed to construct a RsaPrivateKey");
|
|
||||||
}
|
}
|
||||||
std::string sig;
|
std::string sig;
|
||||||
if (!rsa_private_key->GenerateSignature(message, &sig)) {
|
if (!rsa_private_key->GenerateSignature(message, &sig)) {
|
||||||
return util::Status(util::error::INTERNAL,
|
return Status(error::INTERNAL, "Failed to generate a RSA signature");
|
||||||
"Failed to generate a RSA signature");
|
|
||||||
}
|
}
|
||||||
if (sig.empty()) {
|
if (sig.empty()) {
|
||||||
return util::Status(util::error::INTERNAL,
|
return Status(error::INTERNAL, "Computed RSA signature is empty");
|
||||||
"Computed RSA signature is empty");
|
|
||||||
}
|
}
|
||||||
*signature = sig;
|
*signature = sig;
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace signature_util
|
} // namespace signature_util
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "util/status.h"
|
#include "common/status.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
namespace signature_util {
|
namespace signature_util {
|
||||||
@@ -19,14 +19,14 @@ namespace signature_util {
|
|||||||
// Generates an AES signature of |message| using |aes_key| and |aes_iv|.
|
// Generates an AES signature of |message| using |aes_key| and |aes_iv|.
|
||||||
// Signature is returned via |signature| if generation was successful.
|
// Signature is returned via |signature| if generation was successful.
|
||||||
// Returns a Status that carries the details of error if generation failed.
|
// Returns a Status that carries the details of error if generation failed.
|
||||||
util::Status GenerateAesSignature(const std::string& message, const std::string& aes_key,
|
Status GenerateAesSignature(const std::string& message, const std::string& aes_key,
|
||||||
const std::string& aes_iv, std::string* signature);
|
const std::string& aes_iv, std::string* signature);
|
||||||
|
|
||||||
// Generates a RSA signature of |message| using |private_key|.
|
// Generates a RSA signature of |message| using |private_key|.
|
||||||
// Signature is returned via |sigature| if generation was successful.
|
// Signature is returned via |sigature| if generation was successful.
|
||||||
// Returns a Status that carries the details of error if generation failed.
|
// Returns a Status that carries the details of error if generation failed.
|
||||||
util::Status GenerateRsaSignature(const std::string& message,
|
Status GenerateRsaSignature(const std::string& message, const std::string& private_key,
|
||||||
const std::string& private_key, std::string* signature);
|
std::string* signature);
|
||||||
|
|
||||||
} // namespace signature_util
|
} // namespace signature_util
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace widevine {
|
|||||||
|
|
||||||
using crypto_util::kSigningKeySizeBits;
|
using crypto_util::kSigningKeySizeBits;
|
||||||
|
|
||||||
uint32_t SigningKeyMaterialSize(ProtocolVersion protocol_version) {
|
uint32_t SigningKeyMaterialSizeBits(ProtocolVersion protocol_version) {
|
||||||
if (protocol_version <= VERSION_2_0) {
|
if (protocol_version <= VERSION_2_0) {
|
||||||
return kSigningKeySizeBits;
|
return kSigningKeySizeBits;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
// std::string derived_key = DeriveKey(key_str,
|
// std::string derived_key = DeriveKey(key_str,
|
||||||
// label,
|
// label,
|
||||||
// context,
|
// context,
|
||||||
// SigningKeyMaterialSize(VERSION_2_1));
|
// SigningKeyMaterialSizeBits(VERSION_2_1));
|
||||||
// std::string server_derived_key = GetServerSigningKey(derived_key);
|
// std::string server_derived_key = GetServerSigningKey(derived_key);
|
||||||
// std::string client_derived_key = GetClientSigninKey(derived_key);
|
// std::string client_derived_key = GetClientSigninKey(derived_key);
|
||||||
#ifndef COMMON_SIGNING_KEY_UTIL_H_
|
#ifndef COMMON_SIGNING_KEY_UTIL_H_
|
||||||
@@ -36,7 +36,7 @@ namespace widevine {
|
|||||||
// Returns the size of the signing key based on the License Protocol
|
// Returns the size of the signing key based on the License Protocol
|
||||||
// Version. Signing keys for version 2.0 have a length of 256. Signing
|
// Version. Signing keys for version 2.0 have a length of 256. Signing
|
||||||
// keys for version 2.1 have a length of 512.
|
// keys for version 2.1 have a length of 512.
|
||||||
uint32_t SigningKeyMaterialSize(ProtocolVersion protocol_version);
|
uint32_t SigningKeyMaterialSizeBits(ProtocolVersion protocol_version);
|
||||||
|
|
||||||
// Returns the client portion of the derived_key. The client portion
|
// Returns the client portion of the derived_key. The client portion
|
||||||
// depend on the size of the key. Keys that are 512 bits in length
|
// depend on the size of the key. Keys that are 512 bits in length
|
||||||
|
|||||||
@@ -30,14 +30,14 @@ std::string GenerateDerivedKey(widevine::ProtocolVersion protocol_version) {
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
TEST(DerivedKeyUtilTest, SigningKeyMaterialSizeProtocolVersion_2_0) {
|
TEST(DerivedKeyUtilTest, SigningKeyMaterialSizeBitsProtocolVersion_2_0) {
|
||||||
ASSERT_EQ(crypto_util::kSigningKeySizeBits,
|
ASSERT_EQ(crypto_util::kSigningKeySizeBits,
|
||||||
SigningKeyMaterialSize(VERSION_2_0));
|
SigningKeyMaterialSizeBits(VERSION_2_0));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(DerivedKeyUtilTest, SigningKeyMaterialSizeProtocolVersion_2_1) {
|
TEST(DerivedKeyUtilTest, SigningKeyMaterialSizeBitsProtocolVersion_2_1) {
|
||||||
ASSERT_EQ(crypto_util::kSigningKeySizeBits * 2,
|
ASSERT_EQ(crypto_util::kSigningKeySizeBits * 2,
|
||||||
SigningKeyMaterialSize(VERSION_2_1));
|
SigningKeyMaterialSizeBits(VERSION_2_1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(DerivedKeyUtilTest, GetServerSigningKeyProtocolVersion2_1) {
|
TEST(DerivedKeyUtilTest, GetServerSigningKeyProtocolVersion2_1) {
|
||||||
|
|||||||
74
common/status.cc
Normal file
74
common/status.cc
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 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/status.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "absl/base/macros.h"
|
||||||
|
#include "absl/strings/str_cat.h"
|
||||||
|
#include "util/error_space.h"
|
||||||
|
|
||||||
|
namespace widevine {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const char* kGenericErrorStatusMessage[] = {"OK",
|
||||||
|
"unknown_error",
|
||||||
|
"unknown_error",
|
||||||
|
"invalid_argument",
|
||||||
|
"unknown_error",
|
||||||
|
"not_found",
|
||||||
|
"already_exists",
|
||||||
|
"permission_denied",
|
||||||
|
"unknown_error",
|
||||||
|
"unknown_error",
|
||||||
|
"unknown_error",
|
||||||
|
"unknown_error",
|
||||||
|
"unimplemented",
|
||||||
|
"internal",
|
||||||
|
"unavailable"};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
class GenericErrorSpace : public util::ErrorSpaceImpl<GenericErrorSpace> {
|
||||||
|
public:
|
||||||
|
static std::string space_name();
|
||||||
|
static std::string code_to_string(int code);
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string GenericErrorSpace::space_name() { return "generic"; }
|
||||||
|
|
||||||
|
std::string GenericErrorSpace::code_to_string(int code) {
|
||||||
|
static_assert(
|
||||||
|
ABSL_ARRAYSIZE(kGenericErrorStatusMessage) == error::NUM_ERRORS,
|
||||||
|
"mismatching generic error status message and generic error status.");
|
||||||
|
|
||||||
|
if (code >= 0 && code < error::NUM_ERRORS)
|
||||||
|
return kGenericErrorStatusMessage[code];
|
||||||
|
return std::to_string(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const util::ErrorSpace* Status::canonical_space() {
|
||||||
|
return GenericErrorSpace::Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Status::ToString() const {
|
||||||
|
if (status_code_ == error::OK) return "OK";
|
||||||
|
return absl::StrCat("Errors::", error_space_->String(status_code_), ": ",
|
||||||
|
error_message_);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, const Status& x) {
|
||||||
|
os << x.ToString();
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace widevine
|
||||||
@@ -6,15 +6,14 @@
|
|||||||
// widevine-licensing@google.com.
|
// widevine-licensing@google.com.
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifndef UTIL_STATUS_H_
|
#ifndef COMMON_STATUS_H_
|
||||||
#define UTIL_STATUS_H_
|
#define COMMON_STATUS_H_
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "util/error_space.h"
|
#include "util/error_space.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
namespace util {
|
|
||||||
namespace error {
|
namespace error {
|
||||||
|
|
||||||
enum StatusCode {
|
enum StatusCode {
|
||||||
@@ -54,66 +53,56 @@ enum StatusCode {
|
|||||||
|
|
||||||
} // namespace error
|
} // namespace error
|
||||||
|
|
||||||
class GenericErrorSpace : public ErrorSpaceImpl<GenericErrorSpace> {
|
|
||||||
public:
|
|
||||||
static std::string SpaceName();
|
|
||||||
static std::string CodeToString(int code);
|
|
||||||
};
|
|
||||||
|
|
||||||
class Status {
|
class Status {
|
||||||
public:
|
public:
|
||||||
Status() : status_code_(error::OK) {}
|
|
||||||
~Status() {}
|
Status() = default;
|
||||||
|
|
||||||
|
~Status() = default;
|
||||||
|
|
||||||
explicit Status(error::StatusCode c) : status_code_(c) {}
|
explicit Status(error::StatusCode c) : status_code_(c) {}
|
||||||
|
|
||||||
Status(error::StatusCode c, const std::string& error_message)
|
Status(error::StatusCode c, const std::string& error_message)
|
||||||
: status_code_(c), error_message_(error_message) {}
|
: status_code_(c), error_message_(error_message) {}
|
||||||
Status(const ErrorSpace* e, error::StatusCode c,
|
|
||||||
const std::string& error_message) {
|
Status(const util::ErrorSpace* e, error::StatusCode c,
|
||||||
SetError(e, c, error_message);
|
const std::string& error_message)
|
||||||
}
|
: error_space_(e), status_code_(c), error_message_(error_message) {}
|
||||||
Status(const ErrorSpace* e, int error, const std::string& error_message) {
|
|
||||||
SetError(e, error, error_message);
|
Status(const util::ErrorSpace* e, int error, const std::string& error_message)
|
||||||
}
|
: error_space_(e), status_code_(error), error_message_(error_message) {}
|
||||||
void SetError(const ErrorSpace* e, int c, const std::string& error_message) {
|
|
||||||
error_space_ = e;
|
|
||||||
status_code_ = c;
|
|
||||||
error_message_ = error_message;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ok() const { return status_code_ == error::OK; }
|
bool ok() const { return status_code_ == error::OK; }
|
||||||
const ErrorSpace* error_space() const { return error_space_; }
|
const util::ErrorSpace* error_space() const { return error_space_; }
|
||||||
static const ErrorSpace* canonical_space() {
|
static const util::ErrorSpace* canonical_space();
|
||||||
return GenericErrorSpace::Get();
|
|
||||||
}
|
|
||||||
std::string ToString() const;
|
std::string ToString() const;
|
||||||
std::string error_message() const { return error_message_; }
|
std::string error_message() const { return error_message_; }
|
||||||
int error_code() const { return status_code_; }
|
int error_code() const { return status_code_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const ErrorSpace* error_space_ = GenericErrorSpace::Get();
|
const util::ErrorSpace* error_space_ = canonical_space();
|
||||||
int status_code_;
|
int status_code_ = error::OK;
|
||||||
std::string error_message_;
|
std::string error_message_;
|
||||||
}; // class Status
|
};
|
||||||
|
|
||||||
inline Status OkStatus() { return Status(); }
|
inline Status OkStatus() { return Status(); }
|
||||||
|
|
||||||
// Here error_message_ is ignored during comparison.
|
|
||||||
inline bool operator==(const Status& s1, const Status& s2) {
|
inline bool operator==(const Status& s1, const Status& s2) {
|
||||||
return s1.error_space() == s2.error_space() &&
|
return s1.error_space() == s2.error_space() &&
|
||||||
s1.error_code() == s2.error_code();
|
s1.error_code() == s2.error_code() &&
|
||||||
|
s1.error_message() == s2.error_message();
|
||||||
}
|
}
|
||||||
inline bool operator!=(const Status& s1, const Status& s2) {
|
inline bool operator!=(const Status& s1, const Status& s2) {
|
||||||
return s1.error_space() != s2.error_space() ||
|
return !(s1 == s2);
|
||||||
s1.error_code() != s2.error_code();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 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(expression.ok()) << expression.ToString()
|
#define CHECK_OK(expression) CHECK(expression.ok()) << expression.ToString()
|
||||||
|
|
||||||
|
|
||||||
} // namespace util
|
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
|
|
||||||
#endif // UTIL_STATUS_H_
|
#endif // COMMON_STATUS_H_
|
||||||
@@ -6,12 +6,10 @@
|
|||||||
// widevine-licensing@google.com.
|
// widevine-licensing@google.com.
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include "util/status.h"
|
#include "common/status.h"
|
||||||
|
|
||||||
#include "testing/gunit.h"
|
#include "testing/gunit.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
namespace util {
|
|
||||||
|
|
||||||
TEST(StatusTest, OK_Status) {
|
TEST(StatusTest, OK_Status) {
|
||||||
// test case for ok status.
|
// test case for ok status.
|
||||||
@@ -27,13 +25,13 @@ TEST(StatusTest, OK_Status2) {
|
|||||||
|
|
||||||
TEST(StatusTest, ALREADY_EXISTS_Status) {
|
TEST(StatusTest, ALREADY_EXISTS_Status) {
|
||||||
Status status(error::ALREADY_EXISTS, "it is already exist");
|
Status status(error::ALREADY_EXISTS, "it is already exist");
|
||||||
EXPECT_EQ("Errors::ALREADY_EXISTS: it is already exist", status.ToString());
|
EXPECT_EQ("Errors::already_exists: it is already exist", status.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
// test case for status in boundary cases.
|
// test case for status in boundary cases.
|
||||||
TEST(StatusTest, UNAVAILABLE_Status) {
|
TEST(StatusTest, UNAVAILABLE_Status) {
|
||||||
Status status(error::UNAVAILABLE, "unavailable");
|
Status status(error::UNAVAILABLE, "unavailable");
|
||||||
EXPECT_EQ("Errors::UNAVAILABLE: unavailable", status.ToString());
|
EXPECT_EQ("Errors::unavailable: unavailable", status.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(StatusTest, NoNameCode) {
|
TEST(StatusTest, NoNameCode) {
|
||||||
@@ -43,7 +41,7 @@ TEST(StatusTest, NoNameCode) {
|
|||||||
|
|
||||||
TEST(StatusTest, EQUAL_OPERATOR) {
|
TEST(StatusTest, EQUAL_OPERATOR) {
|
||||||
Status status1(error::ALREADY_EXISTS, "already exists 1");
|
Status status1(error::ALREADY_EXISTS, "already exists 1");
|
||||||
Status status2(error::ALREADY_EXISTS, "already exists 2");
|
Status status2(error::ALREADY_EXISTS, "already exists 1");
|
||||||
EXPECT_EQ(status1, status2);
|
EXPECT_EQ(status1, status2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,5 +57,5 @@ TEST(StatusTest, NOT_EQUAL_OPERATOR_NONE_MSG) {
|
|||||||
EXPECT_NE(status1, status2);
|
EXPECT_NE(status1, status2);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace util
|
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
@@ -11,14 +11,14 @@
|
|||||||
#include <bitset>
|
#include <bitset>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "util/status.h"
|
#include "common/status.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
namespace string_util {
|
namespace string_util {
|
||||||
|
|
||||||
util::Status BitsetStringToBinaryString(const std::string& bitset, std::string* output) {
|
Status BitsetStringToBinaryString(const std::string& bitset, std::string* output) {
|
||||||
if (output == nullptr) {
|
if (output == nullptr) {
|
||||||
return util::Status(util::error::INTERNAL, "output is nullptr.");
|
return Status(error::INTERNAL, "output is nullptr.");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::stringstream sstream(bitset);
|
std::stringstream sstream(bitset);
|
||||||
@@ -29,7 +29,7 @@ util::Status BitsetStringToBinaryString(const std::string& bitset, std::string*
|
|||||||
*output += c;
|
*output += c;
|
||||||
}
|
}
|
||||||
|
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace string_util
|
} // namespace string_util
|
||||||
|
|||||||
@@ -10,14 +10,14 @@
|
|||||||
#define COMMON_STRING_UTIL_H_
|
#define COMMON_STRING_UTIL_H_
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "util/status.h"
|
#include "common/status.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
namespace string_util {
|
namespace string_util {
|
||||||
|
|
||||||
// Converts std::string representation of a bitset to its binary equivalent string.
|
// Converts std::string representation of a bitset to its binary equivalent string.
|
||||||
// For example, converts "01110100011001010111001101110100" to "test".
|
// For example, converts "01110100011001010111001101110100" to "test".
|
||||||
util::Status BitsetStringToBinaryString(const std::string& bitset, std::string* output);
|
Status BitsetStringToBinaryString(const std::string& bitset, std::string* output);
|
||||||
|
|
||||||
} // namespace string_util
|
} // namespace string_util
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
|
|||||||
@@ -18,32 +18,31 @@
|
|||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
|
|
||||||
util::Status GenerateRsaSignatureSha256Pkcs1(const std::string& pem_private_key,
|
Status GenerateRsaSignatureSha256Pkcs1(const std::string& pem_private_key,
|
||||||
const std::string& message,
|
const std::string& message,
|
||||||
std::string* signature) {
|
std::string* signature) {
|
||||||
CHECK(signature);
|
CHECK(signature);
|
||||||
if (pem_private_key.empty()) {
|
if (pem_private_key.empty()) {
|
||||||
return util::Status(util::error::INVALID_ARGUMENT, "Empty PEM private key");
|
return Status(error::INVALID_ARGUMENT, "Empty PEM private key");
|
||||||
}
|
}
|
||||||
if (message.empty()) {
|
if (message.empty()) {
|
||||||
return util::Status(util::error::INVALID_ARGUMENT, "Empty message");
|
return Status(error::INVALID_ARGUMENT, "Empty message");
|
||||||
}
|
}
|
||||||
BIO* bio(NULL);
|
BIO* bio(NULL);
|
||||||
bio = BIO_new_mem_buf(const_cast<char*>(pem_private_key.data()),
|
bio = BIO_new_mem_buf(const_cast<char*>(pem_private_key.data()),
|
||||||
pem_private_key.size());
|
pem_private_key.size());
|
||||||
if (bio == NULL) {
|
if (bio == NULL) {
|
||||||
return util::Status(util::error::INTERNAL, "BIO allocation failed");
|
return Status(error::INTERNAL, "BIO allocation failed");
|
||||||
}
|
}
|
||||||
util::Status status;
|
Status status;
|
||||||
RSA* key(NULL);
|
RSA* key(NULL);
|
||||||
std::unique_ptr<char[]> sig_buffer;
|
std::unique_ptr<char[]> sig_buffer;
|
||||||
unsigned int sig_size;
|
unsigned int sig_size;
|
||||||
unsigned char digest[SHA256_DIGEST_LENGTH];
|
unsigned char digest[SHA256_DIGEST_LENGTH];
|
||||||
key = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
|
key = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
|
||||||
if (key == NULL) {
|
if (key == NULL) {
|
||||||
status = util::Status(util::Status::canonical_space(),
|
status = Status(Status::canonical_space(), error::INVALID_ARGUMENT,
|
||||||
util::error::INVALID_ARGUMENT,
|
"PEM RSA private key load failed");
|
||||||
"PEM RSA private key load failed");
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
SHA256(reinterpret_cast<const unsigned char*>(message.data()), message.size(),
|
SHA256(reinterpret_cast<const unsigned char*>(message.data()), message.size(),
|
||||||
@@ -53,9 +52,8 @@ util::Status GenerateRsaSignatureSha256Pkcs1(const std::string& pem_private_key,
|
|||||||
if (RSA_sign(NID_sha256, digest, sizeof(digest),
|
if (RSA_sign(NID_sha256, digest, sizeof(digest),
|
||||||
reinterpret_cast<unsigned char*>(sig_buffer.get()), &sig_size,
|
reinterpret_cast<unsigned char*>(sig_buffer.get()), &sig_size,
|
||||||
key) != 1) {
|
key) != 1) {
|
||||||
status =
|
status = Status(Status::canonical_space(), error::INTERNAL,
|
||||||
util::Status(util::Status::canonical_space(), util::error::INTERNAL,
|
"RSA private encrypt failed");
|
||||||
"RSA private encrypt failed");
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
signature->assign(sig_buffer.get(), sig_size);
|
signature->assign(sig_buffer.get(), sig_size);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "util/status.h"
|
#include "common/status.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
|
|
||||||
@@ -23,9 +23,9 @@ namespace widevine {
|
|||||||
// |message| is the message to be signed, and |signature| is a pointer to a
|
// |message| is the message to be signed, and |signature| is a pointer to a
|
||||||
// std::string where the signature will be stored. The caller returns ownership of
|
// std::string where the signature will be stored. The caller returns ownership of
|
||||||
// all paramters.
|
// all paramters.
|
||||||
util::Status GenerateRsaSignatureSha256Pkcs1(const std::string& pem_private_key,
|
Status GenerateRsaSignatureSha256Pkcs1(const std::string& pem_private_key,
|
||||||
const std::string& message,
|
const std::string& message,
|
||||||
std::string* signature);
|
std::string* signature);
|
||||||
|
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
|
|
||||||
|
|||||||
@@ -14,13 +14,11 @@
|
|||||||
#include "common/vmp_checker.h"
|
#include "common/vmp_checker.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
util::Status VerifyVmpData(
|
Status VerifyVmpData(const std::string& vmp_data,
|
||||||
const std::string& vmp_data,
|
PlatformVerificationStatus* platform_verification_status) {
|
||||||
PlatformVerificationStatus* platform_verification_status) {
|
|
||||||
*platform_verification_status = PLATFORM_UNVERIFIED;
|
*platform_verification_status = PLATFORM_UNVERIFIED;
|
||||||
VmpChecker::Result vmp_result;
|
VmpChecker::Result vmp_result;
|
||||||
util::Status status =
|
Status status = VmpChecker::Instance()->VerifyVmpData(vmp_data, &vmp_result);
|
||||||
VmpChecker::Instance()->VerifyVmpData(vmp_data, &vmp_result);
|
|
||||||
if (status.ok()) {
|
if (status.ok()) {
|
||||||
switch (vmp_result) {
|
switch (vmp_result) {
|
||||||
case VmpChecker::kUnverified:
|
case VmpChecker::kUnverified:
|
||||||
|
|||||||
@@ -13,16 +13,15 @@
|
|||||||
#define COMMON_VERIFIED_MEDIA_PIPELINE_H_
|
#define COMMON_VERIFIED_MEDIA_PIPELINE_H_
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "util/status.h"
|
#include "common/status.h"
|
||||||
#include "protos/public/license_protocol.pb.h"
|
#include "protos/public/license_protocol.pb.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
|
|
||||||
// Retrieve the PlatformVerificationStatus for |vmp_data|. The
|
// Retrieve the PlatformVerificationStatus for |vmp_data|. The
|
||||||
// PlatformVerificationStatus is defined at
|
// PlatformVerificationStatus is defined at
|
||||||
util::Status VerifyVmpData(
|
Status VerifyVmpData(const std::string& vmp_data,
|
||||||
const std::string& vmp_data,
|
PlatformVerificationStatus* platform_verification_status);
|
||||||
PlatformVerificationStatus* platform_verification_status);
|
|
||||||
|
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
#endif // COMMON_VERIFIED_MEDIA_PIPELINE_H_
|
#endif // COMMON_VERIFIED_MEDIA_PIPELINE_H_
|
||||||
|
|||||||
@@ -248,9 +248,9 @@ VmpChecker::VmpChecker() : allow_development_vmp_(false) {}
|
|||||||
|
|
||||||
VmpChecker::~VmpChecker() {}
|
VmpChecker::~VmpChecker() {}
|
||||||
|
|
||||||
util::Status VmpChecker::SelectCertificateType(CertificateType cert_type) {
|
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(
|
Status status = ca_cert->LoadDer(
|
||||||
cert_type == kCertificateTypeProduction
|
cert_type == kCertificateTypeProduction
|
||||||
? std::string(reinterpret_cast<const char*>(
|
? std::string(reinterpret_cast<const char*>(
|
||||||
kProdVmpCodeSigningDrmRootCertificate),
|
kProdVmpCodeSigningDrmRootCertificate),
|
||||||
@@ -262,7 +262,7 @@ util::Status VmpChecker::SelectCertificateType(CertificateType cert_type) {
|
|||||||
|
|
||||||
ca_.reset(new X509CA(ca_cert.release()));
|
ca_.reset(new X509CA(ca_cert.release()));
|
||||||
|
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
VmpChecker* VmpChecker::Instance() {
|
VmpChecker* VmpChecker::Instance() {
|
||||||
@@ -271,17 +271,16 @@ VmpChecker* VmpChecker::Instance() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verify VMP data and return appropriate result.
|
// Verify VMP data and return appropriate result.
|
||||||
util::Status VmpChecker::VerifyVmpData(const std::string& vmp_data, Result* result) {
|
Status VmpChecker::VerifyVmpData(const std::string& vmp_data, Result* result) {
|
||||||
DCHECK(!vmp_data.empty());
|
DCHECK(!vmp_data.empty());
|
||||||
DCHECK(result);
|
DCHECK(result);
|
||||||
|
|
||||||
if (!ca_) return util::Status(error_space, CERT_CHAIN_NOT_SELECTED, "");
|
if (!ca_) return Status(error_space, CERT_CHAIN_NOT_SELECTED, "");
|
||||||
|
|
||||||
vmp::VmpData vmp_data_obj;
|
vmp::VmpData vmp_data_obj;
|
||||||
if (!vmp_data_obj.ParseFromString(vmp_data)) {
|
if (!vmp_data_obj.ParseFromString(vmp_data)) {
|
||||||
LOG(INFO) << "Error deserializing VmpData.";
|
LOG(INFO) << "Error deserializing VmpData.";
|
||||||
return util::Status(error_space, INVALID_MESSAGE,
|
return Status(error_space, INVALID_MESSAGE, "vmp-data-deserialize-failed");
|
||||||
"vmp-data-deserialize-failed");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::unique_ptr<X509Cert>> code_signing_certs;
|
std::vector<std::unique_ptr<X509Cert>> code_signing_certs;
|
||||||
@@ -290,7 +289,7 @@ util::Status VmpChecker::VerifyVmpData(const std::string& vmp_data, Result* resu
|
|||||||
for (int cert_idx = 0; cert_idx < vmp_data_obj.certificates_size();
|
for (int cert_idx = 0; cert_idx < vmp_data_obj.certificates_size();
|
||||||
++cert_idx) {
|
++cert_idx) {
|
||||||
code_signing_certs.emplace_back(new X509Cert);
|
code_signing_certs.emplace_back(new X509Cert);
|
||||||
util::Status status(code_signing_certs.back()->LoadDer(
|
Status status(code_signing_certs.back()->LoadDer(
|
||||||
vmp_data_obj.certificates(cert_idx)));
|
vmp_data_obj.certificates(cert_idx)));
|
||||||
if (!status.ok()) return status;
|
if (!status.ok()) return status;
|
||||||
|
|
||||||
@@ -299,8 +298,8 @@ util::Status VmpChecker::VerifyVmpData(const std::string& vmp_data, Result* resu
|
|||||||
if (code_signing_certs.back()->GetV3BooleanExtension(kDevelopmentFlagOid,
|
if (code_signing_certs.back()->GetV3BooleanExtension(kDevelopmentFlagOid,
|
||||||
&dev_flag) &&
|
&dev_flag) &&
|
||||||
dev_flag) {
|
dev_flag) {
|
||||||
return util::Status(error_space, DEVELOPMENT_CERTIFICATE_NOT_ALLOWED,
|
return Status(error_space, DEVELOPMENT_CERTIFICATE_NOT_ALLOWED,
|
||||||
"development-vmp-certificate-not-allowed");
|
"development-vmp-certificate-not-allowed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
status = ca_->VerifyCert(*code_signing_certs.back());
|
status = ca_->VerifyCert(*code_signing_certs.back());
|
||||||
@@ -324,12 +323,12 @@ util::Status VmpChecker::VerifyVmpData(const std::string& vmp_data, Result* resu
|
|||||||
if (binary_info.signature().empty()) {
|
if (binary_info.signature().empty()) {
|
||||||
LOG(INFO) << "Unsigned binary \"" << binary_info.file_name() << "\".";
|
LOG(INFO) << "Unsigned binary \"" << binary_info.file_name() << "\".";
|
||||||
*result = kTampered;
|
*result = kTampered;
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
if (binary_info.certificate_index() >= code_signing_certs.size()) {
|
if (binary_info.certificate_index() >= code_signing_certs.size()) {
|
||||||
LOG(INFO) << "Invalid code signing certificate index.";
|
LOG(INFO) << "Invalid code signing certificate index.";
|
||||||
*result = kTampered;
|
*result = kTampered;
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
X509Cert* cert = code_signing_certs[binary_info.certificate_index()].get();
|
X509Cert* cert = code_signing_certs[binary_info.certificate_index()].get();
|
||||||
std::unique_ptr<RsaPublicKey> key(cert->GetRsaPublicKey());
|
std::unique_ptr<RsaPublicKey> key(cert->GetRsaPublicKey());
|
||||||
@@ -339,7 +338,7 @@ util::Status VmpChecker::VerifyVmpData(const std::string& vmp_data, Result* resu
|
|||||||
LOG(INFO) << "Code signature verification failed for file \""
|
LOG(INFO) << "Code signature verification failed for file \""
|
||||||
<< binary_info.file_name() << "\".";
|
<< binary_info.file_name() << "\".";
|
||||||
*result = kTampered;
|
*result = kTampered;
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
if (binary_info.flags() & kBlessedBinaryFlag) ++num_blessed_binaries;
|
if (binary_info.flags() & kBlessedBinaryFlag) ++num_blessed_binaries;
|
||||||
}
|
}
|
||||||
@@ -347,13 +346,13 @@ util::Status VmpChecker::VerifyVmpData(const std::string& vmp_data, Result* resu
|
|||||||
LOG(INFO) << "Invalid number of blessed binaries (" << num_blessed_binaries
|
LOG(INFO) << "Invalid number of blessed binaries (" << num_blessed_binaries
|
||||||
<< ").";
|
<< ").";
|
||||||
*result = kTampered;
|
*result = kTampered;
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
VLOG(2) << "VMP verification success. Secure storage: "
|
VLOG(2) << "VMP verification success. Secure storage: "
|
||||||
<< secure_storage_verified;
|
<< secure_storage_verified;
|
||||||
*result = secure_storage_verified ? kSecureStorageVerified : kVerified;
|
*result = secure_storage_verified ? kSecureStorageVerified : kVerified;
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
|
|||||||
@@ -16,8 +16,8 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "util/status.h"
|
|
||||||
#include "common/certificate_type.h"
|
#include "common/certificate_type.h"
|
||||||
|
#include "common/status.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
class X509CA;
|
class X509CA;
|
||||||
@@ -35,10 +35,10 @@ 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 SelectCertificateType(CertificateType cert_type);
|
virtual 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 Status VerifyVmpData(const std::string& vmp_data, Result* result);
|
||||||
|
|
||||||
// Enable/disable development code signing certificates.
|
// Enable/disable development code signing certificates.
|
||||||
void set_allow_development_vmp(bool allow) { allow_development_vmp_ = allow; }
|
void set_allow_development_vmp(bool allow) { allow_development_vmp_ = allow; }
|
||||||
|
|||||||
@@ -16,10 +16,10 @@
|
|||||||
#include "absl/synchronization/mutex.h"
|
#include "absl/synchronization/mutex.h"
|
||||||
#include "util/endian/endian.h"
|
#include "util/endian/endian.h"
|
||||||
#include "util/gtl/map_util.h"
|
#include "util/gtl/map_util.h"
|
||||||
#include "util/status.h"
|
|
||||||
#include "common/aes_cbc_util.h"
|
#include "common/aes_cbc_util.h"
|
||||||
#include "common/ecb_util.h"
|
#include "common/ecb_util.h"
|
||||||
#include "common/sha_util.h"
|
#include "common/sha_util.h"
|
||||||
|
#include "common/status.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
|
|
||||||
@@ -108,20 +108,20 @@ bool WvmTokenHandler::IsSystemIdKnown(uint32_t system_id) {
|
|||||||
return PreprovKeysMap::GetSingleton()->IsSystemIdKnown(system_id);
|
return PreprovKeysMap::GetSingleton()->IsSystemIdKnown(system_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token,
|
Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token,
|
||||||
std::string* device_key_out,
|
std::string* device_key_out,
|
||||||
Cipher* cipher_out,
|
Cipher* cipher_out,
|
||||||
bool* insecure_out) {
|
bool* insecure_out) {
|
||||||
const std::string default_make_model;
|
const std::string default_make_model;
|
||||||
return DecryptDeviceKey(token, default_make_model, device_key_out, cipher_out,
|
return DecryptDeviceKey(token, default_make_model, device_key_out, cipher_out,
|
||||||
insecure_out);
|
insecure_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token,
|
Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token,
|
||||||
const std::string& make_model,
|
const std::string& make_model,
|
||||||
std::string* device_key_out,
|
std::string* device_key_out,
|
||||||
Cipher* cipher_out,
|
Cipher* cipher_out,
|
||||||
bool* insecure_out) {
|
bool* insecure_out) {
|
||||||
DCHECK(device_key_out);
|
DCHECK(device_key_out);
|
||||||
// DCHECK below is commented out because preprov_keys_ being nullptr
|
// DCHECK below is commented out because preprov_keys_ being nullptr
|
||||||
// is a valid test in wvm_token_handler_test.cc. If we have
|
// is a valid test in wvm_token_handler_test.cc. If we have
|
||||||
@@ -129,12 +129,11 @@ util::Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token,
|
|||||||
// presubmit because evidently Kokoro does debug build.
|
// presubmit because evidently Kokoro does debug build.
|
||||||
// DCHECK(preprov_keys_);
|
// DCHECK(preprov_keys_);
|
||||||
if (token.size() < kKeyboxSizeBytes) {
|
if (token.size() < kKeyboxSizeBytes) {
|
||||||
return util::Status(util::error::INVALID_ARGUMENT,
|
return Status(error::INVALID_ARGUMENT, "Keybox token is too short.");
|
||||||
"Keybox token is too short.");
|
|
||||||
}
|
}
|
||||||
if (PreprovKeysMap::GetSingleton()->IsEmpty()) {
|
if (PreprovKeysMap::GetSingleton()->IsEmpty()) {
|
||||||
return util::Status(util::error::INVALID_ARGUMENT,
|
return Status(error::INVALID_ARGUMENT,
|
||||||
"Pre-provisioning key map is nullptr.");
|
"Pre-provisioning key map is nullptr.");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t system_id = GetSystemId(token);
|
uint32_t system_id = GetSystemId(token);
|
||||||
@@ -143,7 +142,7 @@ util::Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token,
|
|||||||
std::vector<PreprovKey> key_vector =
|
std::vector<PreprovKey> key_vector =
|
||||||
PreprovKeysMap::GetSingleton()->GetPreprovKeys(system_id);
|
PreprovKeysMap::GetSingleton()->GetPreprovKeys(system_id);
|
||||||
|
|
||||||
util::Status status;
|
Status status;
|
||||||
// First pass through the matching system Ids is an attempt to find an
|
// First pass through the matching system Ids is an attempt to find an
|
||||||
// alternate preprov key specific to this make/model.
|
// alternate preprov key specific to this make/model.
|
||||||
const PreprovKey* preferred_ppk = NULL;
|
const PreprovKey* preferred_ppk = NULL;
|
||||||
@@ -162,8 +161,8 @@ util::Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token,
|
|||||||
ppk.key_bytes, token, device_key_out, insecure_out, &version);
|
ppk.key_bytes, token, device_key_out, insecure_out, &version);
|
||||||
if (version != 2) {
|
if (version != 2) {
|
||||||
// Only version 2 keyboxes supported.
|
// Only version 2 keyboxes supported.
|
||||||
return util::Status(util::error::PERMISSION_DENIED,
|
return Status(error::PERMISSION_DENIED,
|
||||||
absl::StrCat("invalid-keybox-version ", version));
|
absl::StrCat("invalid-keybox-version ", version));
|
||||||
}
|
}
|
||||||
if (status.ok()) {
|
if (status.ok()) {
|
||||||
if (cipher_out) {
|
if (cipher_out) {
|
||||||
@@ -176,8 +175,8 @@ util::Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token,
|
|||||||
// Return error from last attempt.
|
// Return error from last attempt.
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
return util::Status(
|
return Status(
|
||||||
util::error::NOT_FOUND,
|
error::NOT_FOUND,
|
||||||
absl::StrCat("Unknown system id: ", system_id).c_str()); // NOLINT
|
absl::StrCat("Unknown system id: ", system_id).c_str()); // NOLINT
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,12 +184,13 @@ util::Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token,
|
|||||||
// decrypted device key to encrypt the given asset key. Returns the encrypted
|
// decrypted device key to encrypt the given asset key. Returns the encrypted
|
||||||
// asset key in |result|.
|
// asset key in |result|.
|
||||||
// On failure, returns an error from the Widevine Server SDK error space.
|
// On failure, returns an error from the Widevine Server SDK error space.
|
||||||
util::Status WvmTokenHandler::GetEncryptedAssetKey(
|
Status WvmTokenHandler::GetEncryptedAssetKey(absl::string_view token,
|
||||||
absl::string_view token, absl::string_view raw_asset_key,
|
absl::string_view raw_asset_key,
|
||||||
const std::string& make_model, std::string* result) {
|
const std::string& make_model,
|
||||||
|
std::string* result) {
|
||||||
std::string device_key;
|
std::string device_key;
|
||||||
Cipher cipher = AES;
|
Cipher cipher = AES;
|
||||||
util::Status status =
|
Status status =
|
||||||
DecryptDeviceKey(token, make_model, &device_key, &cipher, nullptr);
|
DecryptDeviceKey(token, make_model, &device_key, &cipher, nullptr);
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
return status;
|
return status;
|
||||||
@@ -215,20 +215,19 @@ std::string WvmTokenHandler::GetEncryptedUniqueId(absl::string_view token) {
|
|||||||
return encrypted_unique_id;
|
return encrypted_unique_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
|
Status WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
|
||||||
absl::string_view preprov_key, absl::string_view token,
|
absl::string_view preprov_key, absl::string_view token,
|
||||||
std::string* device_key_out) {
|
std::string* device_key_out) {
|
||||||
return DecryptDeviceKeyWithPreprovKey(preprov_key, token, device_key_out,
|
return DecryptDeviceKeyWithPreprovKey(preprov_key, token, device_key_out,
|
||||||
nullptr, nullptr);
|
nullptr, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
|
Status WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
|
||||||
absl::string_view preprov_key, absl::string_view token,
|
absl::string_view preprov_key, absl::string_view token,
|
||||||
std::string* device_key_out, bool* insecure_out, uint32_t* version) {
|
std::string* device_key_out, bool* insecure_out, uint32_t* version) {
|
||||||
CHECK(device_key_out);
|
CHECK(device_key_out);
|
||||||
if (token.size() < kKeyboxSizeBytes) {
|
if (token.size() < kKeyboxSizeBytes) {
|
||||||
return util::Status(util::error::INVALID_ARGUMENT,
|
return Status(error::INVALID_ARGUMENT, "Keybox token is too short.");
|
||||||
"Keybox token is too short.");
|
|
||||||
}
|
}
|
||||||
if (version) {
|
if (version) {
|
||||||
*version = BigEndian::Load32(token.data());
|
*version = BigEndian::Load32(token.data());
|
||||||
@@ -243,7 +242,7 @@ util::Status WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
|
|||||||
if (unique_id.size() != 16) {
|
if (unique_id.size() != 16) {
|
||||||
// Decrypting 16 bytes should result in 16 bytes.
|
// Decrypting 16 bytes should result in 16 bytes.
|
||||||
LOG(WARNING) << "Internal error decrypting unique id from token.";
|
LOG(WARNING) << "Internal error decrypting unique id from token.";
|
||||||
return util::Status(util::error::INTERNAL, "Wrong size after decrypt/16.");
|
return Status(error::INTERNAL, "Wrong size after decrypt/16.");
|
||||||
}
|
}
|
||||||
|
|
||||||
absl::string_view encrypted_bits = token.substr(24, 48);
|
absl::string_view encrypted_bits = token.substr(24, 48);
|
||||||
@@ -252,7 +251,7 @@ util::Status WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
|
|||||||
if (decrypted_bits.size() != 48) {
|
if (decrypted_bits.size() != 48) {
|
||||||
// Decrypting 48 bytes should result in 48 bytes.
|
// Decrypting 48 bytes should result in 48 bytes.
|
||||||
LOG(WARNING) << "Internal error decrypting device key from token.";
|
LOG(WARNING) << "Internal error decrypting device key from token.";
|
||||||
return util::Status(util::error::INTERNAL, "Wrong size after decrypt/48.");
|
return Status(error::INTERNAL, "Wrong size after decrypt/48.");
|
||||||
}
|
}
|
||||||
uint8_t keybox_flags = decrypted_bits[36];
|
uint8_t keybox_flags = decrypted_bits[36];
|
||||||
absl::string_view device_key =
|
absl::string_view device_key =
|
||||||
@@ -269,48 +268,43 @@ util::Status WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
|
|||||||
keybox_flags = 0;
|
keybox_flags = 0;
|
||||||
}
|
}
|
||||||
if (expected_hash != actual_hash) {
|
if (expected_hash != actual_hash) {
|
||||||
return util::Status(util::error::PERMISSION_DENIED,
|
return Status(error::PERMISSION_DENIED, "Keybox validation failed.");
|
||||||
"Keybox validation failed.");
|
|
||||||
}
|
}
|
||||||
*device_key_out = std::string(device_key);
|
*device_key_out = std::string(device_key);
|
||||||
if (insecure_out) {
|
if (insecure_out) {
|
||||||
*insecure_out = (keybox_flags & kKeyboxFlagInsecure) != 0;
|
*insecure_out = (keybox_flags & kKeyboxFlagInsecure) != 0;
|
||||||
}
|
}
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status WvmTokenHandler::EncryptAssetKey(absl::string_view device_key,
|
Status WvmTokenHandler::EncryptAssetKey(absl::string_view device_key,
|
||||||
absl::string_view raw_asset_key,
|
absl::string_view raw_asset_key,
|
||||||
Cipher cipher, std::string* result) {
|
Cipher cipher, std::string* result) {
|
||||||
CHECK(result);
|
CHECK(result);
|
||||||
if (device_key.size() != 16) {
|
if (device_key.size() != 16) {
|
||||||
return util::Status(util::error::INVALID_ARGUMENT,
|
return Status(error::INVALID_ARGUMENT, "Invalid device key: size != 16");
|
||||||
"Invalid device key: size != 16");
|
|
||||||
}
|
}
|
||||||
if (raw_asset_key.size() < 16) {
|
if (raw_asset_key.size() < 16) {
|
||||||
return util::Status(util::error::INVALID_ARGUMENT,
|
return Status(error::INVALID_ARGUMENT, "Invalid asset key: size < 16");
|
||||||
"Invalid asset key: size < 16");
|
|
||||||
}
|
}
|
||||||
// Truncate extra characters in the key; wvm always uses 16.
|
// Truncate extra characters in the key; wvm always uses 16.
|
||||||
absl::string_view asset_key = raw_asset_key.substr(0, 16);
|
absl::string_view asset_key = raw_asset_key.substr(0, 16);
|
||||||
switch (cipher) {
|
switch (cipher) {
|
||||||
case DES3:
|
case DES3:
|
||||||
if (!crypto_util::Encrypt3DesEcb(device_key, asset_key, result)) {
|
if (!crypto_util::Encrypt3DesEcb(device_key, asset_key, result)) {
|
||||||
return util::Status(util::error::INTERNAL,
|
return Status(error::INTERNAL, "Error encrypting asset key with 3DES.");
|
||||||
"Error encrypting asset key with 3DES.");
|
|
||||||
}
|
}
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
case AES:
|
case AES:
|
||||||
if (!crypto_util::EncryptAesEcb(device_key, asset_key, result)) {
|
if (!crypto_util::EncryptAesEcb(device_key, asset_key, result)) {
|
||||||
return util::Status(util::error::INTERNAL,
|
return Status(error::INTERNAL, "Error encrypting asset key with AES.");
|
||||||
"Error encrypting asset key with AES.");
|
|
||||||
}
|
}
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
case PASS_THRU:
|
case PASS_THRU:
|
||||||
result->assign(raw_asset_key.data(), raw_asset_key.size());
|
result->assign(raw_asset_key.data(), raw_asset_key.size());
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
default:
|
default:
|
||||||
return util::Status(util::error::INVALID_ARGUMENT, "Unknown cipher type");
|
return Status(error::INVALID_ARGUMENT, "Unknown cipher type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
#include "base/macros.h"
|
#include "base/macros.h"
|
||||||
#include "absl/strings/string_view.h"
|
#include "absl/strings/string_view.h"
|
||||||
#include "util/status.h"
|
#include "common/status.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
|
|
||||||
@@ -70,24 +70,23 @@ class WvmTokenHandler {
|
|||||||
// to use with the device key.
|
// to use with the device key.
|
||||||
// insecure_out may be null; if not, *insecure_out will be set to the
|
// insecure_out may be null; if not, *insecure_out will be set to the
|
||||||
// decrypted value of the 'insecure keybox' flag.
|
// decrypted value of the 'insecure keybox' flag.
|
||||||
static util::Status DecryptDeviceKey(absl::string_view token,
|
static Status DecryptDeviceKey(absl::string_view token,
|
||||||
std::string* device_key_out,
|
std::string* device_key_out, Cipher* cipher_out,
|
||||||
Cipher* cipher_out, bool* insecure_out);
|
bool* insecure_out);
|
||||||
// Same as above, except takes in the make/model from the license request.
|
// Same as above, except takes in the make/model from the license request.
|
||||||
// For legacy WVM license, we have some special cases where we need to inspect
|
// For legacy WVM license, we have some special cases where we need to inspect
|
||||||
// the make/model as we apply alternate keys.
|
// the make/model as we apply alternate keys.
|
||||||
static util::Status DecryptDeviceKey(absl::string_view token,
|
static Status DecryptDeviceKey(absl::string_view token,
|
||||||
const std::string& make_model,
|
const std::string& make_model,
|
||||||
std::string* device_key_out,
|
std::string* device_key_out, Cipher* cipher_out,
|
||||||
Cipher* cipher_out, bool* insecure_out);
|
bool* insecure_out);
|
||||||
|
|
||||||
// Decrypt a token using the preprov key for its system ID, and use the
|
// Decrypt a token using the preprov key for its system ID, and use the
|
||||||
// decrypted device key to encrypt the given asset key. Returns the encrypted
|
// decrypted device key to encrypt the given asset key. Returns the encrypted
|
||||||
// asset key in result.
|
// asset key in result.
|
||||||
static util::Status GetEncryptedAssetKey(absl::string_view token,
|
static Status GetEncryptedAssetKey(absl::string_view token,
|
||||||
absl::string_view raw_asset_key,
|
absl::string_view raw_asset_key,
|
||||||
const std::string& make_model,
|
const std::string& make_model, std::string* result);
|
||||||
std::string* result);
|
|
||||||
|
|
||||||
// Extract the system ID component of a token (bytes 4-8).
|
// Extract the system ID component of a token (bytes 4-8).
|
||||||
static uint32_t GetSystemId(absl::string_view token);
|
static uint32_t GetSystemId(absl::string_view token);
|
||||||
@@ -101,21 +100,21 @@ class WvmTokenHandler {
|
|||||||
// Note that the if the input std::string lengths are correct (16 and 72 bytes),
|
// Note that the if the input std::string lengths are correct (16 and 72 bytes),
|
||||||
// the only possible cause of failure is the decrypted device key hash
|
// the only possible cause of failure is the decrypted device key hash
|
||||||
// being incorrect.
|
// being incorrect.
|
||||||
static util::Status DecryptDeviceKeyWithPreprovKey(
|
static Status DecryptDeviceKeyWithPreprovKey(
|
||||||
absl::string_view preprov_key_bytes, absl::string_view token,
|
absl::string_view preprov_key_bytes, absl::string_view token,
|
||||||
std::string* device_key_out);
|
std::string* device_key_out);
|
||||||
|
|
||||||
// Same as above, but allows extracting the 'insecure keybox' flag and keybox
|
// Same as above, but allows extracting the 'insecure keybox' flag and keybox
|
||||||
// version.
|
// version.
|
||||||
static util::Status DecryptDeviceKeyWithPreprovKey(
|
static Status DecryptDeviceKeyWithPreprovKey(
|
||||||
absl::string_view preprov_key_bytes, absl::string_view token,
|
absl::string_view preprov_key_bytes, absl::string_view token,
|
||||||
std::string* device_key_out, bool* insecure_out, uint32_t* version);
|
std::string* device_key_out, bool* insecure_out, uint32_t* version);
|
||||||
|
|
||||||
// Given a decrypted device key as returned by DecryptToken(), use it to
|
// Given a decrypted device key as returned by DecryptToken(), use it to
|
||||||
// encrypt an asset key with the given cipher.
|
// encrypt an asset key with the given cipher.
|
||||||
static util::Status EncryptAssetKey(absl::string_view device_key,
|
static Status EncryptAssetKey(absl::string_view device_key,
|
||||||
absl::string_view raw_asset_key,
|
absl::string_view raw_asset_key, Cipher cipher,
|
||||||
Cipher cipher, std::string* result);
|
std::string* result);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DISALLOW_IMPLICIT_CONSTRUCTORS(WvmTokenHandler);
|
DISALLOW_IMPLICIT_CONSTRUCTORS(WvmTokenHandler);
|
||||||
|
|||||||
@@ -29,12 +29,6 @@ namespace widevine {
|
|||||||
using absl::BytesToHexString;
|
using absl::BytesToHexString;
|
||||||
using absl::HexStringToBytes;
|
using absl::HexStringToBytes;
|
||||||
|
|
||||||
// TODO(user): Add EXPECT_OK macro to testing/gmock.h.
|
|
||||||
// (b/37545268).
|
|
||||||
#define EXPECT_OK(expression) \
|
|
||||||
EXPECT_EQ(util::error::OK, expression.error_code())
|
|
||||||
|
|
||||||
|
|
||||||
TEST(WvmTokenHandlerTest, GetSystemId) {
|
TEST(WvmTokenHandlerTest, GetSystemId) {
|
||||||
EXPECT_EQ(kTestSystemId,
|
EXPECT_EQ(kTestSystemId,
|
||||||
WvmTokenHandler::GetSystemId(HexStringToBytes(kTestToken1Hex)));
|
WvmTokenHandler::GetSystemId(HexStringToBytes(kTestToken1Hex)));
|
||||||
@@ -52,7 +46,7 @@ TEST(WvmTokenHandlerTest, GetEncryptedUniqueId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(WvmTokenHandlerTest, DecryptDeviceKeyWithPreprovKey) {
|
TEST(WvmTokenHandlerTest, DecryptDeviceKeyWithPreprovKey) {
|
||||||
util::Status status;
|
Status status;
|
||||||
std::string device_key;
|
std::string device_key;
|
||||||
|
|
||||||
status = WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
|
status = WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
|
||||||
@@ -76,7 +70,7 @@ TEST(WvmTokenHandlerTest, DecryptDeviceKeyWithPreprovKey) {
|
|||||||
status = WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
|
status = WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
|
||||||
HexStringToBytes(kTestPreprovKeyHex), token, &device_key);
|
HexStringToBytes(kTestPreprovKeyHex), token, &device_key);
|
||||||
EXPECT_FALSE(status.ok());
|
EXPECT_FALSE(status.ok());
|
||||||
EXPECT_EQ(util::error::PERMISSION_DENIED, status.error_code());
|
EXPECT_EQ(error::PERMISSION_DENIED, status.error_code());
|
||||||
EXPECT_TRUE(device_key.empty());
|
EXPECT_TRUE(device_key.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,18 +80,18 @@ TEST(WvmTokenHandlerTest, DecryptDeviceKeyWithPreprovKey) {
|
|||||||
TEST(WvmTokenHandlerTest, DecryptDeviceKey_PreprovKeysNullPtr) {
|
TEST(WvmTokenHandlerTest, DecryptDeviceKey_PreprovKeysNullPtr) {
|
||||||
// Not calling WvmTokenHandler::SetPreprovKeys()
|
// Not calling WvmTokenHandler::SetPreprovKeys()
|
||||||
// So preprov_keys_ would be nullptr.
|
// So preprov_keys_ would be nullptr.
|
||||||
util::Status status;
|
Status status;
|
||||||
std::string device_key;
|
std::string device_key;
|
||||||
status = WvmTokenHandler::DecryptDeviceKey(HexStringToBytes(kTestToken1Hex),
|
status = WvmTokenHandler::DecryptDeviceKey(HexStringToBytes(kTestToken1Hex),
|
||||||
&device_key, nullptr, nullptr);
|
&device_key, nullptr, nullptr);
|
||||||
EXPECT_FALSE(status.ok());
|
EXPECT_FALSE(status.ok());
|
||||||
EXPECT_EQ(util::error::INVALID_ARGUMENT, status.error_code());
|
EXPECT_EQ(error::INVALID_ARGUMENT, status.error_code());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Same tests as DecryptDeviceKeyWithPreprovKey(), but we use the handler's
|
// Same tests as DecryptDeviceKeyWithPreprovKey(), but we use the handler's
|
||||||
// table of preprov keys instead of providing our own.
|
// table of preprov keys instead of providing our own.
|
||||||
TEST(WvmTokenHandlerTest, DecryptDeviceKey) {
|
TEST(WvmTokenHandlerTest, DecryptDeviceKey) {
|
||||||
util::Status status;
|
Status status;
|
||||||
std::string device_key;
|
std::string device_key;
|
||||||
WvmTokenHandler::SetPreprovKeys(GetPreprovKeyVector());
|
WvmTokenHandler::SetPreprovKeys(GetPreprovKeyVector());
|
||||||
|
|
||||||
@@ -120,7 +114,7 @@ TEST(WvmTokenHandlerTest, DecryptDeviceKey) {
|
|||||||
status =
|
status =
|
||||||
WvmTokenHandler::DecryptDeviceKey(token, &device_key, nullptr, nullptr);
|
WvmTokenHandler::DecryptDeviceKey(token, &device_key, nullptr, nullptr);
|
||||||
EXPECT_FALSE(status.ok());
|
EXPECT_FALSE(status.ok());
|
||||||
EXPECT_EQ(util::error::PERMISSION_DENIED, status.error_code());
|
EXPECT_EQ(error::PERMISSION_DENIED, status.error_code());
|
||||||
EXPECT_TRUE(device_key.empty());
|
EXPECT_TRUE(device_key.empty());
|
||||||
|
|
||||||
// Test with nonexistent system id. Should produce NOT_FOUND.
|
// Test with nonexistent system id. Should produce NOT_FOUND.
|
||||||
@@ -132,7 +126,7 @@ TEST(WvmTokenHandlerTest, DecryptDeviceKey) {
|
|||||||
status =
|
status =
|
||||||
WvmTokenHandler::DecryptDeviceKey(token, &device_key, nullptr, nullptr);
|
WvmTokenHandler::DecryptDeviceKey(token, &device_key, nullptr, nullptr);
|
||||||
EXPECT_FALSE(status.ok());
|
EXPECT_FALSE(status.ok());
|
||||||
EXPECT_EQ(util::error::NOT_FOUND, status.error_code());
|
EXPECT_EQ(error::NOT_FOUND, status.error_code());
|
||||||
EXPECT_TRUE(device_key.empty());
|
EXPECT_TRUE(device_key.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +136,7 @@ TEST(WvmTokenHandlerTest, GetEncryptedAssetKey) {
|
|||||||
std::string raw_asset_key = "asset-key-000000";
|
std::string raw_asset_key = "asset-key-000000";
|
||||||
std::string asset_key;
|
std::string asset_key;
|
||||||
std::string make_model;
|
std::string make_model;
|
||||||
util::Status status = WvmTokenHandler::GetEncryptedAssetKey(
|
Status status = WvmTokenHandler::GetEncryptedAssetKey(
|
||||||
HexStringToBytes(kTestToken1Hex), raw_asset_key, make_model, &asset_key);
|
HexStringToBytes(kTestToken1Hex), raw_asset_key, make_model, &asset_key);
|
||||||
EXPECT_OK(status);
|
EXPECT_OK(status);
|
||||||
EXPECT_EQ("305d5f979074b1c4f932be70d3cc850c", BytesToHexString(asset_key));
|
EXPECT_EQ("305d5f979074b1c4f932be70d3cc850c", BytesToHexString(asset_key));
|
||||||
@@ -194,7 +188,7 @@ TEST(WvmTokenHandlerTest, FilterOnMakeModel) {
|
|||||||
std::string raw_asset_key = "asset-key-000000";
|
std::string raw_asset_key = "asset-key-000000";
|
||||||
std::string asset_key;
|
std::string asset_key;
|
||||||
// Check 3DES encryption of asset keys
|
// Check 3DES encryption of asset keys
|
||||||
util::Status status = WvmTokenHandler::EncryptAssetKey(
|
Status status = WvmTokenHandler::EncryptAssetKey(
|
||||||
HexStringToBytes(kTestDeviceKey3DesHex), raw_asset_key,
|
HexStringToBytes(kTestDeviceKey3DesHex), raw_asset_key,
|
||||||
WvmTokenHandler::DES3, &asset_key);
|
WvmTokenHandler::DES3, &asset_key);
|
||||||
EXPECT_OK(status);
|
EXPECT_OK(status);
|
||||||
@@ -220,7 +214,7 @@ TEST(WvmTokenHandlerTest, FilterOnMakeModel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(WvmTokenHandlerTest, AncientKeybox) {
|
TEST(WvmTokenHandlerTest, AncientKeybox) {
|
||||||
util::Status status;
|
Status status;
|
||||||
std::string device_key;
|
std::string device_key;
|
||||||
|
|
||||||
std::string v1_token(
|
std::string v1_token(
|
||||||
@@ -228,7 +222,7 @@ TEST(WvmTokenHandlerTest, AncientKeybox) {
|
|||||||
status = WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
|
status = WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
|
||||||
HexStringToBytes(v1_token), HexStringToBytes(kTestToken1Hex),
|
HexStringToBytes(v1_token), HexStringToBytes(kTestToken1Hex),
|
||||||
&device_key);
|
&device_key);
|
||||||
EXPECT_EQ(util::error::PERMISSION_DENIED, status.error_code());
|
EXPECT_EQ(error::PERMISSION_DENIED, status.error_code());
|
||||||
EXPECT_TRUE(device_key.empty());
|
EXPECT_TRUE(device_key.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,22 +67,20 @@ X509Cert::~X509Cert() {
|
|||||||
|
|
||||||
X509Cert::X509Cert(X509* openssl_cert) : openssl_cert_(openssl_cert) {}
|
X509Cert::X509Cert(X509* openssl_cert) : openssl_cert_(openssl_cert) {}
|
||||||
|
|
||||||
util::Status X509Cert::LoadPem(const std::string& pem_cert) {
|
Status X509Cert::LoadPem(const std::string& pem_cert) {
|
||||||
if (pem_cert.empty()) {
|
if (pem_cert.empty()) {
|
||||||
return util::Status(util::error::INVALID_ARGUMENT, "Empty PEM certificate");
|
return Status(error::INVALID_ARGUMENT, "Empty PEM certificate");
|
||||||
}
|
}
|
||||||
BIO* bio(NULL);
|
BIO* bio(NULL);
|
||||||
X509* new_cert(NULL);
|
X509* new_cert(NULL);
|
||||||
bio = BIO_new_mem_buf(const_cast<char*>(pem_cert.data()), pem_cert.size());
|
bio = BIO_new_mem_buf(const_cast<char*>(pem_cert.data()), pem_cert.size());
|
||||||
if (bio == NULL) {
|
if (bio == NULL) {
|
||||||
return util::Status(util::error::INTERNAL, "BIO allocation failed");
|
return Status(error::INTERNAL, "BIO allocation failed");
|
||||||
}
|
}
|
||||||
util::Status status;
|
Status status;
|
||||||
new_cert = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
|
new_cert = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
|
||||||
if (new_cert == NULL) {
|
if (new_cert == NULL) {
|
||||||
status = util::Status(util::Status::canonical_space(),
|
status = Status(error::INVALID_ARGUMENT, "PEM certificate load failed");
|
||||||
util::error::INVALID_ARGUMENT,
|
|
||||||
"PEM certificate load failed");
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
if (openssl_cert_ != NULL) {
|
if (openssl_cert_ != NULL) {
|
||||||
@@ -97,22 +95,21 @@ cleanup:
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status X509Cert::LoadDer(const std::string& der_cert) {
|
Status X509Cert::LoadDer(const std::string& der_cert) {
|
||||||
if (der_cert.empty()) {
|
if (der_cert.empty()) {
|
||||||
return util::Status(util::error::INVALID_ARGUMENT, "Empty DER certificate");
|
return Status(error::INVALID_ARGUMENT, "Empty DER certificate");
|
||||||
}
|
}
|
||||||
const unsigned char* cert_data =
|
const unsigned char* cert_data =
|
||||||
reinterpret_cast<const unsigned char*>(der_cert.data());
|
reinterpret_cast<const unsigned char*>(der_cert.data());
|
||||||
X509* new_cert = d2i_X509(NULL, &cert_data, der_cert.size());
|
X509* new_cert = d2i_X509(NULL, &cert_data, der_cert.size());
|
||||||
if (new_cert == NULL) {
|
if (new_cert == NULL) {
|
||||||
return util::Status(util::error::INVALID_ARGUMENT,
|
return Status(error::INVALID_ARGUMENT, "DER certificate load failed");
|
||||||
"DER certificate load failed");
|
|
||||||
}
|
}
|
||||||
if (openssl_cert_ != NULL) {
|
if (openssl_cert_ != NULL) {
|
||||||
X509_free(openssl_cert_);
|
X509_free(openssl_cert_);
|
||||||
}
|
}
|
||||||
openssl_cert_ = new_cert;
|
openssl_cert_ = new_cert;
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string X509Cert::GetPem() const {
|
std::string X509Cert::GetPem() const {
|
||||||
@@ -184,6 +181,24 @@ std::string X509Cert::GetSerialNumber() const {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool X509Cert::GetNotBeforeSeconds(int64_t* valid_start_seconds) const {
|
||||||
|
if (openssl_cert_ == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return Asn1TimeToEpochSeconds(X509_get0_notBefore(openssl_cert_),
|
||||||
|
valid_start_seconds)
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X509Cert::GetNotAfterSeconds(int64_t* valid_end_seconds) const {
|
||||||
|
if (openssl_cert_ == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return Asn1TimeToEpochSeconds(X509_get0_notAfter(openssl_cert_),
|
||||||
|
valid_end_seconds)
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
|
||||||
bool X509Cert::IsCaCertificate() const {
|
bool X509Cert::IsCaCertificate() const {
|
||||||
return X509_check_ca(openssl_cert_) != 0;
|
return X509_check_ca(openssl_cert_) != 0;
|
||||||
}
|
}
|
||||||
@@ -204,6 +219,38 @@ bool X509Cert::GetV3BooleanExtension(const std::string& oid, bool* value) const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Status X509Cert::Asn1TimeToEpochSeconds(const ASN1_TIME* asn1_time,
|
||||||
|
int64_t* epoch_seconds) const {
|
||||||
|
if (asn1_time == nullptr) {
|
||||||
|
// This code is exported to shared source. The exported code does not yet
|
||||||
|
// support MakeStatus.
|
||||||
|
// NOLINTNEXTLINE
|
||||||
|
return Status(error::INVALID_ARGUMENT, "asn1_time cannot be null.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (epoch_seconds == nullptr) {
|
||||||
|
// NOLINTNEXTLINE
|
||||||
|
return Status(error::INVALID_ARGUMENT, "epoch_seconds cannot be null.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedAsn1Time epoch_time(ASN1_TIME_new());
|
||||||
|
if (!ASN1_TIME_set(epoch_time.get(), 0)) {
|
||||||
|
// NOLINTNEXTLINE
|
||||||
|
return Status(error::INTERNAL, "Failed to set epoch time.");
|
||||||
|
}
|
||||||
|
|
||||||
|
int day = 0;
|
||||||
|
int seconds = 0;
|
||||||
|
if (!ASN1_TIME_diff(&day, &seconds, epoch_time.get(), asn1_time)) {
|
||||||
|
// NOLINTNEXTLINE
|
||||||
|
return Status(error::INTERNAL,
|
||||||
|
"Failed to convert asn1 time to epoch time.");
|
||||||
|
}
|
||||||
|
|
||||||
|
*epoch_seconds = 24L * 3600L * day + seconds;
|
||||||
|
return OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
X509CertChain::~X509CertChain() { Reset(); }
|
X509CertChain::~X509CertChain() { Reset(); }
|
||||||
|
|
||||||
void X509CertChain::Reset() {
|
void X509CertChain::Reset() {
|
||||||
@@ -213,7 +260,7 @@ void X509CertChain::Reset() {
|
|||||||
cert_chain_.clear();
|
cert_chain_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status X509CertChain::LoadPem(const std::string& pem_cert_chain) {
|
Status X509CertChain::LoadPem(const std::string& pem_cert_chain) {
|
||||||
static const char kBeginCertificate[] = "-----BEGIN CERTIFICATE-----";
|
static const char kBeginCertificate[] = "-----BEGIN CERTIFICATE-----";
|
||||||
static const char kEndCertificate[] = "-----END CERTIFICATE-----";
|
static const char kEndCertificate[] = "-----END CERTIFICATE-----";
|
||||||
|
|
||||||
@@ -225,7 +272,7 @@ util::Status X509CertChain::LoadPem(const std::string& pem_cert_chain) {
|
|||||||
if (end_pos != std::string::npos) {
|
if (end_pos != std::string::npos) {
|
||||||
end_pos += sizeof(kEndCertificate) - 1;
|
end_pos += sizeof(kEndCertificate) - 1;
|
||||||
std::unique_ptr<X509Cert> new_cert(new X509Cert);
|
std::unique_ptr<X509Cert> new_cert(new X509Cert);
|
||||||
util::Status status = new_cert->LoadPem(
|
Status status = new_cert->LoadPem(
|
||||||
pem_cert_chain.substr(begin_pos, end_pos - begin_pos));
|
pem_cert_chain.substr(begin_pos, end_pos - begin_pos));
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
return status;
|
return status;
|
||||||
@@ -234,17 +281,17 @@ util::Status X509CertChain::LoadPem(const std::string& pem_cert_chain) {
|
|||||||
begin_pos = pem_cert_chain.find(kBeginCertificate, end_pos);
|
begin_pos = pem_cert_chain.find(kBeginCertificate, end_pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status X509CertChain::LoadPkcs7(const std::string& pk7_cert_chain) {
|
Status X509CertChain::LoadPkcs7(const std::string& pk7_cert_chain) {
|
||||||
ScopedX509Stack cert_stack(sk_X509_new_null());
|
ScopedX509Stack cert_stack(sk_X509_new_null());
|
||||||
CBS cbs;
|
CBS cbs;
|
||||||
CBS_init(&cbs, reinterpret_cast<const uint8_t*>(pk7_cert_chain.data()),
|
CBS_init(&cbs, reinterpret_cast<const uint8_t*>(pk7_cert_chain.data()),
|
||||||
pk7_cert_chain.size());
|
pk7_cert_chain.size());
|
||||||
if (!PKCS7_get_certificates(cert_stack.get(), &cbs)) {
|
if (!PKCS7_get_certificates(cert_stack.get(), &cbs)) {
|
||||||
return util::Status(util::error::INVALID_ARGUMENT,
|
return Status(error::INVALID_ARGUMENT,
|
||||||
"Unable to load PKCS#7 certificate chain");
|
"Unable to load PKCS#7 certificate chain");
|
||||||
}
|
}
|
||||||
|
|
||||||
while (sk_X509_num(cert_stack.get()) > 0) {
|
while (sk_X509_num(cert_stack.get()) > 0) {
|
||||||
@@ -252,7 +299,7 @@ util::Status X509CertChain::LoadPkcs7(const std::string& pk7_cert_chain) {
|
|||||||
new X509Cert(sk_X509_pop(cert_stack.get())));
|
new X509Cert(sk_X509_pop(cert_stack.get())));
|
||||||
}
|
}
|
||||||
|
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string X509CertChain::GetPkcs7() {
|
std::string X509CertChain::GetPkcs7() {
|
||||||
@@ -305,44 +352,42 @@ X509CA::~X509CA() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status X509CA::InitializeStore() {
|
Status X509CA::InitializeStore() {
|
||||||
absl::WriterMutexLock lock(&openssl_store_mutex_);
|
absl::WriterMutexLock lock(&openssl_store_mutex_);
|
||||||
if (openssl_store_ == NULL) {
|
if (openssl_store_ == NULL) {
|
||||||
if (ca_cert_ == NULL) {
|
if (ca_cert_ == NULL) {
|
||||||
return util::Status(util::error::INTERNAL, "CA X.509Cert is NULL");
|
return Status(error::INTERNAL, "CA X.509Cert is NULL");
|
||||||
}
|
}
|
||||||
openssl_store_ = X509_STORE_new();
|
openssl_store_ = X509_STORE_new();
|
||||||
if (openssl_store_ == NULL) {
|
if (openssl_store_ == NULL) {
|
||||||
return util::Status(util::error::INTERNAL,
|
return Status(error::INTERNAL, "Failed to allocate X.509 store");
|
||||||
"Failed to allocate X.509 store");
|
|
||||||
}
|
}
|
||||||
if (X509_STORE_add_cert(openssl_store_,
|
if (X509_STORE_add_cert(openssl_store_,
|
||||||
const_cast<X509*>(ca_cert_->openssl_cert())) == 0) {
|
const_cast<X509*>(ca_cert_->openssl_cert())) == 0) {
|
||||||
X509_STORE_free(openssl_store_);
|
X509_STORE_free(openssl_store_);
|
||||||
openssl_store_ = NULL;
|
openssl_store_ = NULL;
|
||||||
|
|
||||||
return util::Status(util::error::INTERNAL,
|
return Status(error::INTERNAL,
|
||||||
"Failed to add X.509 CA certificate to store");
|
"Failed to add X.509 CA certificate to store");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status X509CA::VerifyCert(const X509Cert& cert) {
|
Status X509CA::VerifyCert(const X509Cert& cert) {
|
||||||
return OpenSslX509Verify(cert.openssl_cert(), nullptr);
|
return OpenSslX509Verify(cert.openssl_cert(), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status X509CA::VerifyCertChain(const X509CertChain& cert_chain) {
|
Status X509CA::VerifyCertChain(const X509CertChain& cert_chain) {
|
||||||
if (cert_chain.GetNumCerts() < 1) {
|
if (cert_chain.GetNumCerts() < 1) {
|
||||||
return util::Status(util::error::INVALID_ARGUMENT,
|
return Status(error::INVALID_ARGUMENT,
|
||||||
"Cannot verify empty certificate chain");
|
"Cannot verify empty certificate chain");
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopedX509StackOnly intermediates(sk_X509_new_null());
|
ScopedX509StackOnly intermediates(sk_X509_new_null());
|
||||||
if (!intermediates) {
|
if (!intermediates) {
|
||||||
return util::Status(
|
return Status(error::INTERNAL,
|
||||||
util::Status::canonical_space(), util::error::INTERNAL,
|
"Failed to allocate X.509 intermediate certificate stack");
|
||||||
"Failed to allocate X.509 intermediate certificate stack");
|
|
||||||
}
|
}
|
||||||
const X509Cert* leaf_cert(nullptr);
|
const X509Cert* leaf_cert(nullptr);
|
||||||
for (size_t idx = 0; idx < cert_chain.GetNumCerts(); ++idx) {
|
for (size_t idx = 0; idx < cert_chain.GetNumCerts(); ++idx) {
|
||||||
@@ -354,23 +399,21 @@ util::Status X509CA::VerifyCertChain(const X509CertChain& cert_chain) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!leaf_cert) {
|
if (!leaf_cert) {
|
||||||
return util::Status(util::Status::canonical_space(),
|
return Status(error::INVALID_ARGUMENT,
|
||||||
util::error::INVALID_ARGUMENT,
|
"X.509 certificate chain without leaf certificate.");
|
||||||
"X.509 certificate chain without leaf certificate.");
|
|
||||||
}
|
}
|
||||||
return OpenSslX509Verify(leaf_cert->openssl_cert(), intermediates.get());
|
return OpenSslX509Verify(leaf_cert->openssl_cert(), intermediates.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status X509CA::VerifyCertWithChain(const X509Cert& cert,
|
Status X509CA::VerifyCertWithChain(const X509Cert& cert,
|
||||||
const X509CertChain& cert_chain) {
|
const X509CertChain& cert_chain) {
|
||||||
ScopedX509StackOnly intermediates(sk_X509_new_null());
|
ScopedX509StackOnly intermediates(sk_X509_new_null());
|
||||||
if (!intermediates) {
|
if (!intermediates) {
|
||||||
// MakeStatus is now preferred. But we don't support it in the exported
|
// MakeStatus is now preferred. But we don't support it in the exported
|
||||||
// version, yet. So, ignore lint here.
|
// version, yet. So, ignore lint here.
|
||||||
// NOLINTNEXTLINE
|
// NOLINTNEXTLINE
|
||||||
return util::Status(
|
return Status(error::INTERNAL,
|
||||||
util::Status::canonical_space(), util::error::INTERNAL,
|
"Failed to allocate X.509 intermediate certificate stack");
|
||||||
"Failed to allocate X.509 intermediate certificate stack");
|
|
||||||
}
|
}
|
||||||
for (size_t idx = 0; idx < cert_chain.GetNumCerts(); ++idx) {
|
for (size_t idx = 0; idx < cert_chain.GetNumCerts(); ++idx) {
|
||||||
sk_X509_push(intermediates.get(),
|
sk_X509_push(intermediates.get(),
|
||||||
@@ -380,14 +423,14 @@ util::Status X509CA::VerifyCertWithChain(const X509Cert& cert,
|
|||||||
return OpenSslX509Verify(cert.openssl_cert(), intermediates.get());
|
return OpenSslX509Verify(cert.openssl_cert(), intermediates.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status X509CA::OpenSslX509Verify(const X509* cert,
|
Status X509CA::OpenSslX509Verify(const X509* cert,
|
||||||
STACK_OF(X509) * intermediates) {
|
STACK_OF(X509) * intermediates) {
|
||||||
DCHECK(cert);
|
DCHECK(cert);
|
||||||
|
|
||||||
absl::ReaderMutexLock lock(&openssl_store_mutex_);
|
absl::ReaderMutexLock lock(&openssl_store_mutex_);
|
||||||
if (openssl_store_ == NULL) {
|
if (openssl_store_ == NULL) {
|
||||||
openssl_store_mutex_.ReaderUnlock();
|
openssl_store_mutex_.ReaderUnlock();
|
||||||
util::Status status = InitializeStore();
|
Status status = InitializeStore();
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@@ -395,23 +438,21 @@ util::Status X509CA::OpenSslX509Verify(const X509* cert,
|
|||||||
}
|
}
|
||||||
ScopedX509StoreCtx store_ctx(X509_STORE_CTX_new());
|
ScopedX509StoreCtx store_ctx(X509_STORE_CTX_new());
|
||||||
if (!store_ctx) {
|
if (!store_ctx) {
|
||||||
return util::Status(util::Status::canonical_space(), util::error::INTERNAL,
|
return Status(error::INTERNAL, "Failed to allocate X.509 store context");
|
||||||
"Failed to allocate X.509 store context");
|
|
||||||
}
|
}
|
||||||
if (X509_STORE_CTX_init(store_ctx.get(), openssl_store_,
|
if (X509_STORE_CTX_init(store_ctx.get(), openssl_store_,
|
||||||
const_cast<X509*>(cert), intermediates) == 0) {
|
const_cast<X509*>(cert), intermediates) == 0) {
|
||||||
return util::Status(util::Status::canonical_space(), util::error::INTERNAL,
|
return Status(error::INTERNAL, "Failed to initialize X.509 store context");
|
||||||
"Failed to initialize X.509 store context");
|
|
||||||
}
|
}
|
||||||
int x509_status = X509_verify_cert(store_ctx.get());
|
int x509_status = X509_verify_cert(store_ctx.get());
|
||||||
if (x509_status != 1) {
|
if (x509_status != 1) {
|
||||||
return util::Status(util::Status::canonical_space(), util::error::INTERNAL,
|
return Status(error::INTERNAL,
|
||||||
std::string("X.509 certificate chain validation failed: ") +
|
std::string("X.509 certificate chain validation failed: ") +
|
||||||
X509_verify_cert_error_string(
|
X509_verify_cert_error_string(
|
||||||
X509_STORE_CTX_get_error(store_ctx.get())));
|
X509_STORE_CTX_get_error(store_ctx.get())));
|
||||||
}
|
}
|
||||||
|
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
|
|||||||
@@ -24,13 +24,13 @@
|
|||||||
#include "openssl/pem.h"
|
#include "openssl/pem.h"
|
||||||
#include "openssl/x509.h"
|
#include "openssl/x509.h"
|
||||||
#include "openssl/x509v3.h"
|
#include "openssl/x509v3.h"
|
||||||
#include "util/status.h"
|
|
||||||
#include "common/openssl_util.h"
|
#include "common/openssl_util.h"
|
||||||
#include "common/rsa_key.h"
|
#include "common/rsa_key.h"
|
||||||
|
#include "common/status.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
|
|
||||||
// NOTE: All util::Status codes are in the canonical error space.
|
// NOTE: All Status codes are in the canonical error space.
|
||||||
|
|
||||||
// Class which holds a single X.509 certificates.
|
// Class which holds a single X.509 certificates.
|
||||||
class X509Cert {
|
class X509Cert {
|
||||||
@@ -43,11 +43,11 @@ class X509Cert {
|
|||||||
|
|
||||||
// Load an X.509 certificate. Takes a single parameter, |pem_cert|, which is
|
// Load an X.509 certificate. Takes a single parameter, |pem_cert|, which is
|
||||||
// a PEM-encoded certificate.
|
// a PEM-encoded certificate.
|
||||||
util::Status LoadPem(const std::string& pem_cert);
|
Status LoadPem(const std::string& pem_cert);
|
||||||
|
|
||||||
// Load an X.509 certificate. Takes a single parameter, |pem_cert|, which is
|
// Load an X.509 certificate. Takes a single parameter, |pem_cert|, which is
|
||||||
// a DER-encoded certificate.
|
// a DER-encoded certificate.
|
||||||
util::Status LoadDer(const std::string& der_cert);
|
Status LoadDer(const std::string& der_cert);
|
||||||
|
|
||||||
// Return a std::string containing the PEM-encoded certificate.
|
// Return a std::string containing the PEM-encoded certificate.
|
||||||
std::string GetPem() const;
|
std::string GetPem() const;
|
||||||
@@ -70,6 +70,16 @@ class X509Cert {
|
|||||||
// if an error occurs.
|
// if an error occurs.
|
||||||
std::string GetSerialNumber() const;
|
std::string GetSerialNumber() const;
|
||||||
|
|
||||||
|
// Gets the start of the validity period for the certificate in seconds
|
||||||
|
// since the epoch. |valid_start_seconds| must not be null. Returns true on
|
||||||
|
// success, false otherwise.
|
||||||
|
bool GetNotBeforeSeconds(int64_t* valid_start_seconds) const;
|
||||||
|
|
||||||
|
// Gets the end of the validity period for the certificate in seconds
|
||||||
|
// since the epoch. |valid_end_seconds| must not be null. Returns true on
|
||||||
|
// success, false otherwise.
|
||||||
|
bool GetNotAfterSeconds(int64_t* valid_end_seconds) const;
|
||||||
|
|
||||||
// Returns true if the certificate is a CA (root or intermediate) certificate.
|
// Returns true if the certificate is a CA (root or intermediate) certificate.
|
||||||
bool IsCaCertificate() const;
|
bool IsCaCertificate() const;
|
||||||
|
|
||||||
@@ -81,6 +91,8 @@ class X509Cert {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
explicit X509Cert(X509* openssl_cert);
|
explicit X509Cert(X509* openssl_cert);
|
||||||
|
Status Asn1TimeToEpochSeconds(const ASN1_TIME* asn1_time,
|
||||||
|
int64_t* epoch_seconds) const;
|
||||||
|
|
||||||
X509* openssl_cert_;
|
X509* openssl_cert_;
|
||||||
std::string subject_name_;
|
std::string subject_name_;
|
||||||
@@ -100,12 +112,12 @@ class X509CertChain {
|
|||||||
// |pem_cert_chain|, which is the concatenation of a number of PEM X.509
|
// |pem_cert_chain|, which is the concatenation of a number of PEM X.509
|
||||||
// certificates, beginning with the leaf certificate, and ending with the
|
// certificates, beginning with the leaf certificate, and ending with the
|
||||||
// certificate signed by the root CA.
|
// certificate signed by the root CA.
|
||||||
util::Status LoadPem(const std::string& pem_cert_chain);
|
Status LoadPem(const std::string& pem_cert_chain);
|
||||||
|
|
||||||
// Loads a chain of DER-encoded PKCS#7 certificates. Takes a single parameter,
|
// Loads a chain of DER-encoded PKCS#7 certificates. Takes a single parameter,
|
||||||
// |pk7_cert_chain|, which is a DER-encoded PKCS#7 X.509 certificate
|
// |pk7_cert_chain|, which is a DER-encoded PKCS#7 X.509 certificate
|
||||||
// container.
|
// container.
|
||||||
util::Status LoadPkcs7(const std::string& pk7_cert_chain);
|
Status LoadPkcs7(const std::string& pk7_cert_chain);
|
||||||
|
|
||||||
// Writes the |cert_chain_| to a DER-encoded PKCS#7 X.509 cryptographic
|
// Writes the |cert_chain_| to a DER-encoded PKCS#7 X.509 cryptographic
|
||||||
// message. The final message does not include signed data.
|
// message. The final message does not include signed data.
|
||||||
@@ -136,21 +148,21 @@ class X509CA {
|
|||||||
|
|
||||||
// Does X.509 PKI validation of |cert| against the root CA certificate
|
// Does X.509 PKI validation of |cert| against the root CA certificate
|
||||||
// used when constructing X509CA. This method is thread-safe.
|
// used when constructing X509CA. This method is thread-safe.
|
||||||
util::Status VerifyCert(const X509Cert& cert);
|
Status VerifyCert(const X509Cert& cert);
|
||||||
|
|
||||||
// Does X.509 PKI validation of |cert_chain| against the root CA certificate
|
// Does X.509 PKI validation of |cert_chain| against the root CA certificate
|
||||||
// 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);
|
Status VerifyCertChain(const X509CertChain& cert_chain);
|
||||||
|
|
||||||
// Does X.509 PKI validation of |cert| using the |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
|
// certificates. This method allows |cert| to be an ICA. This method is
|
||||||
// thread-safe.
|
// thread-safe.
|
||||||
util::Status VerifyCertWithChain(const X509Cert& cert,
|
Status VerifyCertWithChain(const X509Cert& cert,
|
||||||
const X509CertChain& cert_chain);
|
const X509CertChain& cert_chain);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
util::Status InitializeStore();
|
Status InitializeStore();
|
||||||
util::Status OpenSslX509Verify(const X509* cert, STACK_OF(X509) * stack);
|
Status OpenSslX509Verify(const X509* cert, STACK_OF(X509) * intermediates);
|
||||||
|
|
||||||
std::unique_ptr<X509Cert> ca_cert_;
|
std::unique_ptr<X509Cert> ca_cert_;
|
||||||
absl::Mutex openssl_store_mutex_;
|
absl::Mutex openssl_store_mutex_;
|
||||||
|
|||||||
@@ -107,6 +107,9 @@ const char kTestPemCertSubjectField_CN[] =
|
|||||||
"stable id/emailAddress=tinskip@google.com";
|
"stable id/emailAddress=tinskip@google.com";
|
||||||
const char kTestPemCertSerialNumber[] = "\002";
|
const char kTestPemCertSerialNumber[] = "\002";
|
||||||
|
|
||||||
|
const int64_t kTestPemCertNotBeforeSeconds = 1376689440;
|
||||||
|
const int64_t kTestPemCertNotAfterSeconds = 2007755040;
|
||||||
|
|
||||||
const char kTestPemCertChain[] =
|
const char kTestPemCertChain[] =
|
||||||
"-----BEGIN CERTIFICATE-----\n"
|
"-----BEGIN CERTIFICATE-----\n"
|
||||||
"MIIDwzCCAqsCAQIwDQYJKoZIhvcNAQEFBQAwgZ8xCzAJBgNVBAYTAlVTMRMwEQYD\n"
|
"MIIDwzCCAqsCAQIwDQYJKoZIhvcNAQEFBQAwgZ8xCzAJBgNVBAYTAlVTMRMwEQYD\n"
|
||||||
@@ -352,23 +355,23 @@ const bool kTestDevCodeSigningCertFlagValue = true;
|
|||||||
|
|
||||||
TEST(X509CertTest, LoadCert) {
|
TEST(X509CertTest, LoadCert) {
|
||||||
X509Cert test_cert;
|
X509Cert test_cert;
|
||||||
EXPECT_EQ(util::OkStatus(),
|
EXPECT_EQ(OkStatus(),
|
||||||
test_cert.LoadDer(absl::HexStringToBytes(kTestRootCaDerCert)));
|
test_cert.LoadDer(absl::HexStringToBytes(kTestRootCaDerCert)));
|
||||||
EXPECT_EQ(util::OkStatus(), test_cert.LoadPem(kTestPemCert));
|
EXPECT_EQ(OkStatus(), test_cert.LoadPem(kTestPemCert));
|
||||||
// TODO(user): Add more specific status checks to failure tests.
|
// TODO(user): Add more specific status checks to failure tests.
|
||||||
EXPECT_NE(util::OkStatus(), test_cert.LoadDer("bad cert"));
|
EXPECT_NE(OkStatus(), test_cert.LoadDer("bad cert"));
|
||||||
EXPECT_NE(util::OkStatus(), test_cert.LoadPem("bad cert"));
|
EXPECT_NE(OkStatus(), test_cert.LoadPem("bad cert"));
|
||||||
EXPECT_NE(util::OkStatus(), test_cert.LoadDer(""));
|
EXPECT_NE(OkStatus(), test_cert.LoadDer(""));
|
||||||
EXPECT_NE(util::OkStatus(), test_cert.LoadPem(""));
|
EXPECT_NE(OkStatus(), test_cert.LoadPem(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(X509CertTest, VerifySignature) {
|
TEST(X509CertTest, VerifySignature) {
|
||||||
X509Cert test_cert;
|
X509Cert test_cert;
|
||||||
ASSERT_EQ(util::OkStatus(), test_cert.LoadPem(kTestPemCert));
|
ASSERT_EQ(OkStatus(), test_cert.LoadPem(kTestPemCert));
|
||||||
std::string message(absl::HexStringToBytes(kTestMessage));
|
std::string message(absl::HexStringToBytes(kTestMessage));
|
||||||
std::string signature;
|
std::string signature;
|
||||||
ASSERT_EQ(util::OkStatus(), GenerateRsaSignatureSha256Pkcs1(
|
ASSERT_EQ(OkStatus(), GenerateRsaSignatureSha256Pkcs1(kTestCertPrivateKey,
|
||||||
kTestCertPrivateKey, message, &signature));
|
message, &signature));
|
||||||
std::unique_ptr<RsaPublicKey> pub_key(test_cert.GetRsaPublicKey());
|
std::unique_ptr<RsaPublicKey> pub_key(test_cert.GetRsaPublicKey());
|
||||||
ASSERT_TRUE(pub_key);
|
ASSERT_TRUE(pub_key);
|
||||||
EXPECT_TRUE(pub_key->VerifySignatureSha256Pkcs7(message, signature));
|
EXPECT_TRUE(pub_key->VerifySignatureSha256Pkcs7(message, signature));
|
||||||
@@ -381,7 +384,7 @@ TEST(X509CertTest, VerifySignature) {
|
|||||||
|
|
||||||
TEST(X509CertTest, GetSubjectNameField) {
|
TEST(X509CertTest, GetSubjectNameField) {
|
||||||
X509Cert test_cert;
|
X509Cert test_cert;
|
||||||
ASSERT_EQ(util::OkStatus(), test_cert.LoadPem(kTestPemCert));
|
ASSERT_EQ(OkStatus(), test_cert.LoadPem(kTestPemCert));
|
||||||
EXPECT_EQ(kTestPemCertSubjectField_C, test_cert.GetSubjectNameField("C"));
|
EXPECT_EQ(kTestPemCertSubjectField_C, test_cert.GetSubjectNameField("C"));
|
||||||
EXPECT_EQ(kTestPemCertSubjectField_CN, test_cert.GetSubjectNameField("CN"));
|
EXPECT_EQ(kTestPemCertSubjectField_CN, test_cert.GetSubjectNameField("CN"));
|
||||||
EXPECT_EQ("", test_cert.GetSubjectNameField("invalid_field"));
|
EXPECT_EQ("", test_cert.GetSubjectNameField("invalid_field"));
|
||||||
@@ -389,13 +392,29 @@ TEST(X509CertTest, GetSubjectNameField) {
|
|||||||
|
|
||||||
TEST(X509CertTest, GetSerialNumber) {
|
TEST(X509CertTest, GetSerialNumber) {
|
||||||
X509Cert test_cert;
|
X509Cert test_cert;
|
||||||
ASSERT_EQ(util::OkStatus(), test_cert.LoadPem(kTestPemCert));
|
ASSERT_EQ(OkStatus(), test_cert.LoadPem(kTestPemCert));
|
||||||
EXPECT_EQ(kTestPemCertSerialNumber, test_cert.GetSerialNumber());
|
EXPECT_EQ(kTestPemCertSerialNumber, test_cert.GetSerialNumber());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(X509CertTest, GetNotBeforeSeconds) {
|
||||||
|
X509Cert test_cert;
|
||||||
|
ASSERT_EQ(OkStatus(), test_cert.LoadPem(kTestPemCert));
|
||||||
|
int64_t not_before_seconds = 0;
|
||||||
|
ASSERT_TRUE(test_cert.GetNotBeforeSeconds(¬_before_seconds));
|
||||||
|
EXPECT_EQ(kTestPemCertNotBeforeSeconds, not_before_seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(X509CertTest, GetNotAfterSeconds) {
|
||||||
|
X509Cert test_cert;
|
||||||
|
ASSERT_EQ(OkStatus(), test_cert.LoadPem(kTestPemCert));
|
||||||
|
int64_t not_after_seconds = 0;
|
||||||
|
ASSERT_TRUE(test_cert.GetNotAfterSeconds(¬_after_seconds));
|
||||||
|
EXPECT_EQ(kTestPemCertNotAfterSeconds, not_after_seconds);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(X509CertTest, CertChain) {
|
TEST(X509CertTest, CertChain) {
|
||||||
X509CertChain test_chain;
|
X509CertChain test_chain;
|
||||||
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCertChain));
|
ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemCertChain));
|
||||||
ASSERT_EQ(2, test_chain.GetNumCerts());
|
ASSERT_EQ(2, test_chain.GetNumCerts());
|
||||||
EXPECT_FALSE(test_chain.GetCert(0) == NULL);
|
EXPECT_FALSE(test_chain.GetCert(0) == NULL);
|
||||||
EXPECT_FALSE(test_chain.GetCert(1) == NULL);
|
EXPECT_FALSE(test_chain.GetCert(1) == NULL);
|
||||||
@@ -404,7 +423,7 @@ TEST(X509CertTest, CertChain) {
|
|||||||
|
|
||||||
TEST(X509CertTest, IsCaCertificate) {
|
TEST(X509CertTest, IsCaCertificate) {
|
||||||
X509CertChain test_chain;
|
X509CertChain test_chain;
|
||||||
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCertChain));
|
ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemCertChain));
|
||||||
ASSERT_EQ(2, test_chain.GetNumCerts());
|
ASSERT_EQ(2, test_chain.GetNumCerts());
|
||||||
EXPECT_FALSE(test_chain.GetCert(0)->IsCaCertificate());
|
EXPECT_FALSE(test_chain.GetCert(0)->IsCaCertificate());
|
||||||
EXPECT_TRUE(test_chain.GetCert(1)->IsCaCertificate());
|
EXPECT_TRUE(test_chain.GetCert(1)->IsCaCertificate());
|
||||||
@@ -412,84 +431,84 @@ TEST(X509CertTest, IsCaCertificate) {
|
|||||||
|
|
||||||
TEST(X509CertTest, ChainVerificationPem) {
|
TEST(X509CertTest, ChainVerificationPem) {
|
||||||
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
|
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
|
||||||
ASSERT_EQ(util::OkStatus(),
|
ASSERT_EQ(OkStatus(),
|
||||||
ca_cert->LoadDer(absl::HexStringToBytes(kTestRootCaDerCert)));
|
ca_cert->LoadDer(absl::HexStringToBytes(kTestRootCaDerCert)));
|
||||||
X509CA ca(ca_cert.release());
|
X509CA ca(ca_cert.release());
|
||||||
X509CertChain test_chain;
|
X509CertChain test_chain;
|
||||||
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCertChain));
|
ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemCertChain));
|
||||||
EXPECT_EQ(util::OkStatus(), ca.VerifyCertChain(test_chain));
|
EXPECT_EQ(OkStatus(), ca.VerifyCertChain(test_chain));
|
||||||
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCert));
|
ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemCert));
|
||||||
ASSERT_EQ(1, test_chain.GetNumCerts());
|
ASSERT_EQ(1, test_chain.GetNumCerts());
|
||||||
EXPECT_NE(util::OkStatus(), ca.VerifyCertChain(test_chain));
|
EXPECT_NE(OkStatus(), ca.VerifyCertChain(test_chain));
|
||||||
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCertChain));
|
ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemCertChain));
|
||||||
EXPECT_EQ(util::OkStatus(), ca.VerifyCertChain(test_chain));
|
EXPECT_EQ(OkStatus(), ca.VerifyCertChain(test_chain));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(X509CertTest, ChainVerificationPkcs7) {
|
TEST(X509CertTest, ChainVerificationPkcs7) {
|
||||||
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
|
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
|
||||||
ASSERT_EQ(util::OkStatus(),
|
ASSERT_EQ(OkStatus(),
|
||||||
ca_cert->LoadDer(absl::HexStringToBytes(kTestRootCaDerCert)));
|
ca_cert->LoadDer(absl::HexStringToBytes(kTestRootCaDerCert)));
|
||||||
X509CA ca(ca_cert.release());
|
X509CA ca(ca_cert.release());
|
||||||
X509CertChain test_chain;
|
X509CertChain test_chain;
|
||||||
ASSERT_EQ(util::OkStatus(),
|
ASSERT_EQ(OkStatus(),
|
||||||
test_chain.LoadPkcs7(absl::HexStringToBytes(kTestPk7CertChain)));
|
test_chain.LoadPkcs7(absl::HexStringToBytes(kTestPk7CertChain)));
|
||||||
EXPECT_EQ(util::OkStatus(), ca.VerifyCertChain(test_chain));
|
EXPECT_EQ(OkStatus(), ca.VerifyCertChain(test_chain));
|
||||||
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCert));
|
ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemCert));
|
||||||
ASSERT_EQ(1, test_chain.GetNumCerts());
|
ASSERT_EQ(1, test_chain.GetNumCerts());
|
||||||
EXPECT_NE(util::OkStatus(), ca.VerifyCertChain(test_chain));
|
EXPECT_NE(OkStatus(), ca.VerifyCertChain(test_chain));
|
||||||
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCertChain));
|
ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemCertChain));
|
||||||
EXPECT_EQ(util::OkStatus(), ca.VerifyCertChain(test_chain));
|
EXPECT_EQ(OkStatus(), ca.VerifyCertChain(test_chain));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(X509CertTest, VerifyCertWithChainIca) {
|
TEST(X509CertTest, VerifyCertWithChainIca) {
|
||||||
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
|
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
|
||||||
ASSERT_EQ(util::OkStatus(), ca_cert->LoadPem(kTestRootCaPemCert));
|
ASSERT_EQ(OkStatus(), ca_cert->LoadPem(kTestRootCaPemCert));
|
||||||
X509CA ca(ca_cert.release());
|
X509CA ca(ca_cert.release());
|
||||||
|
|
||||||
// Verify the ICA with the root succeeds.
|
// Verify the ICA with the root succeeds.
|
||||||
X509CertChain test_chain;
|
X509CertChain test_chain;
|
||||||
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestRootCaPemCert));
|
ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestRootCaPemCert));
|
||||||
ASSERT_EQ(1, test_chain.GetNumCerts());
|
ASSERT_EQ(1, test_chain.GetNumCerts());
|
||||||
X509Cert ica_cert;
|
X509Cert ica_cert;
|
||||||
ASSERT_EQ(util::OkStatus(), ica_cert.LoadPem(kTestPemIca));
|
ASSERT_EQ(OkStatus(), ica_cert.LoadPem(kTestPemIca));
|
||||||
EXPECT_EQ(util::OkStatus(), ca.VerifyCertWithChain(ica_cert, test_chain));
|
EXPECT_EQ(OkStatus(), ca.VerifyCertWithChain(ica_cert, test_chain));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(X509CertTest, VerifyCertWithChainLeaf) {
|
TEST(X509CertTest, VerifyCertWithChainLeaf) {
|
||||||
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
|
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
|
||||||
ASSERT_EQ(util::OkStatus(), ca_cert->LoadPem(kTestRootCaPemCert));
|
ASSERT_EQ(OkStatus(), ca_cert->LoadPem(kTestRootCaPemCert));
|
||||||
X509CA ca(ca_cert.release());
|
X509CA ca(ca_cert.release());
|
||||||
|
|
||||||
// Verify the leaf with the root and ICA succeeds.
|
// Verify the leaf with the root and ICA succeeds.
|
||||||
X509CertChain test_chain;
|
X509CertChain test_chain;
|
||||||
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemIca));
|
ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemIca));
|
||||||
ASSERT_EQ(1, test_chain.GetNumCerts());
|
ASSERT_EQ(1, test_chain.GetNumCerts());
|
||||||
X509Cert leaf_cert;
|
X509Cert leaf_cert;
|
||||||
ASSERT_EQ(util::OkStatus(), leaf_cert.LoadPem(kTestPemCert));
|
ASSERT_EQ(OkStatus(), leaf_cert.LoadPem(kTestPemCert));
|
||||||
EXPECT_EQ(util::OkStatus(), ca.VerifyCertWithChain(leaf_cert, test_chain));
|
EXPECT_EQ(OkStatus(), ca.VerifyCertWithChain(leaf_cert, test_chain));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(X509CertTest, VerifyCertWithChainLeafMissincIca) {
|
TEST(X509CertTest, VerifyCertWithChainLeafMissincIca) {
|
||||||
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
|
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
|
||||||
ASSERT_EQ(util::OkStatus(), ca_cert->LoadPem(kTestRootCaPemCert));
|
ASSERT_EQ(OkStatus(), ca_cert->LoadPem(kTestRootCaPemCert));
|
||||||
X509CA ca(ca_cert.release());
|
X509CA ca(ca_cert.release());
|
||||||
|
|
||||||
// Verify the leaf with only the root fails (ICA missing).
|
// Verify the leaf with only the root fails (ICA missing).
|
||||||
X509CertChain test_chain;
|
X509CertChain test_chain;
|
||||||
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestRootCaPemCert));
|
ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestRootCaPemCert));
|
||||||
ASSERT_EQ(1, test_chain.GetNumCerts());
|
ASSERT_EQ(1, test_chain.GetNumCerts());
|
||||||
X509Cert leaf_cert;
|
X509Cert leaf_cert;
|
||||||
ASSERT_EQ(util::OkStatus(), leaf_cert.LoadPem(kTestPemCert));
|
ASSERT_EQ(OkStatus(), leaf_cert.LoadPem(kTestPemCert));
|
||||||
EXPECT_NE(util::OkStatus(), ca.VerifyCertWithChain(leaf_cert, test_chain));
|
EXPECT_NE(OkStatus(), ca.VerifyCertWithChain(leaf_cert, test_chain));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(X509CertTest, GetPkcs7) {
|
TEST(X509CertTest, GetPkcs7) {
|
||||||
X509CertChain test_chain;
|
X509CertChain test_chain;
|
||||||
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCertChain));
|
ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemCertChain));
|
||||||
std::string pkcs7_certificate = test_chain.GetPkcs7();
|
std::string pkcs7_certificate = test_chain.GetPkcs7();
|
||||||
ASSERT_NE(pkcs7_certificate.size(), 0);
|
ASSERT_NE(pkcs7_certificate.size(), 0);
|
||||||
X509CertChain new_test_chain;
|
X509CertChain new_test_chain;
|
||||||
ASSERT_EQ(util::OkStatus(), new_test_chain.LoadPkcs7(pkcs7_certificate));
|
ASSERT_EQ(OkStatus(), new_test_chain.LoadPkcs7(pkcs7_certificate));
|
||||||
ASSERT_EQ(test_chain.GetNumCerts(), new_test_chain.GetNumCerts());
|
ASSERT_EQ(test_chain.GetNumCerts(), new_test_chain.GetNumCerts());
|
||||||
for (int i = 0; i < test_chain.GetNumCerts(); i++) {
|
for (int i = 0; i < test_chain.GetNumCerts(); i++) {
|
||||||
ASSERT_EQ(test_chain.GetCert(i)->GetPem(),
|
ASSERT_EQ(test_chain.GetCert(i)->GetPem(),
|
||||||
@@ -499,12 +518,12 @@ TEST(X509CertTest, GetPkcs7) {
|
|||||||
|
|
||||||
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(OkStatus(), cert1->LoadPem(kTestPemCert));
|
||||||
bool extension_value;
|
bool extension_value;
|
||||||
EXPECT_FALSE(cert1->GetV3BooleanExtension(kDevCertFlagOid, &extension_value));
|
EXPECT_FALSE(cert1->GetV3BooleanExtension(kDevCertFlagOid, &extension_value));
|
||||||
|
|
||||||
std::unique_ptr<X509Cert> cert2(new X509Cert);
|
std::unique_ptr<X509Cert> cert2(new X509Cert);
|
||||||
ASSERT_EQ(util::OkStatus(), cert2->LoadPem(kTestDevCodeSigningCert));
|
ASSERT_EQ(OkStatus(), cert2->LoadPem(kTestDevCodeSigningCert));
|
||||||
ASSERT_TRUE(cert2->GetV3BooleanExtension(kDevCertFlagOid, &extension_value));
|
ASSERT_TRUE(cert2->GetV3BooleanExtension(kDevCertFlagOid, &extension_value));
|
||||||
EXPECT_EQ(kTestDevCodeSigningCertFlagValue, extension_value);
|
EXPECT_EQ(kTestDevCodeSigningCertFlagValue, extension_value);
|
||||||
}
|
}
|
||||||
|
|||||||
39
example/BUILD
Normal file
39
example/BUILD
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
################################################################################
|
||||||
|
# Copyright 2019 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.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
# Build file for the example code.
|
||||||
|
|
||||||
|
package(
|
||||||
|
default_visibility = ["//visibility:public"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "binary_release_files",
|
||||||
|
srcs = [
|
||||||
|
"wvpl_cas_proxy_environment_example.cc",
|
||||||
|
"wvpl_cas_proxy_session_example.cc",
|
||||||
|
":wvpl_cas_proxy_environment_example",
|
||||||
|
":wvpl_cas_proxy_session_example",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc_binary(
|
||||||
|
name = "wvpl_cas_proxy_environment_example",
|
||||||
|
srcs = ["wvpl_cas_proxy_environment_example.cc"],
|
||||||
|
deps = [
|
||||||
|
"//media_cas_proxy_sdk/external/common/wvpl:wvpl_cas_proxy_environment",
|
||||||
|
"//media_cas_proxy_sdk/external/common/wvpl:wvpl_cas_proxy_session", # build_cleaner: keep
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc_binary(
|
||||||
|
name = "wvpl_cas_proxy_session_example",
|
||||||
|
srcs = ["wvpl_cas_proxy_session_example.cc"],
|
||||||
|
deps = ["//media_cas_proxy_sdk/external/common/wvpl:wvpl_cas_proxy_session"],
|
||||||
|
)
|
||||||
24
example/wvpl_cas_proxy_environment_example.cc
Normal file
24
example/wvpl_cas_proxy_environment_example.cc
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright 2019 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.
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Example of usage of wvpl_cas_proxy_environment.
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_environment.h"
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
std::map<std::string, std::string> config_values;
|
||||||
|
widevine_server::wv_pl_sdk::WvPLCASProxyEnvironment environment(
|
||||||
|
config_values);
|
||||||
|
std::cout << "Hello world!" << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
23
example/wvpl_cas_proxy_session_example.cc
Normal file
23
example/wvpl_cas_proxy_session_example.cc
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright 2019 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.
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Example of usage of wvpl_cas_proxy_session.
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_session.h"
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
std::cout << "Session version: "
|
||||||
|
<< widevine_server::wv_pl_sdk::WvPLCASProxySession::
|
||||||
|
GetVersionString()
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -41,7 +41,6 @@ cc_library(
|
|||||||
"@abseil_repo//absl/synchronization",
|
"@abseil_repo//absl/synchronization",
|
||||||
"//util/endian",
|
"//util/endian",
|
||||||
"//util/random:global_id",
|
"//util/random:global_id",
|
||||||
"//util:status",
|
|
||||||
"//common:aes_cbc_util",
|
"//common:aes_cbc_util",
|
||||||
"//common:certificate_type",
|
"//common:certificate_type",
|
||||||
"//common:client_cert",
|
"//common:client_cert",
|
||||||
@@ -51,9 +50,11 @@ cc_library(
|
|||||||
"//common:random_util",
|
"//common:random_util",
|
||||||
"//common:remote_attestation_verifier",
|
"//common:remote_attestation_verifier",
|
||||||
"//common:drm_root_certificate",
|
"//common:drm_root_certificate",
|
||||||
"//common:rsa_key",
|
|
||||||
"//common:drm_service_certificate",
|
"//common:drm_service_certificate",
|
||||||
|
"//common:rsa_key",
|
||||||
|
"//common:sha_util",
|
||||||
"//common:signing_key_util",
|
"//common:signing_key_util",
|
||||||
|
"//common:status",
|
||||||
"//common:verified_media_pipeline",
|
"//common:verified_media_pipeline",
|
||||||
"//common:vmp_checker",
|
"//common:vmp_checker",
|
||||||
"//protos/public:client_identification_proto",
|
"//protos/public:client_identification_proto",
|
||||||
@@ -86,7 +87,6 @@ cc_library(
|
|||||||
"//external:openssl",
|
"//external:openssl",
|
||||||
"//util/endian",
|
"//util/endian",
|
||||||
"//util/gtl:map_util",
|
"//util/gtl:map_util",
|
||||||
"//util:status",
|
|
||||||
"//common:client_cert",
|
"//common:client_cert",
|
||||||
"//common:crypto_util",
|
"//common:crypto_util",
|
||||||
"//common:device_status_list",
|
"//common:device_status_list",
|
||||||
@@ -96,6 +96,7 @@ cc_library(
|
|||||||
"//common:drm_root_certificate",
|
"//common:drm_root_certificate",
|
||||||
"//common:drm_service_certificate",
|
"//common:drm_service_certificate",
|
||||||
"//common:signing_key_util",
|
"//common:signing_key_util",
|
||||||
|
"//common:status",
|
||||||
"//common:wvm_token_handler",
|
"//common:wvm_token_handler",
|
||||||
"//sdk/external/common/wvpl:wvpl_types",
|
"//sdk/external/common/wvpl:wvpl_types",
|
||||||
"//protos/public:client_identification_proto",
|
"//protos/public:client_identification_proto",
|
||||||
@@ -120,6 +121,7 @@ cc_test(
|
|||||||
"//base",
|
"//base",
|
||||||
"//external:protobuf",
|
"//external:protobuf",
|
||||||
"//testing:gunit_main",
|
"//testing:gunit_main",
|
||||||
|
"@abseil_repo//absl/memory",
|
||||||
"@abseil_repo//absl/strings",
|
"@abseil_repo//absl/strings",
|
||||||
"//common:aes_cbc_util",
|
"//common:aes_cbc_util",
|
||||||
"//common:client_cert",
|
"//common:client_cert",
|
||||||
@@ -131,6 +133,7 @@ cc_test(
|
|||||||
"//common:rsa_key",
|
"//common:rsa_key",
|
||||||
"//common:rsa_test_keys",
|
"//common:rsa_test_keys",
|
||||||
"//common:rsa_util",
|
"//common:rsa_util",
|
||||||
|
"//common:sha_util",
|
||||||
"//common:signing_key_util",
|
"//common:signing_key_util",
|
||||||
"//common:test_drm_certificates",
|
"//common:test_drm_certificates",
|
||||||
"//common:test_utils",
|
"//common:test_utils",
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
#include "protos/public/errors.pb.h"
|
#include "protos/public/errors.pb.h"
|
||||||
#include "protos/public/license_protocol.pb.h"
|
#include "protos/public/license_protocol.pb.h"
|
||||||
|
|
||||||
namespace util = widevine::util;
|
|
||||||
using widevine::DRM_DEVICE_CERTIFICATE_REVOKED;
|
using widevine::DRM_DEVICE_CERTIFICATE_REVOKED;
|
||||||
using widevine::DrmServiceCertificate;
|
using widevine::DrmServiceCertificate;
|
||||||
using widevine::EXPIRED_CERTIFICATE_STATUS_LIST;
|
using widevine::EXPIRED_CERTIFICATE_STATUS_LIST;
|
||||||
@@ -26,7 +25,7 @@ using widevine::SERVICE_CERTIFICATE_REQUEST_MESSAGE;
|
|||||||
using widevine::SignedMessage;
|
using widevine::SignedMessage;
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
bool GenerateErrorResponse(const util::Status& create_session_status,
|
bool GenerateErrorResponse(const Status& create_session_status,
|
||||||
std::string* license_response) {
|
std::string* license_response) {
|
||||||
DCHECK(license_response);
|
DCHECK(license_response);
|
||||||
|
|
||||||
@@ -61,9 +60,8 @@ bool GenerateErrorResponse(const util::Status& create_session_status,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((create_session_status.error_space() ==
|
if ((create_session_status.error_space() == Status::canonical_space()) &&
|
||||||
util::Status::canonical_space()) &&
|
(create_session_status.error_code() == error::UNAVAILABLE)) {
|
||||||
(create_session_status.error_code() == util::error::UNAVAILABLE)) {
|
|
||||||
error_proto.set_error_code(LicenseError::SERVICE_UNAVAILABLE);
|
error_proto.set_error_code(LicenseError::SERVICE_UNAVAILABLE);
|
||||||
}
|
}
|
||||||
if (!error_proto.has_error_code()) {
|
if (!error_proto.has_error_code()) {
|
||||||
|
|||||||
@@ -11,17 +11,16 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "util/status.h"
|
#include "common/status.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
// Generates a SignedMessage containing a message generated in response to
|
// Generates a SignedMessage containing a message generated in response to
|
||||||
// an error condition. |status| is a previous error status returned by the
|
// an error condition. |status| is a previous error status returned by the
|
||||||
// Session or util::Status(util::error::UNAVAILABLE, ...) to indicate that the
|
// Session or Status(error::UNAVAILABLE, ...) to indicate that the
|
||||||
// backend is unavailable, |signed_message| points to a std::string to contain the
|
// backend is unavailable, |signed_message| points to a std::string to contain the
|
||||||
// serialized SignedMessage, and may not be NULL. This method returns true if
|
// serialized SignedMessage, and may not be NULL. This method returns true if
|
||||||
// there is an error license to be sent to the client, or false otherwise.
|
// there is an error license to be sent to the client, or false otherwise.
|
||||||
// Example usage in the Session::Create comments above.
|
// Example usage in the Session::Create comments above.
|
||||||
bool GenerateErrorResponse(const util::Status& status,
|
bool GenerateErrorResponse(const Status& status, std::string* license_response);
|
||||||
std::string* license_response);
|
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
#endif // LICENSE_SERVER_SDK_INTERNAL_GENERATE_ERROR_RESPONSE_H_
|
#endif // LICENSE_SERVER_SDK_INTERNAL_GENERATE_ERROR_RESPONSE_H_
|
||||||
|
|||||||
@@ -37,19 +37,18 @@ void AddKeyIdIfNotFound(const std::string& key_id,
|
|||||||
entry->add_key_ids(key_id);
|
entry->add_key_ids(key_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status AddWidevinePsshInfo(
|
Status AddWidevinePsshInfo(const std::string& pssh_data,
|
||||||
const std::string& pssh_data,
|
ContentInfo::ContentInfoEntry* content_info_entry) {
|
||||||
ContentInfo::ContentInfoEntry* content_info_entry) {
|
|
||||||
if (pssh_data.empty()) {
|
if (pssh_data.empty()) {
|
||||||
return util::Status(error_space, INVALID_WIDEVINE_PSSH_DATA,
|
return Status(error_space, INVALID_WIDEVINE_PSSH_DATA,
|
||||||
"widevine-pssh-data-is-empty");
|
"widevine-pssh-data-is-empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!content_info_entry->mutable_pssh()
|
if (!content_info_entry->mutable_pssh()
|
||||||
->mutable_widevine_data()
|
->mutable_widevine_data()
|
||||||
->ParseFromString(pssh_data)) {
|
->ParseFromString(pssh_data)) {
|
||||||
return util::Status(error_space, INVALID_WIDEVINE_PSSH_DATA,
|
return Status(error_space, INVALID_WIDEVINE_PSSH_DATA,
|
||||||
"invalid-widevine-pssh-data");
|
"invalid-widevine-pssh-data");
|
||||||
}
|
}
|
||||||
content_info_entry->mutable_pssh()->set_system_id(
|
content_info_entry->mutable_pssh()->set_system_id(
|
||||||
std::string(kWidevineSystemId, kWidevineSystemId + sizeof(kWidevineSystemId)));
|
std::string(kWidevineSystemId, kWidevineSystemId + sizeof(kWidevineSystemId)));
|
||||||
@@ -58,39 +57,37 @@ util::Status AddWidevinePsshInfo(
|
|||||||
for (int idx = 0; idx < wv_pssh.key_ids_size(); ++idx)
|
for (int idx = 0; idx < wv_pssh.key_ids_size(); ++idx)
|
||||||
AddKeyIdIfNotFound(wv_pssh.key_ids(idx), content_info_entry);
|
AddKeyIdIfNotFound(wv_pssh.key_ids(idx), content_info_entry);
|
||||||
|
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status ParseCencId(
|
Status ParseCencId(const LicenseRequest::ContentIdentification& content_id,
|
||||||
const LicenseRequest::ContentIdentification& content_id,
|
ContentInfo* content_info) {
|
||||||
ContentInfo* content_info) {
|
|
||||||
content_info->set_init_data_type(
|
content_info->set_init_data_type(
|
||||||
LicenseRequest::ContentIdentification::InitData::CENC);
|
LicenseRequest::ContentIdentification::InitData::CENC);
|
||||||
for (int idx = 0; idx < content_id.cenc_id_deprecated().pssh_size(); ++idx) {
|
for (int idx = 0; idx < content_id.cenc_id_deprecated().pssh_size(); ++idx) {
|
||||||
util::Status status =
|
Status status =
|
||||||
AddWidevinePsshInfo(content_id.cenc_id_deprecated().pssh(idx),
|
AddWidevinePsshInfo(content_id.cenc_id_deprecated().pssh(idx),
|
||||||
content_info->add_content_info_entry());
|
content_info->add_content_info_entry());
|
||||||
if (!status.ok()) return status;
|
if (!status.ok()) return status;
|
||||||
}
|
}
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status AddWebmKeyId(const std::string& key_id, ContentInfo* content_info) {
|
Status AddWebmKeyId(const std::string& key_id, ContentInfo* content_info) {
|
||||||
content_info->set_init_data_type(
|
content_info->set_init_data_type(
|
||||||
LicenseRequest::ContentIdentification::InitData::WEBM);
|
LicenseRequest::ContentIdentification::InitData::WEBM);
|
||||||
content_info->add_content_info_entry()->add_key_ids(key_id);
|
content_info->add_content_info_entry()->add_key_ids(key_id);
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status ParseIsoBmffBoxes(const std::string& boxes, ContentInfo* content_info) {
|
Status ParseIsoBmffBoxes(const std::string& boxes, ContentInfo* content_info) {
|
||||||
const uint32_t kPsshType = 0x70737368;
|
const uint32_t kPsshType = 0x70737368;
|
||||||
const size_t kPsshSystemIdSize = 16;
|
const size_t kPsshSystemIdSize = 16;
|
||||||
const size_t kKeyIdSize = 16;
|
const size_t kKeyIdSize = 16;
|
||||||
const size_t kMinPsshSize = kPsshSystemIdSize + 8;
|
const size_t kMinPsshSize = kPsshSystemIdSize + 8;
|
||||||
|
|
||||||
if (boxes.empty()) {
|
if (boxes.empty()) {
|
||||||
return util::Status(error_space, INVALID_CENC_INIT_DATA,
|
return Status(error_space, INVALID_CENC_INIT_DATA, "init-data-is-empty");
|
||||||
"init-data-is-empty");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* r_ptr = boxes.data();
|
const char* r_ptr = boxes.data();
|
||||||
@@ -100,8 +97,7 @@ util::Status ParseIsoBmffBoxes(const std::string& boxes, ContentInfo* content_in
|
|||||||
ContentInfo::ContentInfoEntry content_info_entry;
|
ContentInfo::ContentInfoEntry content_info_entry;
|
||||||
|
|
||||||
if (r_ptr + 8 > end_ptr)
|
if (r_ptr + 8 > end_ptr)
|
||||||
return util::Status(error_space, INVALID_CENC_INIT_DATA,
|
return Status(error_space, INVALID_CENC_INIT_DATA, "init-data-too-short");
|
||||||
"init-data-too-short");
|
|
||||||
|
|
||||||
const char* box_start = r_ptr;
|
const char* box_start = r_ptr;
|
||||||
uint64_t box_size = BigEndian::Load32(r_ptr);
|
uint64_t box_size = BigEndian::Load32(r_ptr);
|
||||||
@@ -111,8 +107,8 @@ util::Status ParseIsoBmffBoxes(const std::string& boxes, ContentInfo* content_in
|
|||||||
|
|
||||||
if (box_size == 1) {
|
if (box_size == 1) {
|
||||||
if (r_ptr + 8 > end_ptr) {
|
if (r_ptr + 8 > end_ptr) {
|
||||||
return util::Status(error_space, INVALID_CENC_INIT_DATA,
|
return Status(error_space, INVALID_CENC_INIT_DATA,
|
||||||
"init-data-too-short");
|
"init-data-too-short");
|
||||||
}
|
}
|
||||||
box_size = BigEndian::Load64(r_ptr);
|
box_size = BigEndian::Load64(r_ptr);
|
||||||
r_ptr += 8;
|
r_ptr += 8;
|
||||||
@@ -120,12 +116,10 @@ util::Status ParseIsoBmffBoxes(const std::string& boxes, ContentInfo* content_in
|
|||||||
|
|
||||||
const char* box_end = box_start + box_size;
|
const char* box_end = box_start + box_size;
|
||||||
if (box_end > end_ptr) {
|
if (box_end > end_ptr) {
|
||||||
return util::Status(error_space, INVALID_CENC_INIT_DATA,
|
return Status(error_space, INVALID_CENC_INIT_DATA, "init-data-too-short");
|
||||||
"init-data-too-short");
|
|
||||||
}
|
}
|
||||||
if (box_end < r_ptr) {
|
if (box_end < r_ptr) {
|
||||||
return util::Status(error_space, INVALID_CENC_INIT_DATA,
|
return Status(error_space, INVALID_CENC_INIT_DATA, "invalid-box-size");
|
||||||
"invalid-box-size");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (box_type != kPsshType) {
|
if (box_type != kPsshType) {
|
||||||
@@ -134,15 +128,15 @@ util::Status ParseIsoBmffBoxes(const std::string& boxes, ContentInfo* content_in
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (r_ptr + kMinPsshSize > box_end)
|
if (r_ptr + kMinPsshSize > box_end)
|
||||||
return util::Status(error_space, INVALID_PSSH, "pssh-contents-too-short");
|
return Status(error_space, INVALID_PSSH, "pssh-contents-too-short");
|
||||||
|
|
||||||
const uint32_t version_and_flags = BigEndian::Load32(r_ptr);
|
const uint32_t version_and_flags = BigEndian::Load32(r_ptr);
|
||||||
r_ptr += 4;
|
r_ptr += 4;
|
||||||
|
|
||||||
const uint8_t version = static_cast<uint8_t>(version_and_flags >> 24);
|
const uint8_t version = static_cast<uint8_t>(version_and_flags >> 24);
|
||||||
if (version > 1) {
|
if (version > 1) {
|
||||||
return util::Status(error_space, UNSUPPORTED_PSSH_VERSION,
|
return Status(error_space, UNSUPPORTED_PSSH_VERSION,
|
||||||
absl::StrCat("unsupported-pssh-version ", version));
|
absl::StrCat("unsupported-pssh-version ", version));
|
||||||
}
|
}
|
||||||
|
|
||||||
content_info_entry.mutable_pssh()->set_system_id(
|
content_info_entry.mutable_pssh()->set_system_id(
|
||||||
@@ -153,16 +147,14 @@ util::Status ParseIsoBmffBoxes(const std::string& boxes, ContentInfo* content_in
|
|||||||
|
|
||||||
if (version == 1) {
|
if (version == 1) {
|
||||||
if (r_ptr + 4 > box_end) {
|
if (r_ptr + 4 > box_end) {
|
||||||
return util::Status(error_space, INVALID_PSSH,
|
return Status(error_space, INVALID_PSSH, "pssh-contents-too-short");
|
||||||
"pssh-contents-too-short");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint32_t num_key_ids = BigEndian::Load32(r_ptr);
|
const uint32_t num_key_ids = BigEndian::Load32(r_ptr);
|
||||||
r_ptr += 4;
|
r_ptr += 4;
|
||||||
|
|
||||||
if (r_ptr + (num_key_ids * kKeyIdSize) > box_end) {
|
if (r_ptr + (num_key_ids * kKeyIdSize) > box_end) {
|
||||||
return util::Status(error_space, INVALID_PSSH,
|
return Status(error_space, INVALID_PSSH, "pssh-contents-too-short");
|
||||||
"pssh-contents-too-short");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t idx = 0; idx < num_key_ids; ++idx) {
|
for (uint32_t idx = 0; idx < num_key_ids; ++idx) {
|
||||||
@@ -173,18 +165,18 @@ util::Status ParseIsoBmffBoxes(const std::string& boxes, ContentInfo* content_in
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (r_ptr + 4 > box_end)
|
if (r_ptr + 4 > box_end)
|
||||||
return util::Status(error_space, INVALID_PSSH, "pssh-contents-too-short");
|
return Status(error_space, INVALID_PSSH, "pssh-contents-too-short");
|
||||||
|
|
||||||
uint32_t data_size = BigEndian::Load32(r_ptr);
|
uint32_t data_size = BigEndian::Load32(r_ptr);
|
||||||
r_ptr += 4;
|
r_ptr += 4;
|
||||||
if (r_ptr + data_size > box_end)
|
if (r_ptr + data_size > box_end)
|
||||||
return util::Status(error_space, INVALID_PSSH, "pssh-contents-too-short");
|
return Status(error_space, INVALID_PSSH, "pssh-contents-too-short");
|
||||||
if (r_ptr + data_size < box_end)
|
if (r_ptr + data_size < box_end)
|
||||||
return util::Status(error_space, INVALID_PSSH, "pssh-contents-too-long");
|
return Status(error_space, INVALID_PSSH, "pssh-contents-too-long");
|
||||||
|
|
||||||
if (is_widevine_pssh) {
|
if (is_widevine_pssh) {
|
||||||
util::Status status = AddWidevinePsshInfo(
|
Status status = AddWidevinePsshInfo(std::string(r_ptr, r_ptr + data_size),
|
||||||
std::string(r_ptr, r_ptr + data_size), &content_info_entry);
|
&content_info_entry);
|
||||||
if (!status.ok()) return status;
|
if (!status.ok()) return status;
|
||||||
} else {
|
} else {
|
||||||
content_info_entry.mutable_pssh()->set_raw_data(
|
content_info_entry.mutable_pssh()->set_raw_data(
|
||||||
@@ -195,14 +187,13 @@ util::Status ParseIsoBmffBoxes(const std::string& boxes, ContentInfo* content_in
|
|||||||
*content_info->add_content_info_entry() = content_info_entry;
|
*content_info->add_content_info_entry() = content_info_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status ParseInitData(
|
Status ParseInitData(const LicenseRequest::ContentIdentification& content_id,
|
||||||
const LicenseRequest::ContentIdentification& content_id,
|
ContentInfo* content_info) {
|
||||||
ContentInfo* content_info) {
|
|
||||||
if (!content_id.init_data().has_init_data())
|
if (!content_id.init_data().has_init_data())
|
||||||
return util::Status(error_space, MISSING_INIT_DATA, "missing-init-data");
|
return Status(error_space, MISSING_INIT_DATA, "missing-init-data");
|
||||||
|
|
||||||
if (content_id.init_data().init_data_type() ==
|
if (content_id.init_data().init_data_type() ==
|
||||||
LicenseRequest::ContentIdentification::InitData::CENC) {
|
LicenseRequest::ContentIdentification::InitData::CENC) {
|
||||||
@@ -212,15 +203,13 @@ util::Status ParseInitData(
|
|||||||
LicenseRequest::ContentIdentification::InitData::WEBM) {
|
LicenseRequest::ContentIdentification::InitData::WEBM) {
|
||||||
return AddWebmKeyId(content_id.init_data().init_data(), content_info);
|
return AddWebmKeyId(content_id.init_data().init_data(), content_info);
|
||||||
}
|
}
|
||||||
return util::Status(error_space, UNKNOWN_INIT_DATA_TYPE,
|
return Status(error_space, UNKNOWN_INIT_DATA_TYPE, "unknown-init-data-type");
|
||||||
"unknown-init-data-type");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
util::Status ParseContentId(
|
Status ParseContentId(const LicenseRequest::ContentIdentification& content_id,
|
||||||
const LicenseRequest::ContentIdentification& content_id,
|
ContentInfo* content_info) {
|
||||||
ContentInfo* content_info) {
|
|
||||||
DCHECK(content_info);
|
DCHECK(content_info);
|
||||||
|
|
||||||
content_info->Clear();
|
content_info->Clear();
|
||||||
@@ -235,8 +224,8 @@ util::Status ParseContentId(
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return util::Status(error_space, INVALID_CONTENT_ID_TYPE,
|
return Status(error_space, INVALID_CONTENT_ID_TYPE,
|
||||||
"invalid-content-id-type");
|
"invalid-content-id-type");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#ifndef LICENSE_SERVER_SDK_INTERNAL_PARSE_CONTENT_ID_H__
|
#ifndef LICENSE_SERVER_SDK_INTERNAL_PARSE_CONTENT_ID_H__
|
||||||
#define LICENSE_SERVER_SDK_INTERNAL_PARSE_CONTENT_ID_H__
|
#define LICENSE_SERVER_SDK_INTERNAL_PARSE_CONTENT_ID_H__
|
||||||
|
|
||||||
#include "util/status.h"
|
#include "common/status.h"
|
||||||
#include "protos/public/license_protocol.pb.h"
|
#include "protos/public/license_protocol.pb.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
@@ -20,9 +20,8 @@ class ContentInfo;
|
|||||||
// the ContentInfo message passed into |content_info|. This function deep parses
|
// the ContentInfo message passed into |content_info|. This function deep parses
|
||||||
// PSSH boxes and the Widevine PSSH Data. |content_info| may not be NULL and the
|
// PSSH boxes and the Widevine PSSH Data. |content_info| may not be NULL and the
|
||||||
// caller retains ownership.
|
// caller retains ownership.
|
||||||
util::Status ParseContentId(
|
Status ParseContentId(const LicenseRequest::ContentIdentification& content_id,
|
||||||
const LicenseRequest::ContentIdentification& content_id,
|
ContentInfo* content_info);
|
||||||
ContentInfo* content_info);
|
|
||||||
|
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
|
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ void MakeInitDataWebmContentId(
|
|||||||
void VerifyWebmContentId(
|
void VerifyWebmContentId(
|
||||||
const LicenseRequest::ContentIdentification& content_id) {
|
const LicenseRequest::ContentIdentification& content_id) {
|
||||||
ContentInfo content_info;
|
ContentInfo content_info;
|
||||||
ASSERT_EQ(util::OkStatus(), ParseContentId(content_id, &content_info));
|
ASSERT_EQ(OkStatus(), ParseContentId(content_id, &content_info));
|
||||||
ASSERT_EQ(LicenseRequest::ContentIdentification::InitData::WEBM,
|
ASSERT_EQ(LicenseRequest::ContentIdentification::InitData::WEBM,
|
||||||
content_info.init_data_type());
|
content_info.init_data_type());
|
||||||
ASSERT_EQ(1, content_info.content_info_entry_size());
|
ASSERT_EQ(1, content_info.content_info_entry_size());
|
||||||
@@ -140,7 +140,7 @@ void MakeExistingLicenseContentId(
|
|||||||
void VerifyCencContentId(
|
void VerifyCencContentId(
|
||||||
const LicenseRequest::ContentIdentification& content_id) {
|
const LicenseRequest::ContentIdentification& content_id) {
|
||||||
ContentInfo content_info;
|
ContentInfo content_info;
|
||||||
ASSERT_EQ(util::OkStatus(), ParseContentId(content_id, &content_info));
|
ASSERT_EQ(OkStatus(), ParseContentId(content_id, &content_info));
|
||||||
ASSERT_EQ(LicenseRequest::ContentIdentification::InitData::CENC,
|
ASSERT_EQ(LicenseRequest::ContentIdentification::InitData::CENC,
|
||||||
content_info.init_data_type());
|
content_info.init_data_type());
|
||||||
ASSERT_EQ(1, content_info.content_info_entry_size());
|
ASSERT_EQ(1, content_info.content_info_entry_size());
|
||||||
@@ -194,7 +194,7 @@ TEST(ParseContentIdTest, PsshV1) {
|
|||||||
MakeInitDataCencContentId(std::string(kWvPsshV1, kWvPsshV1 + sizeof(kWvPsshV1)),
|
MakeInitDataCencContentId(std::string(kWvPsshV1, kWvPsshV1 + sizeof(kWvPsshV1)),
|
||||||
&content_id);
|
&content_id);
|
||||||
ContentInfo content_info;
|
ContentInfo content_info;
|
||||||
EXPECT_EQ(util::OkStatus(), ParseContentId(content_id, &content_info));
|
EXPECT_EQ(OkStatus(), ParseContentId(content_id, &content_info));
|
||||||
EXPECT_EQ(LicenseRequest::ContentIdentification::InitData::CENC,
|
EXPECT_EQ(LicenseRequest::ContentIdentification::InitData::CENC,
|
||||||
content_info.init_data_type());
|
content_info.init_data_type());
|
||||||
ASSERT_EQ(1, content_info.content_info_entry_size());
|
ASSERT_EQ(1, content_info.content_info_entry_size());
|
||||||
@@ -210,9 +210,9 @@ TEST(ParseContentIdTest, ExistingLicense) {
|
|||||||
LicenseRequest::ContentIdentification content_id;
|
LicenseRequest::ContentIdentification content_id;
|
||||||
ContentInfo content_info;
|
ContentInfo content_info;
|
||||||
MakeExistingLicenseContentId(&content_id);
|
MakeExistingLicenseContentId(&content_id);
|
||||||
EXPECT_EQ(util::Status(error_space, INVALID_CONTENT_ID_TYPE,
|
EXPECT_EQ(
|
||||||
"invalid-content-id-type"),
|
Status(error_space, INVALID_CONTENT_ID_TYPE, "invalid-content-id-type"),
|
||||||
ParseContentId(content_id, &content_info));
|
ParseContentId(content_id, &content_info));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ParseContentIdTest, MultipleBoxes) {
|
TEST(ParseContentIdTest, MultipleBoxes) {
|
||||||
@@ -227,7 +227,7 @@ TEST(ParseContentIdTest, MultipleBoxes) {
|
|||||||
std::string(kNonPsshBox, kNonPsshBox + sizeof(kNonPsshBox)),
|
std::string(kNonPsshBox, kNonPsshBox + sizeof(kNonPsshBox)),
|
||||||
&content_id);
|
&content_id);
|
||||||
ContentInfo content_info;
|
ContentInfo content_info;
|
||||||
EXPECT_EQ(util::OkStatus(), ParseContentId(content_id, &content_info));
|
EXPECT_EQ(OkStatus(), ParseContentId(content_id, &content_info));
|
||||||
EXPECT_EQ(LicenseRequest::ContentIdentification::InitData::CENC,
|
EXPECT_EQ(LicenseRequest::ContentIdentification::InitData::CENC,
|
||||||
content_info.init_data_type());
|
content_info.init_data_type());
|
||||||
EXPECT_EQ(3, content_info.content_info_entry_size());
|
EXPECT_EQ(3, content_info.content_info_entry_size());
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
#include "common/random_util.h"
|
#include "common/random_util.h"
|
||||||
#include "common/remote_attestation_verifier.h"
|
#include "common/remote_attestation_verifier.h"
|
||||||
#include "common/rsa_key.h"
|
#include "common/rsa_key.h"
|
||||||
|
#include "common/sha_util.h"
|
||||||
#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"
|
||||||
@@ -49,8 +50,8 @@ namespace widevine {
|
|||||||
|
|
||||||
// TODO(user): These constants are also defined in public/session.cc. Fix the
|
// TODO(user): These constants are also defined in public/session.cc. Fix the
|
||||||
// duplicate definitions.
|
// duplicate definitions.
|
||||||
const char* SessionImpl::kEncryptionKeyLabel = "ENCRYPTION";
|
const char* SessionImpl::kWrappingKeyLabel = "ENCRYPTION";
|
||||||
const uint32_t SessionImpl::kEncryptionKeySizeBits = 128;
|
const uint32_t SessionImpl::kWrappingKeySizeBits = 128;
|
||||||
const char* SessionImpl::kSigningKeyLabel = "AUTHENTICATION";
|
const char* SessionImpl::kSigningKeyLabel = "AUTHENTICATION";
|
||||||
const uint32_t SessionImpl::kSigningKeySizeBits = 256;
|
const uint32_t SessionImpl::kSigningKeySizeBits = 256;
|
||||||
bool SessionImpl::is_service_certificate_loaded_ = false;
|
bool SessionImpl::is_service_certificate_loaded_ = false;
|
||||||
@@ -90,12 +91,12 @@ void SessionImpl::SetPreProvisioningKeys(
|
|||||||
KeyboxClientCert::SetPreProvisioningKeys(keys);
|
KeyboxClientCert::SetPreProvisioningKeys(keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status SessionImpl::SetCertificateStatusList(
|
Status SessionImpl::SetCertificateStatusList(
|
||||||
const DrmRootCertificate* root_cert, 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) {
|
||||||
CHECK(root_cert);
|
CHECK(root_cert);
|
||||||
|
|
||||||
util::Status status = DeviceStatusList::Instance()->UpdateStatusList(
|
Status status = DeviceStatusList::Instance()->UpdateStatusList(
|
||||||
root_cert->public_key(), certificate_status_list,
|
root_cert->public_key(), certificate_status_list,
|
||||||
expiration_period_seconds);
|
expiration_period_seconds);
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
@@ -104,16 +105,16 @@ util::Status SessionImpl::SetCertificateStatusList(
|
|||||||
DeviceStatusList::Instance()->set_allow_unknown_devices(
|
DeviceStatusList::Instance()->set_allow_unknown_devices(
|
||||||
allow_unknown_devices);
|
allow_unknown_devices);
|
||||||
|
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status SessionImpl::AddDrmServiceCertificate(
|
Status SessionImpl::AddDrmServiceCertificate(
|
||||||
const DrmRootCertificate* root_cert, 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) {
|
||||||
CHECK(root_cert);
|
CHECK(root_cert);
|
||||||
|
|
||||||
util::Status status = DrmServiceCertificate::AddDrmServiceCertificate(
|
Status status = DrmServiceCertificate::AddDrmServiceCertificate(
|
||||||
root_cert, service_certificate, service_private_key,
|
root_cert, service_certificate, service_private_key,
|
||||||
service_private_key_passphrase);
|
service_private_key_passphrase);
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
@@ -134,24 +135,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 DrmRootCertificate* root_cert,
|
Status SessionImpl::Create(const DrmRootCertificate* root_cert,
|
||||||
const std::string& signed_license_request,
|
const std::string& signed_license_request,
|
||||||
SessionImpl** session) {
|
SessionImpl** session) {
|
||||||
if (!is_service_certificate_loaded_) {
|
if (!is_service_certificate_loaded_) {
|
||||||
return util::Status(error_space, SERVICE_CERTIFICATE_NOT_FOUND, "");
|
return Status(error_space, SERVICE_CERTIFICATE_NOT_FOUND, "");
|
||||||
}
|
}
|
||||||
return SessionImpl::Create(root_cert, signed_license_request, session,
|
return SessionImpl::Create(root_cert, signed_license_request, session,
|
||||||
nullptr);
|
nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status SessionImpl::Create(const DrmRootCertificate* root_cert,
|
Status SessionImpl::Create(const DrmRootCertificate* root_cert,
|
||||||
const std::string& signed_license_request,
|
const std::string& signed_license_request,
|
||||||
SessionImpl** session,
|
SessionImpl** session,
|
||||||
LicenseRequest* parsed_request_out) {
|
LicenseRequest* parsed_request_out) {
|
||||||
CHECK(root_cert);
|
CHECK(root_cert);
|
||||||
DCHECK(session);
|
DCHECK(session);
|
||||||
|
|
||||||
util::Status status;
|
Status status;
|
||||||
|
|
||||||
LicenseRequest* request_ptr = new LicenseRequest();
|
LicenseRequest* request_ptr = new LicenseRequest();
|
||||||
SignedMessage* signed_message_ptr = new SignedMessage();
|
SignedMessage* signed_message_ptr = new SignedMessage();
|
||||||
@@ -168,7 +169,7 @@ util::Status SessionImpl::Create(const DrmRootCertificate* root_cert,
|
|||||||
}
|
}
|
||||||
if (request->has_encrypted_client_id()) {
|
if (request->has_encrypted_client_id()) {
|
||||||
if (request->has_client_id()) {
|
if (request->has_client_id()) {
|
||||||
status = util::Status(error_space, MULTIPLE_CLIENT_ID, "");
|
status = Status(error_space, MULTIPLE_CLIENT_ID, "");
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
status = DrmServiceCertificate::DecryptClientIdentification(
|
status = DrmServiceCertificate::DecryptClientIdentification(
|
||||||
@@ -200,12 +201,12 @@ util::Status SessionImpl::Create(const DrmRootCertificate* root_cert,
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status SessionImpl::CreateForProxy(
|
Status SessionImpl::CreateForProxy(
|
||||||
const DrmRootCertificate* root_cert, 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) {
|
||||||
util::Status status(util::OkStatus());
|
Status status(OkStatus());
|
||||||
DCHECK(session);
|
DCHECK(session);
|
||||||
DCHECK(*session == nullptr);
|
DCHECK(*session == nullptr);
|
||||||
|
|
||||||
@@ -248,13 +249,13 @@ util::Status SessionImpl::CreateForProxy(
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status SessionImpl::LoadKeyControlNonce(const LicenseRequest& request,
|
Status SessionImpl::LoadKeyControlNonce(const LicenseRequest& request,
|
||||||
bool* has_key_control_nonce,
|
bool* has_key_control_nonce,
|
||||||
uint32_t* key_control_nonce) {
|
uint32_t* key_control_nonce) {
|
||||||
DCHECK(has_key_control_nonce);
|
DCHECK(has_key_control_nonce);
|
||||||
DCHECK(key_control_nonce);
|
DCHECK(key_control_nonce);
|
||||||
|
|
||||||
util::Status status;
|
Status status;
|
||||||
*has_key_control_nonce = false;
|
*has_key_control_nonce = false;
|
||||||
if (request.has_key_control_nonce()) {
|
if (request.has_key_control_nonce()) {
|
||||||
// Newer type uint32_t nonce.
|
// Newer type uint32_t nonce.
|
||||||
@@ -269,39 +270,38 @@ util::Status SessionImpl::LoadKeyControlNonce(const LicenseRequest& request,
|
|||||||
kc_nonce_string.resize(nul_pos);
|
kc_nonce_string.resize(nul_pos);
|
||||||
}
|
}
|
||||||
if (!absl::SimpleAtoi(kc_nonce_string, key_control_nonce)) {
|
if (!absl::SimpleAtoi(kc_nonce_string, key_control_nonce)) {
|
||||||
return util::Status(error_space, INVALID_KEY_CONTROL_NONCE,
|
return Status(error_space, INVALID_KEY_CONTROL_NONCE,
|
||||||
request.key_control_nonce_deprecated());
|
request.key_control_nonce_deprecated());
|
||||||
}
|
}
|
||||||
*has_key_control_nonce = true;
|
*has_key_control_nonce = true;
|
||||||
}
|
}
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status SessionImpl::CheckLicenseRequestFields(
|
Status SessionImpl::CheckLicenseRequestFields(const LicenseRequest& request) {
|
||||||
const LicenseRequest& request) {
|
|
||||||
if (request.type() == LicenseRequest::NEW) {
|
if (request.type() == LicenseRequest::NEW) {
|
||||||
if (!request.has_client_id()) {
|
if (!request.has_client_id()) {
|
||||||
return util::Status(error_space, MISSING_CLIENT_ID,
|
return Status(error_space, MISSING_CLIENT_ID,
|
||||||
"new-license-missing-client-id");
|
"new-license-missing-client-id");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!request.has_content_id()) {
|
if (!request.has_content_id()) {
|
||||||
return util::Status(error_space, MISSING_CONTENT_ID,
|
return Status(error_space, MISSING_CONTENT_ID,
|
||||||
"renew-release-license-missing-content-id");
|
"renew-release-license-missing-content-id");
|
||||||
}
|
}
|
||||||
if (!request.content_id().has_existing_license()) {
|
if (!request.content_id().has_existing_license()) {
|
||||||
return util::Status(error_space, MISSING_LICENSE_ID,
|
return Status(error_space, MISSING_LICENSE_ID,
|
||||||
"renew-release-license-missing-existing-license");
|
"renew-release-license-missing-existing-license");
|
||||||
}
|
}
|
||||||
if (!request.content_id().existing_license().has_license_id()) {
|
if (!request.content_id().existing_license().has_license_id()) {
|
||||||
return util::Status(error_space, MISSING_LICENSE_ID,
|
return Status(error_space, MISSING_LICENSE_ID,
|
||||||
"renew-release-license-missing-license-id");
|
"renew-release-license-missing-license-id");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status SessionImpl::ParseLicenseRequestFromString(
|
Status SessionImpl::ParseLicenseRequestFromString(
|
||||||
const std::string& signed_license_request, SignedMessage* signed_message,
|
const std::string& signed_license_request, SignedMessage* signed_message,
|
||||||
LicenseRequest* license_request) {
|
LicenseRequest* license_request) {
|
||||||
DCHECK(signed_message);
|
DCHECK(signed_message);
|
||||||
@@ -309,21 +309,20 @@ util::Status SessionImpl::ParseLicenseRequestFromString(
|
|||||||
|
|
||||||
// Deserialize the signed message
|
// Deserialize the signed message
|
||||||
if (!signed_message->ParseFromString(signed_license_request)) {
|
if (!signed_message->ParseFromString(signed_license_request)) {
|
||||||
return util::Status(error_space, SIGNED_MESSAGE_PARSE_ERROR, "");
|
return Status(error_space, SIGNED_MESSAGE_PARSE_ERROR, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signed_message->type() == SignedMessage::SERVICE_CERTIFICATE_REQUEST) {
|
if (signed_message->type() == SignedMessage::SERVICE_CERTIFICATE_REQUEST) {
|
||||||
return util::Status(error_space, SERVICE_CERTIFICATE_REQUEST_MESSAGE,
|
return Status(error_space, SERVICE_CERTIFICATE_REQUEST_MESSAGE, std::string());
|
||||||
std::string());
|
|
||||||
}
|
}
|
||||||
if (signed_message->type() != SignedMessage::LICENSE_REQUEST &&
|
if (signed_message->type() != SignedMessage::LICENSE_REQUEST &&
|
||||||
signed_message->type() != SignedMessage::CAS_LICENSE_REQUEST) {
|
signed_message->type() != SignedMessage::CAS_LICENSE_REQUEST) {
|
||||||
return util::Status(error_space, INVALID_MESSAGE_TYPE, std::string());
|
return Status(error_space, INVALID_MESSAGE_TYPE, std::string());
|
||||||
}
|
}
|
||||||
if (!license_request->ParseFromString(signed_message->msg())) {
|
if (!license_request->ParseFromString(signed_message->msg())) {
|
||||||
return util::Status(error_space, LICENSE_REQUEST_PARSE_ERROR, "");
|
return Status(error_space, LICENSE_REQUEST_PARSE_ERROR, "");
|
||||||
}
|
}
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SessionImpl::DeriveKey(const std::string& key, const std::string& label,
|
std::string SessionImpl::DeriveKey(const std::string& key, const std::string& label,
|
||||||
@@ -347,12 +346,12 @@ SessionImpl::SessionImpl(SignedMessage* message, LicenseRequest* request,
|
|||||||
|
|
||||||
SessionImpl::~SessionImpl() {}
|
SessionImpl::~SessionImpl() {}
|
||||||
|
|
||||||
util::Status SessionImpl::Init(const DrmRootCertificate* root_cert) {
|
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(
|
Status status = ClientCert::Create(
|
||||||
root_cert, 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);
|
||||||
@@ -365,8 +364,8 @@ util::Status SessionImpl::Init(const DrmRootCertificate* root_cert) {
|
|||||||
if (!client_cert_->service_id().empty() &&
|
if (!client_cert_->service_id().empty() &&
|
||||||
DrmServiceCertificate::GetDefaultDrmServiceCertificateOrDie()
|
DrmServiceCertificate::GetDefaultDrmServiceCertificateOrDie()
|
||||||
->provider_id() == client_cert_->service_id()) {
|
->provider_id() == client_cert_->service_id()) {
|
||||||
status = util::Status(error_space, PROVIDER_ID_MISMATCH,
|
status = Status(error_space, PROVIDER_ID_MISMATCH,
|
||||||
"client-cert-service-cert-id-mismatch");
|
"client-cert-service-cert-id-mismatch");
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
provisioned_device_info_.reset(new ProvisionedDeviceInfo);
|
provisioned_device_info_.reset(new ProvisionedDeviceInfo);
|
||||||
@@ -381,7 +380,7 @@ util::Status SessionImpl::Init(const DrmRootCertificate* root_cert) {
|
|||||||
// 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());
|
||||||
util::Status status = client_cert_->VerifySignature(
|
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());
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
@@ -393,7 +392,7 @@ util::Status SessionImpl::Init(const DrmRootCertificate* root_cert) {
|
|||||||
// proxy. platform_verification_status_ would either be set at the proxy
|
// proxy. platform_verification_status_ would either be set at the proxy
|
||||||
// or as result of calling VerifyPlatform().
|
// or as result of calling VerifyPlatform().
|
||||||
if (platform_verification_status_ == PLATFORM_NO_VERIFICATION) {
|
if (platform_verification_status_ == PLATFORM_NO_VERIFICATION) {
|
||||||
util::Status status = VerifyPlatform();
|
Status status = VerifyPlatform();
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
LOG(ERROR) << "Platform verification failed. Status: " << status
|
LOG(ERROR) << "Platform verification failed. Status: " << status
|
||||||
<< ", License Request: "
|
<< ", License Request: "
|
||||||
@@ -401,7 +400,7 @@ util::Status SessionImpl::Init(const DrmRootCertificate* root_cert) {
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& SessionImpl::GetSessionId() {
|
const std::string& SessionImpl::GetSessionId() {
|
||||||
@@ -428,75 +427,76 @@ bool SessionImpl::GetProvisionedDeviceInfo(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status SessionImpl::GetRequestId(std::string* request_id) const {
|
Status SessionImpl::GetRequestId(std::string* request_id) const {
|
||||||
DCHECK(request_id);
|
DCHECK(request_id);
|
||||||
DCHECK(license_request_);
|
DCHECK(license_request_);
|
||||||
|
|
||||||
if (!license_request_->has_content_id())
|
if (!license_request_->has_content_id())
|
||||||
return util::Status(error_space, MISSING_CONTENT_ID, "missing-content-id");
|
return Status(error_space, MISSING_CONTENT_ID, "missing-content-id");
|
||||||
|
|
||||||
const LicenseRequest::ContentIdentification& content_id =
|
const LicenseRequest::ContentIdentification& content_id =
|
||||||
license_request_->content_id();
|
license_request_->content_id();
|
||||||
if (content_id.has_init_data()) {
|
if (content_id.has_init_data()) {
|
||||||
*request_id = content_id.init_data().request_id();
|
*request_id = content_id.init_data().request_id();
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
if (content_id.has_cenc_id_deprecated()) {
|
if (content_id.has_cenc_id_deprecated()) {
|
||||||
*request_id = content_id.cenc_id_deprecated().request_id();
|
*request_id = content_id.cenc_id_deprecated().request_id();
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
if (content_id.has_webm_id_deprecated()) {
|
if (content_id.has_webm_id_deprecated()) {
|
||||||
*request_id = content_id.webm_id_deprecated().request_id();
|
*request_id = content_id.webm_id_deprecated().request_id();
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
return util::Status(error_space, INVALID_CONTENT_ID_TYPE,
|
return Status(error_space, INVALID_CONTENT_ID_TYPE,
|
||||||
"invalid-content-id-type");
|
"invalid-content-id-type");
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status SessionImpl::GetLicenseType(LicenseType* license_type) const {
|
Status SessionImpl::GetLicenseType(LicenseType* license_type) const {
|
||||||
DCHECK(license_type);
|
DCHECK(license_type);
|
||||||
|
|
||||||
if (!license_request_->has_content_id())
|
if (!license_request_->has_content_id())
|
||||||
return util::Status(error_space, MISSING_CONTENT_ID, "missing-content-id");
|
return Status(error_space, MISSING_CONTENT_ID, "missing-content-id");
|
||||||
|
|
||||||
const LicenseRequest::ContentIdentification& content_id =
|
const LicenseRequest::ContentIdentification& content_id =
|
||||||
license_request_->content_id();
|
license_request_->content_id();
|
||||||
if (content_id.has_init_data()) {
|
if (content_id.has_init_data()) {
|
||||||
*license_type = content_id.init_data().license_type();
|
*license_type = content_id.init_data().license_type();
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
if (content_id.has_cenc_id_deprecated()) {
|
if (content_id.has_cenc_id_deprecated()) {
|
||||||
*license_type = content_id.cenc_id_deprecated().license_type();
|
*license_type = content_id.cenc_id_deprecated().license_type();
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
if (content_id.has_webm_id_deprecated()) {
|
if (content_id.has_webm_id_deprecated()) {
|
||||||
*license_type = content_id.webm_id_deprecated().license_type();
|
*license_type = content_id.webm_id_deprecated().license_type();
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
if (content_id.has_existing_license()) {
|
if (content_id.has_existing_license()) {
|
||||||
*license_type = content_id.existing_license().license_id().type();
|
*license_type = content_id.existing_license().license_id().type();
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
return util::Status(error_space, INVALID_CONTENT_ID_TYPE,
|
return Status(error_space, INVALID_CONTENT_ID_TYPE,
|
||||||
"invalid-content-id-type");
|
"invalid-content-id-type");
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status SessionImpl::GetContentInfo(ContentInfo* content_info) const {
|
Status SessionImpl::GetContentInfo(ContentInfo* content_info) const {
|
||||||
DCHECK(content_info);
|
DCHECK(content_info);
|
||||||
if (!license_request_->has_content_id())
|
if (!license_request_->has_content_id())
|
||||||
return util::Status(error_space, MISSING_CONTENT_ID, "missing-content-id");
|
return Status(error_space, MISSING_CONTENT_ID, "missing-content-id");
|
||||||
|
|
||||||
return ParseContentId(license_request_->content_id(), content_info);
|
return ParseContentId(license_request_->content_id(), content_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status SessionImpl::GenerateNewLicenseInfo(
|
Status SessionImpl::GenerateNewLicenseInfo(const SessionInit* session_init,
|
||||||
const SessionInit* session_init, LicenseIdentification* new_id,
|
LicenseIdentification* new_id,
|
||||||
std::string* renewal_signing_key, std::string* signing_key) {
|
std::string* renewal_signing_key,
|
||||||
|
std::string* signing_key) {
|
||||||
DCHECK(new_id);
|
DCHECK(new_id);
|
||||||
DCHECK(renewal_signing_key);
|
DCHECK(renewal_signing_key);
|
||||||
DCHECK(signing_key);
|
DCHECK(signing_key);
|
||||||
std::string request_id;
|
std::string request_id;
|
||||||
util::Status status = GetRequestId(&request_id);
|
Status status = GetRequestId(&request_id);
|
||||||
if (!status.ok()) return status;
|
if (!status.ok()) return status;
|
||||||
new_id->set_request_id(request_id);
|
new_id->set_request_id(request_id);
|
||||||
|
|
||||||
@@ -512,7 +512,7 @@ util::Status SessionImpl::GenerateNewLicenseInfo(
|
|||||||
// GetSessionID().
|
// GetSessionID().
|
||||||
if (session_init && session_init->has_session_id()) {
|
if (session_init && session_init->has_session_id()) {
|
||||||
if (!session_id_.empty() && (session_id_ != session_init->session_id())) {
|
if (!session_id_.empty() && (session_id_ != session_init->session_id())) {
|
||||||
status = util::Status(error_space, SESSION_ID_MISMATCH, "");
|
status = Status(error_space, SESSION_ID_MISMATCH, "");
|
||||||
} else {
|
} else {
|
||||||
new_id->set_session_id(session_init->session_id());
|
new_id->set_session_id(session_init->session_id());
|
||||||
}
|
}
|
||||||
@@ -540,12 +540,12 @@ util::Status SessionImpl::GenerateNewLicenseInfo(
|
|||||||
if (!status.ok()) return status;
|
if (!status.ok()) return status;
|
||||||
|
|
||||||
uint32_t signing_key_material_size_bytes =
|
uint32_t signing_key_material_size_bytes =
|
||||||
SigningKeyMaterialSize(license_request_->protocol_version()) / 8;
|
SigningKeyMaterialSizeBits(license_request_->protocol_version()) / 8;
|
||||||
if (session_init) {
|
if (session_init) {
|
||||||
if (session_init->has_signing_key()) {
|
if (session_init->has_signing_key()) {
|
||||||
if (session_init->signing_key().size() !=
|
if (session_init->signing_key().size() !=
|
||||||
signing_key_material_size_bytes) {
|
signing_key_material_size_bytes) {
|
||||||
status = util::Status(error_space, INVALID_SIGNING_KEY_SIZE, "");
|
status = Status(error_space, INVALID_SIGNING_KEY_SIZE, "");
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
*renewal_signing_key = session_init->signing_key();
|
*renewal_signing_key = session_init->signing_key();
|
||||||
@@ -555,35 +555,37 @@ util::Status SessionImpl::GenerateNewLicenseInfo(
|
|||||||
} else if (session_init->has_master_signing_key()) {
|
} else if (session_init->has_master_signing_key()) {
|
||||||
if (session_init->master_signing_key().size() !=
|
if (session_init->master_signing_key().size() !=
|
||||||
kMasterSigningKeySizeBytes) {
|
kMasterSigningKeySizeBytes) {
|
||||||
status =
|
status = Status(error_space, INVALID_MASTER_SIGNING_KEY_SIZE, "");
|
||||||
util::Status(error_space, INVALID_MASTER_SIGNING_KEY_SIZE, "");
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
std::string context;
|
std::string context;
|
||||||
if (new_id->SerializeToString(&context)) {
|
if (new_id->SerializeToString(&context)) {
|
||||||
*renewal_signing_key = DeriveKey(
|
*renewal_signing_key = DeriveKey(
|
||||||
session_init->master_signing_key(), std::string(kSigningKeyLabel),
|
session_init->master_signing_key(), std::string(kSigningKeyLabel),
|
||||||
context,
|
license_request_->protocol_version() < VERSION_2_2
|
||||||
SigningKeyMaterialSize(license_request_->protocol_version()));
|
? context
|
||||||
|
: Sha512_Hash(context),
|
||||||
|
SigningKeyMaterialSizeBits(license_request_->protocol_version()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
using crypto_util::kSigningKeySizeBytes;
|
using crypto_util::kSigningKeySizeBytes;
|
||||||
if (!renewal_signing_key->empty() &&
|
if (!renewal_signing_key->empty() &&
|
||||||
renewal_signing_key->size() != signing_key_material_size_bytes) {
|
renewal_signing_key->size() != signing_key_material_size_bytes) {
|
||||||
status = util::Status(error_space, INVALID_RENEWAL_SIGNING_KEY_SIZE, "");
|
status = Status(error_space, INVALID_RENEWAL_SIGNING_KEY_SIZE, "");
|
||||||
}
|
}
|
||||||
new_id->set_version(0);
|
new_id->set_version(0);
|
||||||
*signing_key = client_cert_->signing_key();
|
*signing_key = client_cert_->signing_key();
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status SessionImpl::GeneratePriorLicenseInfo(
|
Status SessionImpl::GeneratePriorLicenseInfo(const SessionInit* session_init,
|
||||||
const SessionInit* session_init, SessionState* session_state,
|
SessionState* session_state,
|
||||||
LicenseIdentification* new_id, std::string* signing_key) {
|
LicenseIdentification* new_id,
|
||||||
|
std::string* signing_key) {
|
||||||
DCHECK(new_id);
|
DCHECK(new_id);
|
||||||
DCHECK(signing_key);
|
DCHECK(signing_key);
|
||||||
util::Status status;
|
Status status;
|
||||||
if (session_state) {
|
if (session_state) {
|
||||||
// If the session_state is provided, we expect to have the previous
|
// If the session_state is provided, we expect to have the previous
|
||||||
// LicenseIdentification to compare against.
|
// LicenseIdentification to compare against.
|
||||||
@@ -600,7 +602,7 @@ util::Status SessionImpl::GeneratePriorLicenseInfo(
|
|||||||
!google::protobuf::util::MessageDifferencer::Equals(
|
!google::protobuf::util::MessageDifferencer::Equals(
|
||||||
license_request_->content_id().existing_license().license_id(),
|
license_request_->content_id().existing_license().license_id(),
|
||||||
session_state->license_id())) {
|
session_state->license_id())) {
|
||||||
status = util::Status(error_space, RENEWAL_LICENSE_ID_MISMATCH, "");
|
status = Status(error_space, RENEWAL_LICENSE_ID_MISMATCH, "");
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -619,18 +621,17 @@ util::Status SessionImpl::GeneratePriorLicenseInfo(
|
|||||||
} else if (session_init) {
|
} else if (session_init) {
|
||||||
if (session_init->has_signing_key()) {
|
if (session_init->has_signing_key()) {
|
||||||
uint32_t signing_key_material_size_bytes =
|
uint32_t signing_key_material_size_bytes =
|
||||||
SigningKeyMaterialSize(license_request_->protocol_version()) / 8;
|
SigningKeyMaterialSizeBits(license_request_->protocol_version()) / 8;
|
||||||
if (session_init->signing_key().size() !=
|
if (session_init->signing_key().size() !=
|
||||||
signing_key_material_size_bytes) {
|
signing_key_material_size_bytes) {
|
||||||
status = util::Status(error_space, INVALID_SIGNING_KEY_SIZE, "");
|
status = Status(error_space, INVALID_SIGNING_KEY_SIZE, "");
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
*signing_key = session_init->signing_key();
|
*signing_key = session_init->signing_key();
|
||||||
} else if (session_init->has_master_signing_key()) {
|
} else if (session_init->has_master_signing_key()) {
|
||||||
if (session_init->master_signing_key().size() !=
|
if (session_init->master_signing_key().size() !=
|
||||||
kMasterSigningKeySizeBytes) {
|
kMasterSigningKeySizeBytes) {
|
||||||
status =
|
status = Status(error_space, INVALID_MASTER_SIGNING_KEY_SIZE, "");
|
||||||
util::Status(error_space, INVALID_MASTER_SIGNING_KEY_SIZE, "");
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
LicenseIdentification id;
|
LicenseIdentification id;
|
||||||
@@ -641,20 +642,22 @@ util::Status SessionImpl::GeneratePriorLicenseInfo(
|
|||||||
if (id.SerializeToString(&context)) {
|
if (id.SerializeToString(&context)) {
|
||||||
*signing_key = DeriveKey(
|
*signing_key = DeriveKey(
|
||||||
session_init->master_signing_key(), std::string(kSigningKeyLabel),
|
session_init->master_signing_key(), std::string(kSigningKeyLabel),
|
||||||
context,
|
license_request_->protocol_version() < VERSION_2_2
|
||||||
SigningKeyMaterialSize(license_request_->protocol_version()));
|
? context
|
||||||
|
: Sha512_Hash(context),
|
||||||
|
SigningKeyMaterialSizeBits(license_request_->protocol_version()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signing_key->empty()) {
|
if (signing_key->empty()) {
|
||||||
status = util::Status(error_space, MISSING_RENEWAL_SIGNING_KEY, "");
|
status = Status(error_space, MISSING_RENEWAL_SIGNING_KEY, "");
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
uint32_t signing_key_material_size_bytes =
|
uint32_t signing_key_material_size_bytes =
|
||||||
SigningKeyMaterialSize(license_request_->protocol_version()) / 8;
|
SigningKeyMaterialSizeBits(license_request_->protocol_version()) / 8;
|
||||||
if (signing_key->size() < signing_key_material_size_bytes) {
|
if (signing_key->size() < signing_key_material_size_bytes) {
|
||||||
status = util::Status(error_space, INVALID_RENEWAL_SIGNING_KEY_SIZE, "");
|
status = Status(error_space, INVALID_RENEWAL_SIGNING_KEY_SIZE, "");
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
signing_key->resize(signing_key_material_size_bytes);
|
signing_key->resize(signing_key_material_size_bytes);
|
||||||
@@ -662,7 +665,7 @@ util::Status SessionImpl::GeneratePriorLicenseInfo(
|
|||||||
GetClientSigningKey(*signing_key,
|
GetClientSigningKey(*signing_key,
|
||||||
license_request_->protocol_version()),
|
license_request_->protocol_version()),
|
||||||
signed_message_->signature(), signed_message_->msg())) {
|
signed_message_->signature(), signed_message_->msg())) {
|
||||||
status = util::Status(error_space, INVALID_RENEWAL_SIGNATURE, "");
|
status = Status(error_space, INVALID_RENEWAL_SIGNATURE, "");
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -676,8 +679,7 @@ util::Status SessionImpl::GeneratePriorLicenseInfo(
|
|||||||
.existing_license()
|
.existing_license()
|
||||||
.session_usage_table_entry();
|
.session_usage_table_entry();
|
||||||
if (session_usage.size() <= kSha1SignatureSizeBytes) {
|
if (session_usage.size() <= kSha1SignatureSizeBytes) {
|
||||||
status =
|
status = Status(error_space, INVALID_SESSION_USAGE_TABLE_ENTRY, "");
|
||||||
util::Status(error_space, INVALID_SESSION_USAGE_TABLE_ENTRY, "");
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
if (!crypto_util::VerifySignatureHmacSha1(
|
if (!crypto_util::VerifySignatureHmacSha1(
|
||||||
@@ -685,7 +687,7 @@ util::Status SessionImpl::GeneratePriorLicenseInfo(
|
|||||||
license_request_->protocol_version()),
|
license_request_->protocol_version()),
|
||||||
session_usage.substr(0, kSha1SignatureSizeBytes),
|
session_usage.substr(0, kSha1SignatureSizeBytes),
|
||||||
session_usage.substr(kSha1SignatureSizeBytes))) {
|
session_usage.substr(kSha1SignatureSizeBytes))) {
|
||||||
status = util::Status(error_space, INVALID_SESSION_USAGE_SIGNATURE, "");
|
status = Status(error_space, INVALID_SESSION_USAGE_SIGNATURE, "");
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -700,8 +702,8 @@ util::Status SessionImpl::GeneratePriorLicenseInfo(
|
|||||||
system_id = client_cert_->system_id();
|
system_id = client_cert_->system_id();
|
||||||
}
|
}
|
||||||
if (system_id && !DeviceStatusList::Instance()->IsSystemIdActive(system_id)) {
|
if (system_id && !DeviceStatusList::Instance()->IsSystemIdActive(system_id)) {
|
||||||
status = util::Status(error_space, UNSUPPORTED_SYSTEM_ID,
|
status = Status(error_space, UNSUPPORTED_SYSTEM_ID,
|
||||||
"system-id-for-renewal-not-active");
|
"system-id-for-renewal-not-active");
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
*new_id = license_request_->content_id().existing_license().license_id();
|
*new_id = license_request_->content_id().existing_license().license_id();
|
||||||
@@ -709,7 +711,7 @@ util::Status SessionImpl::GeneratePriorLicenseInfo(
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status SessionImpl::GenerateSignedLicense(
|
Status SessionImpl::GenerateSignedLicense(
|
||||||
const License::Policy* policy,
|
const License::Policy* policy,
|
||||||
const std::list<License::KeyContainer>* key_container,
|
const std::list<License::KeyContainer>* key_container,
|
||||||
const SessionInit* session_init, SessionState* session_state,
|
const SessionInit* session_init, SessionState* session_state,
|
||||||
@@ -717,14 +719,13 @@ util::Status SessionImpl::GenerateSignedLicense(
|
|||||||
DCHECK(signed_message_bytes);
|
DCHECK(signed_message_bytes);
|
||||||
*signed_message_bytes = "";
|
*signed_message_bytes = "";
|
||||||
|
|
||||||
util::Status status;
|
Status status;
|
||||||
LicenseIdentification new_id;
|
LicenseIdentification new_id;
|
||||||
std::string signing_key, renewal_signing_key;
|
std::string signing_key, renewal_signing_key;
|
||||||
|
|
||||||
if (license_request_->type() != LicenseRequest::NEW) {
|
if (license_request_->type() != LicenseRequest::NEW) {
|
||||||
if (key_container && !key_container->empty()) {
|
if (key_container && !key_container->empty()) {
|
||||||
status = util::Status(error_space,
|
status = Status(error_space, RENEWAL_WITH_CONTENT_KEYS_NOT_ALLOWED, "");
|
||||||
RENEWAL_WITH_CONTENT_KEYS_NOT_ALLOWED, "");
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
status = GeneratePriorLicenseInfo(session_init, session_state, &new_id,
|
status = GeneratePriorLicenseInfo(session_init, session_state, &new_id,
|
||||||
@@ -736,7 +737,7 @@ util::Status SessionImpl::GenerateSignedLicense(
|
|||||||
if (!status.ok()) return status;
|
if (!status.ok()) return status;
|
||||||
|
|
||||||
if (signing_key.empty()) {
|
if (signing_key.empty()) {
|
||||||
status = util::Status(error_space, MISSING_SIGNING_KEY, "");
|
status = Status(error_space, MISSING_SIGNING_KEY, "");
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
// Build up the license using the information passed in.
|
// Build up the license using the information passed in.
|
||||||
@@ -766,33 +767,35 @@ util::Status SessionImpl::GenerateSignedLicense(
|
|||||||
VLOG(3) << "Renewal Signing Key before encryption: "
|
VLOG(3) << "Renewal Signing Key before encryption: "
|
||||||
<< absl::BytesToHexString(renewal_signing_key);
|
<< absl::BytesToHexString(renewal_signing_key);
|
||||||
} else if (license.policy().can_renew()) {
|
} else if (license.policy().can_renew()) {
|
||||||
status =
|
status = Status(error_space, MISSING_RENEWAL_SIGNING_KEY,
|
||||||
util::Status(error_space, MISSING_RENEWAL_SIGNING_KEY,
|
"required for NEW license with can_renew = true.");
|
||||||
"required for NEW license with can_renew = true.");
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
if ((license.id().type() == OFFLINE) && !license.policy().can_persist()) {
|
if ((license.id().type() == OFFLINE) && !license.policy().can_persist()) {
|
||||||
status = util::Status(error_space, INVALID_OFFLINE_CAN_PERSIST, "");
|
status = Status(error_space, INVALID_OFFLINE_CAN_PERSIST, "");
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
} else if (license_request_->type() == LicenseRequest::RELEASE) {
|
} else if (license_request_->type() == LicenseRequest::RELEASE) {
|
||||||
if (license.has_policy() && license.policy().can_play()) {
|
if (license.has_policy() && license.policy().can_play()) {
|
||||||
// Invalid RELEASE response. can_play should be false.
|
// Invalid RELEASE response. can_play should be false.
|
||||||
status = util::Status(error_space, INVALID_RELEASE_CAN_PLAY_VALUE, "");
|
status = Status(error_space, INVALID_RELEASE_CAN_PLAY_VALUE, "");
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string encryption_key;
|
std::string wrapping_key;
|
||||||
if (key_container && !key_container->empty()) {
|
if (key_container && !key_container->empty()) {
|
||||||
if (!client_cert_.get()) {
|
if (!client_cert_.get()) {
|
||||||
status = util::Status(error_space, MISSING_CLIENT_CERT, "");
|
status = Status(error_space, MISSING_CLIENT_CERT, "");
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
encryption_key = DeriveKey(client_cert_->key(), std::string(kEncryptionKeyLabel),
|
wrapping_key = DeriveKey(client_cert_->key(), kWrappingKeyLabel,
|
||||||
signed_message_->msg(), kEncryptionKeySizeBits);
|
license_request_->protocol_version() < VERSION_2_2
|
||||||
if (encryption_key.empty()) {
|
? signed_message_->msg()
|
||||||
status = util::Status(error_space, MISSING_ENCRYPTION_KEY, "");
|
: Sha512_Hash(signed_message_->msg()),
|
||||||
|
kWrappingKeySizeBits);
|
||||||
|
if (wrapping_key.empty()) {
|
||||||
|
status = Status(error_space, MISSING_ENCRYPTION_KEY, "");
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
for (std::list<License::KeyContainer>::const_iterator iter =
|
for (std::list<License::KeyContainer>::const_iterator iter =
|
||||||
@@ -801,23 +804,22 @@ util::Status SessionImpl::GenerateSignedLicense(
|
|||||||
*license.add_key() = *iter;
|
*license.add_key() = *iter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
std::string provider_client_token =
|
||||||
|
GetProviderClientToken(*session_init, license_request_->client_id());
|
||||||
|
if (session_state) {
|
||||||
|
if (!provider_client_token.empty()) {
|
||||||
|
session_state->set_provider_client_token(provider_client_token);
|
||||||
|
} else if (license_request_->client_id().has_provider_client_token()) {
|
||||||
|
session_state->set_provider_client_token(
|
||||||
|
license_request_->client_id().provider_client_token());
|
||||||
|
}
|
||||||
|
session_state->set_license_counter(
|
||||||
|
license_request_->client_id().license_counter());
|
||||||
|
}
|
||||||
if (license_request_->type() == LicenseRequest::NEW) {
|
if (license_request_->type() == LicenseRequest::NEW) {
|
||||||
std::string provider_client_token =
|
|
||||||
GetProviderClientToken(*session_init, license_request_->client_id());
|
|
||||||
if (!provider_client_token.empty()) {
|
if (!provider_client_token.empty()) {
|
||||||
license.set_provider_client_token(provider_client_token);
|
license.set_provider_client_token(provider_client_token);
|
||||||
}
|
}
|
||||||
if (session_state) {
|
|
||||||
if (license.has_provider_client_token()) {
|
|
||||||
session_state->set_provider_client_token(
|
|
||||||
license.provider_client_token());
|
|
||||||
} else if (license_request_->client_id().has_provider_client_token()) {
|
|
||||||
session_state->set_provider_client_token(
|
|
||||||
license_request_->client_id().provider_client_token());
|
|
||||||
}
|
|
||||||
session_state->set_license_counter(
|
|
||||||
license_request_->client_id().license_counter());
|
|
||||||
}
|
|
||||||
// Put the protection scheme contained in the PSSH into the license.
|
// Put the protection scheme contained in the PSSH into the license.
|
||||||
ContentInfo content_info;
|
ContentInfo content_info;
|
||||||
if (ParseContentId(license_request_->content_id(), &content_info).ok()) {
|
if (ParseContentId(license_request_->content_id(), &content_info).ok()) {
|
||||||
@@ -847,8 +849,8 @@ util::Status SessionImpl::GenerateSignedLicense(
|
|||||||
std::unique_ptr<RsaPublicKey> rsa_public_key;
|
std::unique_ptr<RsaPublicKey> rsa_public_key;
|
||||||
rsa_public_key.reset(RsaPublicKey::Create(client_cert_->public_key()));
|
rsa_public_key.reset(RsaPublicKey::Create(client_cert_->public_key()));
|
||||||
if (rsa_public_key == nullptr) {
|
if (rsa_public_key == nullptr) {
|
||||||
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||||
"create-device-public-key-failed");
|
"create-device-public-key-failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -868,8 +870,8 @@ util::Status SessionImpl::GenerateSignedLicense(
|
|||||||
license.id().has_provider_session_token(), session_init,
|
license.id().has_provider_session_token(), session_init,
|
||||||
license.id().type(), system_id,
|
license.id().type(), system_id,
|
||||||
kcb.mutable_key_control_block())) {
|
kcb.mutable_key_control_block())) {
|
||||||
status = util::Status(error_space, KEYCONTROL_GENERATION_ERROR,
|
status = Status(error_space, KEYCONTROL_GENERATION_ERROR,
|
||||||
"Could not generate key control block.");
|
"Could not generate key control block.");
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
if (license.key(i).has_key() &&
|
if (license.key(i).has_key() &&
|
||||||
@@ -879,14 +881,18 @@ util::Status SessionImpl::GenerateSignedLicense(
|
|||||||
// encrypted.
|
// encrypted.
|
||||||
kcb.set_iv(Random16Bytes());
|
kcb.set_iv(Random16Bytes());
|
||||||
kcb.set_key_control_block(
|
kcb.set_key_control_block(
|
||||||
crypto_util::EncryptAesCbc(license.key(i).key().substr(0, 16),
|
license_request_->protocol_version() < VERSION_2_2
|
||||||
kcb.iv(), kcb.key_control_block()));
|
? crypto_util::EncryptAesCbc(license.key(i).key().substr(0, 16),
|
||||||
|
kcb.iv(), kcb.key_control_block())
|
||||||
|
: crypto_util::EncryptAesCbcNoPad(
|
||||||
|
license.key(i).key().substr(0, 16), kcb.iv(),
|
||||||
|
kcb.key_control_block()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (license.key(i).has_key()) {
|
if (license.key(i).has_key()) {
|
||||||
if (license.key(i).type() == License::KeyContainer::CONTENT) {
|
if (license.key(i).type() == License::KeyContainer::CONTENT) {
|
||||||
if (license.key(i).key().size() != kContentKeySize) {
|
if (license.key(i).key().size() != kContentKeySize) {
|
||||||
return util::Status(
|
return Status(
|
||||||
error_space, INVALID_KEY_SIZE,
|
error_space, INVALID_KEY_SIZE,
|
||||||
absl::StrCat(
|
absl::StrCat(
|
||||||
"content key size in license is wrong. Key size should be ",
|
"content key size in license is wrong. Key size should be ",
|
||||||
@@ -894,29 +900,29 @@ util::Status SessionImpl::GenerateSignedLicense(
|
|||||||
}
|
}
|
||||||
} else if (license.key(i).type() == License::KeyContainer::ENTITLEMENT) {
|
} else if (license.key(i).type() == License::KeyContainer::ENTITLEMENT) {
|
||||||
if (license.key(i).key().size() != kEntitlementKeySize) {
|
if (license.key(i).key().size() != kEntitlementKeySize) {
|
||||||
return util::Status(error_space, INVALID_KEY_SIZE,
|
return Status(error_space, INVALID_KEY_SIZE,
|
||||||
"invalid-entitlement-key-size");
|
"invalid-entitlement-key-size");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
license.mutable_key(i)->set_iv(Random16Bytes());
|
license.mutable_key(i)->set_iv(Random16Bytes());
|
||||||
license.mutable_key(i)->set_key(crypto_util::EncryptAesCbc(
|
license.mutable_key(i)->set_key(
|
||||||
encryption_key, license.key(i).iv(), license.key(i).key()));
|
license_request_->protocol_version() < VERSION_2_2
|
||||||
|
? crypto_util::EncryptAesCbc(wrapping_key, license.key(i).iv(),
|
||||||
|
license.key(i).key())
|
||||||
|
: crypto_util::EncryptAesCbcNoPad(
|
||||||
|
wrapping_key, license.key(i).iv(), license.key(i).key()));
|
||||||
if (license.key(i).key().empty()) {
|
if (license.key(i).key().empty()) {
|
||||||
return util::Status(error_space, ENCRYPT_ERROR, "key-encrypt-failed");
|
return Status(error_space, ENCRYPT_ERROR, "key-encrypt-failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (platform_verification_status_) {
|
if (platform_verification_status_ != PLATFORM_NO_VERIFICATION) {
|
||||||
case PLATFORM_NO_VERIFICATION:
|
license.set_platform_verification_status(platform_verification_status_);
|
||||||
break;
|
}
|
||||||
case PLATFORM_HARDWARE_VERIFIED:
|
// TODO(b/65054419): Deprecate remote_attestation_verified altogether.
|
||||||
// TODO(b/65054419): Deprecate remote_attestation_verified altogether.
|
if (remote_attestation_verified_) {
|
||||||
license.set_remote_attestation_verified(true);
|
license.set_remote_attestation_verified(true);
|
||||||
ABSL_FALLTHROUGH_INTENDED;
|
|
||||||
default:
|
|
||||||
license.set_platform_verification_status(platform_verification_status_);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -955,7 +961,7 @@ util::Status SessionImpl::GenerateSignedLicense(
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SessionImpl::GenerateErrorResponse(const util::Status& status,
|
bool SessionImpl::GenerateErrorResponse(const Status& status,
|
||||||
std::string* signed_message_bytes) {
|
std::string* signed_message_bytes) {
|
||||||
return widevine::GenerateErrorResponse(status, signed_message_bytes);
|
return widevine::GenerateErrorResponse(status, signed_message_bytes);
|
||||||
}
|
}
|
||||||
@@ -1027,9 +1033,9 @@ bool SessionImpl::ShouldSetProviderSessionToken(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status SessionImpl::VerifyPlatform() {
|
Status SessionImpl::VerifyPlatform() {
|
||||||
if (platform_verification_status_ != PLATFORM_NO_VERIFICATION) {
|
if (platform_verification_status_ != PLATFORM_NO_VERIFICATION) {
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
// Verify the platform only if it has not been verified at the proxy. This
|
// Verify the platform only if it has not been verified at the proxy. This
|
||||||
// verification can be performed by content providers who host their own
|
// verification can be performed by content providers who host their own
|
||||||
@@ -1039,7 +1045,7 @@ util::Status SessionImpl::VerifyPlatform() {
|
|||||||
ProvisionedDeviceInfo::LEVEL_1) {
|
ProvisionedDeviceInfo::LEVEL_1) {
|
||||||
platform_verification_status_ = PLATFORM_HARDWARE_VERIFIED;
|
platform_verification_status_ = PLATFORM_HARDWARE_VERIFIED;
|
||||||
} else {
|
} else {
|
||||||
util::Status status = VerifyRemoteAttestation();
|
Status status = VerifyRemoteAttestation();
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
VLOG(1) << "Remote Attestation Failure: " << status
|
VLOG(1) << "Remote Attestation Failure: " << status
|
||||||
<< ", license request: " << license_request_->ShortDebugString();
|
<< ", license request: " << license_request_->ShortDebugString();
|
||||||
@@ -1048,9 +1054,8 @@ util::Status SessionImpl::VerifyPlatform() {
|
|||||||
}
|
}
|
||||||
if (platform_verification_status_ == PLATFORM_UNVERIFIED &&
|
if (platform_verification_status_ == PLATFORM_UNVERIFIED &&
|
||||||
license_request_ && !license_request_->client_id().vmp_data().empty()) {
|
license_request_ && !license_request_->client_id().vmp_data().empty()) {
|
||||||
util::Status status =
|
Status status = VerifyVmpData(license_request_->client_id().vmp_data(),
|
||||||
VerifyVmpData(license_request_->client_id().vmp_data(),
|
&platform_verification_status_);
|
||||||
&platform_verification_status_);
|
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
VLOG(1) << "Platform Verification Failure: " << status
|
VLOG(1) << "Platform Verification Failure: " << status
|
||||||
<< ", license request: " << license_request_->ShortDebugString();
|
<< ", license request: " << license_request_->ShortDebugString();
|
||||||
@@ -1058,7 +1063,7 @@ util::Status SessionImpl::VerifyPlatform() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SessionImpl::GetDrmDeviceId() const {
|
std::string SessionImpl::GetDrmDeviceId() const {
|
||||||
@@ -1071,10 +1076,10 @@ std::string SessionImpl::GetDrmDeviceId() const {
|
|||||||
return std::string();
|
return std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status SessionImpl::VerifyDeviceCapabilities(
|
Status SessionImpl::VerifyDeviceCapabilities(
|
||||||
const ClientIdentification::ClientCapabilities& device_capabilities,
|
const ClientIdentification::ClientCapabilities& device_capabilities,
|
||||||
const License::KeyContainer::OutputProtection& output_protection) const {
|
const License::KeyContainer::OutputProtection& output_protection) const {
|
||||||
util::Status status(util::OkStatus());
|
Status status(OkStatus());
|
||||||
if (output_protection.has_hdcp() &&
|
if (output_protection.has_hdcp() &&
|
||||||
device_capabilities.has_max_hdcp_version()) {
|
device_capabilities.has_max_hdcp_version()) {
|
||||||
// TODO(user): Implement the HDCP use case.
|
// TODO(user): Implement the HDCP use case.
|
||||||
@@ -1087,26 +1092,26 @@ util::Status SessionImpl::VerifyDeviceCapabilities(
|
|||||||
device_capabilities.analog_output_capabilities() !=
|
device_capabilities.analog_output_capabilities() !=
|
||||||
ClientIdentification::ClientCapabilities::ANALOG_OUTPUT_NONE) &&
|
ClientIdentification::ClientCapabilities::ANALOG_OUTPUT_NONE) &&
|
||||||
!device_capabilities.can_disable_analog_output()) {
|
!device_capabilities.can_disable_analog_output()) {
|
||||||
return util::Status(util::error::PERMISSION_DENIED,
|
return Status(error::PERMISSION_DENIED,
|
||||||
"Analog output must be disabled.");
|
"Analog output must be disabled.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (output_protection.cgms_flags() !=
|
if (output_protection.cgms_flags() !=
|
||||||
License::KeyContainer::OutputProtection::CGMS_NONE) {
|
License::KeyContainer::OutputProtection::CGMS_NONE) {
|
||||||
if (device_capabilities.analog_output_capabilities() ==
|
if (device_capabilities.analog_output_capabilities() ==
|
||||||
ClientIdentification::ClientCapabilities::ANALOG_OUTPUT_SUPPORTED) {
|
ClientIdentification::ClientCapabilities::ANALOG_OUTPUT_SUPPORTED) {
|
||||||
return util::Status(util::error::PERMISSION_DENIED,
|
return Status(error::PERMISSION_DENIED,
|
||||||
"Analog output must support CGMS-A.");
|
"Analog output must support CGMS-A.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status SessionImpl::CheckProviderSessionToken(const std::string& pst_src) {
|
Status SessionImpl::CheckProviderSessionToken(const std::string& pst_src) {
|
||||||
if (pst_src.size() > kProviderSessionTokenSizeBytes) {
|
if (pst_src.size() > kProviderSessionTokenSizeBytes) {
|
||||||
return util::Status(error_space, INVALID_PROVIDER_SESSION_TOKEN_SIZE, "");
|
return Status(error_space, INVALID_PROVIDER_SESSION_TOKEN_SIZE, "");
|
||||||
}
|
}
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1114,19 +1119,18 @@ PlatformVerificationStatus SessionImpl::GetPlatformVerificationStatus() const {
|
|||||||
return platform_verification_status_;
|
return platform_verification_status_;
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Status SessionImpl::VerifyRemoteAttestation() {
|
Status SessionImpl::VerifyRemoteAttestation() {
|
||||||
platform_verification_status_ = PLATFORM_UNVERIFIED;
|
platform_verification_status_ = PLATFORM_UNVERIFIED;
|
||||||
if (signed_message_ != nullptr && signed_message_->has_remote_attestation()) {
|
if (signed_message_ != nullptr && signed_message_->has_remote_attestation()) {
|
||||||
if (!signed_message_->has_msg()) {
|
if (!signed_message_->has_msg()) {
|
||||||
return util::Status(error_space, INVALID_MESSAGE,
|
return Status(error_space, INVALID_MESSAGE, "SignedMessage-msg-missing");
|
||||||
"SignedMessage-msg-missing");
|
|
||||||
}
|
}
|
||||||
util::Status status =
|
Status status = RemoteAttestationVerifier::get().VerifyRemoteAttestation(
|
||||||
RemoteAttestationVerifier::get().VerifyRemoteAttestation(
|
signed_message_->msg(), signed_message_->remote_attestation(),
|
||||||
signed_message_->msg(), signed_message_->remote_attestation(),
|
&remote_attestation_cert_serial_number_);
|
||||||
&remote_attestation_cert_serial_number_);
|
|
||||||
if (status.ok()) {
|
if (status.ok()) {
|
||||||
platform_verification_status_ = PLATFORM_HARDWARE_VERIFIED;
|
platform_verification_status_ = PLATFORM_HARDWARE_VERIFIED;
|
||||||
|
remote_attestation_verified_ = true;
|
||||||
} else if ((status.error_space() == error_space) &&
|
} else if ((status.error_space() == error_space) &&
|
||||||
(status.error_code() == REMOTE_ATTESTATION_FAILED)) {
|
(status.error_code() == REMOTE_ATTESTATION_FAILED)) {
|
||||||
platform_verification_status_ = PLATFORM_TAMPERED;
|
platform_verification_status_ = PLATFORM_TAMPERED;
|
||||||
@@ -1135,7 +1139,7 @@ util::Status SessionImpl::VerifyRemoteAttestation() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(user): add check to get client_id from EncryptedClientIdentification.
|
// TODO(user): add check to get client_id from EncryptedClientIdentification.
|
||||||
@@ -1158,4 +1162,11 @@ std::string SessionImpl::GetDrmDeviceServiceId() const {
|
|||||||
return std::string();
|
return std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Status SessionImpl::GenerateDeviceStatusListRequest(
|
||||||
|
std::string* signed_device_certificate_status_list_request) {
|
||||||
|
std::string version = GetSdkVersionString();
|
||||||
|
return DeviceStatusList::GenerateSignedDeviceCertificateStatusListRequest(
|
||||||
|
version, signed_device_certificate_status_list_request);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
|
|||||||
@@ -16,8 +16,8 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include "base/macros.h"
|
#include "base/macros.h"
|
||||||
#include "util/status.h"
|
|
||||||
#include "absl/synchronization/mutex.h"
|
#include "absl/synchronization/mutex.h"
|
||||||
|
#include "common/status.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"
|
||||||
#include "protos/public/license_server_sdk.pb.h"
|
#include "protos/public/license_server_sdk.pb.h"
|
||||||
@@ -65,8 +65,8 @@ std::string GetProviderClientToken(const SessionInit& session_init,
|
|||||||
// 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(root_cert, signed_license_request,
|
// Status status = Session::Create(root_cert, signed_license_request,
|
||||||
// &session);
|
// &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)) {
|
||||||
@@ -112,10 +112,10 @@ class SessionImpl {
|
|||||||
// 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 Status SetCertificateStatusList(const DrmRootCertificate* root_cert,
|
||||||
const DrmRootCertificate* root_cert,
|
const std::string& certificate_status_list,
|
||||||
const std::string& certificate_status_list, uint32_t expiration_period_seconds,
|
uint32_t expiration_period_seconds,
|
||||||
bool allow_unknown_devices);
|
bool allow_unknown_devices);
|
||||||
|
|
||||||
// Add a service certificate system-wide. |root_cert| is the root certificate
|
// Add a service certificate system-wide. |root_cert| is the root certificate
|
||||||
// which signed the service certificate;
|
// which signed the service certificate;
|
||||||
@@ -124,7 +124,7 @@ class SessionImpl {
|
|||||||
// |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 Status AddDrmServiceCertificate(
|
||||||
const DrmRootCertificate* root_cert, 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);
|
||||||
@@ -143,13 +143,13 @@ class SessionImpl {
|
|||||||
// |signed_license_request| is the serialized SignedMessage received from the
|
// |signed_license_request| is the serialized SignedMessage received from the
|
||||||
// client. |session| points to a Session*, which must be initialized to NULL
|
// client. |session| points to a Session*, which must be initialized to NULL
|
||||||
// on entry, but |session| itself may not be NULL. The new Session object will
|
// on entry, but |session| itself may not be NULL. The new Session object will
|
||||||
// be owned by the caller. This method returns util::Status::OK if successful,
|
// be owned by the caller. This method returns Status::OK if successful,
|
||||||
// or an appropriate error status, in which case
|
// or an appropriate error status, in which case
|
||||||
// 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(root_cert, request_from_client,
|
// Status status = Session::Create(root_cert, request_from_client,
|
||||||
// &session);
|
// &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)) {
|
||||||
@@ -160,16 +160,16 @@ class SessionImpl {
|
|||||||
// return ...
|
// return ...
|
||||||
// }
|
// }
|
||||||
// // Create license, invoke GenerateSignedLicense, etc.
|
// // Create license, invoke GenerateSignedLicense, etc.
|
||||||
static util::Status Create(const DrmRootCertificate* root_cert,
|
static Status Create(const DrmRootCertificate* root_cert,
|
||||||
const std::string& signed_license_request,
|
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 DrmRootCertificate* root_cert,
|
static Status Create(const DrmRootCertificate* root_cert,
|
||||||
const std::string& signed_license_request,
|
const std::string& signed_license_request,
|
||||||
SessionImpl** session,
|
SessionImpl** session,
|
||||||
LicenseRequest* parsed_request_out);
|
LicenseRequest* parsed_request_out);
|
||||||
|
|
||||||
// Same as Create(), but caller can specify the ClientIdentification
|
// Same as Create(), but caller can specify the ClientIdentification
|
||||||
// message and/or PlatformVerificationStatus. If ClientIdentification is
|
// message and/or PlatformVerificationStatus. If ClientIdentification is
|
||||||
@@ -184,7 +184,7 @@ class SessionImpl {
|
|||||||
// platform verification. The provider will specify the
|
// platform verification. The provider will specify the
|
||||||
// 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 Status CreateForProxy(
|
||||||
const DrmRootCertificate* root_cert, 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,
|
||||||
@@ -192,12 +192,12 @@ class SessionImpl {
|
|||||||
|
|
||||||
// Generates a SignedMessage containing a message generated in response to
|
// Generates a SignedMessage containing a message generated in response to
|
||||||
// an error condition. |status| is a previous error status returned by the
|
// an error condition. |status| is a previous error status returned by the
|
||||||
// Session or util::Status(util::error::UNAVAILABLE, ...) to indicate that the
|
// Session or Status(error::UNAVAILABLE, ...) to indicate that the
|
||||||
// backend is unavailable, |signed_message| points to a std::string to contain the
|
// backend is unavailable, |signed_message| points to a std::string to contain the
|
||||||
// serialized SignedMessage, and may not be NULL. This method returns true if
|
// serialized SignedMessage, and may not be NULL. This method returns true if
|
||||||
// there is an error license to be sent to the client, or false otherwise.
|
// there is an error license to be sent to the client, or false otherwise.
|
||||||
// Example usage in the Session::Create comments above.
|
// Example usage in the Session::Create comments above.
|
||||||
static bool GenerateErrorResponse(const util::Status& status,
|
static bool GenerateErrorResponse(const Status& status,
|
||||||
std::string* signed_message_bytes);
|
std::string* signed_message_bytes);
|
||||||
|
|
||||||
// DeriveKey uses the NIST 800-108 KDF recommendation, using AES-CMAC PRF.
|
// DeriveKey uses the NIST 800-108 KDF recommendation, using AES-CMAC PRF.
|
||||||
@@ -217,8 +217,8 @@ class SessionImpl {
|
|||||||
return is_service_certificate_loaded_;
|
return is_service_certificate_loaded_;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* kEncryptionKeyLabel; // NOLINT
|
static const char* kWrappingKeyLabel; // NOLINT
|
||||||
static const uint32_t kEncryptionKeySizeBits;
|
static const uint32_t kWrappingKeySizeBits;
|
||||||
static const char* kSigningKeyLabel; // NOLINT
|
static const char* kSigningKeyLabel; // NOLINT
|
||||||
static const uint32_t kSigningKeySizeBits;
|
static const uint32_t kSigningKeySizeBits;
|
||||||
|
|
||||||
@@ -239,13 +239,13 @@ class SessionImpl {
|
|||||||
// places in the liciense request protcol buffer. Use this method instead
|
// places in the liciense request protcol buffer. Use this method instead
|
||||||
// of accessing directly. |request_id| is a pointer to a std::string to contain
|
// of accessing directly. |request_id| is a pointer to a std::string to contain
|
||||||
// the request ID upon successful return.
|
// the request ID upon successful return.
|
||||||
virtual util::Status GetRequestId(std::string* request_id) const;
|
virtual Status GetRequestId(std::string* request_id) const;
|
||||||
|
|
||||||
// Accessor for license_type field which may be encoded in one of multiple
|
// Accessor for license_type field which may be encoded in one of multiple
|
||||||
// places in the license request protcol buffer. Use this method instead
|
// places in the license request protcol buffer. Use this method instead
|
||||||
// of accessing directly. |license_type| is a pointer to a value to contain
|
// of accessing directly. |license_type| is a pointer to a value to contain
|
||||||
// the license type upon successful return.
|
// the license type upon successful return.
|
||||||
virtual util::Status GetLicenseType(LicenseType* license_type) const;
|
virtual Status GetLicenseType(LicenseType* license_type) const;
|
||||||
|
|
||||||
// Method used to get ContentIdentification in a consistent message regardless
|
// Method used to get ContentIdentification in a consistent message regardless
|
||||||
// of the type or version of initialization data contained in the content_id
|
// of the type or version of initialization data contained in the content_id
|
||||||
@@ -253,7 +253,7 @@ class SessionImpl {
|
|||||||
// fields of ContentIdentification directly. |content_info| is a pointer to a
|
// fields of ContentIdentification directly. |content_info| is a pointer to a
|
||||||
// message to contain the parsed values from content_id upon successful
|
// message to contain the parsed values from content_id upon successful
|
||||||
// return.
|
// return.
|
||||||
virtual util::Status GetContentInfo(ContentInfo* content_info) const;
|
virtual Status GetContentInfo(ContentInfo* content_info) const;
|
||||||
|
|
||||||
// Returns the serial number of certificate associated with this device and
|
// Returns the serial number of certificate associated with this device and
|
||||||
// content provider.
|
// content provider.
|
||||||
@@ -271,7 +271,7 @@ class SessionImpl {
|
|||||||
// are necessary to fulfill the request (such as the case with license
|
// are necessary to fulfill the request (such as the case with license
|
||||||
// renewal), |policy| and/or |key_container| may be NULL.
|
// renewal), |policy| and/or |key_container| may be NULL.
|
||||||
// The response is expected to be sent to the Widevine CDM.
|
// The response is expected to be sent to the Widevine CDM.
|
||||||
virtual util::Status GenerateSignedLicense(
|
virtual Status GenerateSignedLicense(
|
||||||
/*IN*/ const License::Policy* policy,
|
/*IN*/ const License::Policy* policy,
|
||||||
/*IN*/ const std::list<License::KeyContainer>* key_container,
|
/*IN*/ const std::list<License::KeyContainer>* key_container,
|
||||||
/*IN*/ const SessionInit* session_init,
|
/*IN*/ const SessionInit* session_init,
|
||||||
@@ -280,7 +280,7 @@ class SessionImpl {
|
|||||||
|
|
||||||
// Verify the required |output_protection| can be satisified based on the
|
// Verify the required |output_protection| can be satisified based on the
|
||||||
// |device_capabilities| specified by the client.
|
// |device_capabilities| specified by the client.
|
||||||
virtual util::Status VerifyDeviceCapabilities(
|
virtual Status VerifyDeviceCapabilities(
|
||||||
const ClientIdentification::ClientCapabilities& device_capabilities,
|
const ClientIdentification::ClientCapabilities& device_capabilities,
|
||||||
const License::KeyContainer::OutputProtection& output_protection) const;
|
const License::KeyContainer::OutputProtection& output_protection) const;
|
||||||
|
|
||||||
@@ -294,10 +294,17 @@ class SessionImpl {
|
|||||||
// false.
|
// false.
|
||||||
virtual bool HasKeyControlNonce() const { return has_key_control_nonce_; }
|
virtual bool HasKeyControlNonce() const { return has_key_control_nonce_; }
|
||||||
|
|
||||||
|
// Generate a signed request to be sent to Widevine Certificate Provisioning
|
||||||
|
// Server to retrieve 'DeviceCertificateStatusList'.
|
||||||
|
virtual Status GenerateDeviceStatusListRequest(
|
||||||
|
std::string* signed_device_certificate_status_list_request);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class Session;
|
friend class Session;
|
||||||
|
|
||||||
PlatformVerificationStatus platform_verification_status_ =
|
PlatformVerificationStatus platform_verification_status_ =
|
||||||
PLATFORM_NO_VERIFICATION;
|
PLATFORM_NO_VERIFICATION;
|
||||||
|
bool remote_attestation_verified_ = false;
|
||||||
|
|
||||||
// For testing only. This allows unit tests to define a mock Session class.
|
// For testing only. This allows unit tests to define a mock Session class.
|
||||||
SessionImpl();
|
SessionImpl();
|
||||||
@@ -310,12 +317,12 @@ 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(const DrmRootCertificate* root_cert);
|
Status Init(const DrmRootCertificate* root_cert);
|
||||||
util::Status GenerateNewLicenseInfo(/*IN*/ const SessionInit* session_init,
|
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,
|
||||||
/*OUT*/ std::string* signing_key);
|
/*OUT*/ std::string* signing_key);
|
||||||
util::Status GeneratePriorLicenseInfo(
|
Status GeneratePriorLicenseInfo(
|
||||||
/*IN*/ const SessionInit* session_init,
|
/*IN*/ const SessionInit* session_init,
|
||||||
/*INOUT*/ SessionState* session_state,
|
/*INOUT*/ SessionState* session_state,
|
||||||
/*OUT*/ LicenseIdentification* new_id,
|
/*OUT*/ LicenseIdentification* new_id,
|
||||||
@@ -324,7 +331,7 @@ class SessionImpl {
|
|||||||
|
|
||||||
// Verifies remote attestation in the license request and sets
|
// Verifies remote attestation in the license request and sets
|
||||||
// |platform_verification_status_|.
|
// |platform_verification_status_|.
|
||||||
virtual util::Status VerifyRemoteAttestation();
|
virtual Status VerifyRemoteAttestation();
|
||||||
// Return true if the provider session token should get included in the
|
// Return true if the provider session token should get included in the
|
||||||
// license response.
|
// license response.
|
||||||
static bool ShouldSetProviderSessionToken(
|
static bool ShouldSetProviderSessionToken(
|
||||||
@@ -334,25 +341,25 @@ class SessionImpl {
|
|||||||
// Verifies the platform by platform-specific means such as Remote Attestion
|
// Verifies the platform by platform-specific means such as Remote Attestion
|
||||||
// or host code verification. Only meaningful for Widevine Level 2-3, as
|
// or host code verification. Only meaningful for Widevine Level 2-3, as
|
||||||
// Level 1 devices are verified by default.
|
// Level 1 devices are verified by default.
|
||||||
virtual util::Status VerifyPlatform();
|
virtual Status VerifyPlatform();
|
||||||
|
|
||||||
// Extracts the nonce from |request| and populates |key_control_nonce|. Sets
|
// Extracts the nonce from |request| and populates |key_control_nonce|. Sets
|
||||||
// |key_control_nonce| to true if the nonce is found.
|
// |key_control_nonce| to true if the nonce is found.
|
||||||
static util::Status LoadKeyControlNonce(const LicenseRequest& request,
|
static Status LoadKeyControlNonce(const LicenseRequest& request,
|
||||||
bool* has_key_control_nonce,
|
bool* has_key_control_nonce,
|
||||||
uint32_t* key_control_nonce);
|
uint32_t* key_control_nonce);
|
||||||
|
|
||||||
// Validates required fields are set in the license |request|.
|
// Validates required fields are set in the license |request|.
|
||||||
static util::Status CheckLicenseRequestFields(const LicenseRequest& request);
|
static Status CheckLicenseRequestFields(const LicenseRequest& request);
|
||||||
|
|
||||||
// De-serialize the license request from the |signed_license_request|
|
// De-serialize the license request from the |signed_license_request|
|
||||||
// into |license_request| and |signed_message|.
|
// into |license_request| and |signed_message|.
|
||||||
static util::Status ParseLicenseRequestFromString(
|
static Status ParseLicenseRequestFromString(
|
||||||
const std::string& signed_license_request, SignedMessage* signed_message,
|
const std::string& signed_license_request, SignedMessage* signed_message,
|
||||||
LicenseRequest* license_request);
|
LicenseRequest* license_request);
|
||||||
|
|
||||||
// Validates the Provider Session Token from |pst_src|.
|
// Validates the Provider Session Token from |pst_src|.
|
||||||
static util::Status CheckProviderSessionToken(const std::string& pst_src);
|
static Status CheckProviderSessionToken(const std::string& pst_src);
|
||||||
|
|
||||||
std::unique_ptr<SignedMessage> signed_message_;
|
std::unique_ptr<SignedMessage> signed_message_;
|
||||||
std::unique_ptr<LicenseRequest> license_request_;
|
std::unique_ptr<LicenseRequest> license_request_;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -13,11 +13,12 @@
|
|||||||
#include "common/error_space.h"
|
#include "common/error_space.h"
|
||||||
#include "media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_session.h"
|
#include "media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_session.h"
|
||||||
|
|
||||||
namespace util = widevine::util;
|
|
||||||
using widevine::error_space;
|
using widevine::error_space;
|
||||||
using widevine::kCertificateTypeDevelopment;
|
using widevine::kCertificateTypeDevelopment;
|
||||||
using widevine::kCertificateTypeTesting;
|
using widevine::kCertificateTypeTesting;
|
||||||
|
|
||||||
|
namespace error = widevine::error;
|
||||||
|
|
||||||
namespace widevine_server {
|
namespace widevine_server {
|
||||||
namespace wv_pl_sdk {
|
namespace wv_pl_sdk {
|
||||||
|
|
||||||
@@ -32,6 +33,7 @@ WvPLCASProxyEnvironment::WvPLCASProxyEnvironment(
|
|||||||
if (it != config_values.end()) {
|
if (it != config_values.end()) {
|
||||||
provider_ = (*it).second;
|
provider_ = (*it).second;
|
||||||
}
|
}
|
||||||
|
it = config_values.find(kProviderIv);
|
||||||
if (it != config_values.end()) {
|
if (it != config_values.end()) {
|
||||||
provider_iv_ = new std::string(absl::HexStringToBytes((*it).second));
|
provider_iv_ = new std::string(absl::HexStringToBytes((*it).second));
|
||||||
}
|
}
|
||||||
@@ -49,20 +51,17 @@ WvPLStatus WvPLCASProxyEnvironment::Initialize() {
|
|||||||
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) {
|
||||||
WvPLStatus status = util::OkStatus();
|
WvPLStatus status;
|
||||||
if (cas_proxy_session == nullptr) {
|
if (cas_proxy_session == nullptr) {
|
||||||
return WvPLStatus(error_space, util::error::INTERNAL,
|
return WvPLStatus(error_space, error::INTERNAL, "proxy_session is NULL");
|
||||||
"proxy_session is NULL");
|
|
||||||
}
|
}
|
||||||
if (*cas_proxy_session != nullptr) {
|
if (*cas_proxy_session != nullptr) {
|
||||||
return WvPLStatus(error_space, util::error::INTERNAL,
|
return WvPLStatus(error_space, error::INTERNAL,
|
||||||
"*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(drm_root_certificate_.get(),
|
new WvPLCASProxySession(drm_root_certificate_.get(),
|
||||||
cas_license_request));
|
cas_license_request));
|
||||||
// TODO(user): Complete the license request parsing in WvPLCASProxySession.
|
|
||||||
// status = wvpl_cas_proxy_session->ParseLicenseRequest();
|
|
||||||
if (status.ok()) {
|
if (status.ok()) {
|
||||||
*cas_proxy_session = wvpl_cas_proxy_session.release();
|
*cas_proxy_session = wvpl_cas_proxy_session.release();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,34 @@ namespace wv_pl_sdk {
|
|||||||
|
|
||||||
class WvPLCASProxySession;
|
class WvPLCASProxySession;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up an environment for partners who are using the Widevine CAS License
|
||||||
|
* Proxy SDK. This environment *must* be successfully created in order to work
|
||||||
|
* with the SDK API.
|
||||||
|
*
|
||||||
|
* Implements the following public API:
|
||||||
|
* - CreateSession()
|
||||||
|
* - SetDeviceCertificateStatusList()
|
||||||
|
*
|
||||||
|
* Example Usage:
|
||||||
|
* map<std::string, std::string> config_values;
|
||||||
|
* config_values.insert(std::make_pair(kDrmCertificateType, "prod");
|
||||||
|
* config_values.insert(std::make_pair(kProvider, "TEST_PROVIDER");
|
||||||
|
* config_values.insert(std::make_pair(kProviderIv, "TEST_IV"));
|
||||||
|
* config_values.insert(std::make_pair(kProviderKey, "TEST_KEY"));
|
||||||
|
* WvPLCASProxyEnvironment* wv_cas_proxy_environment =
|
||||||
|
* new WvPLCASProxyEnvironment(config_values);
|
||||||
|
* // This is the DeviceCertificateStatusList returned from a query to the
|
||||||
|
* // Widevine Certificate Provisioning Service (List API).
|
||||||
|
* std::string certificate_status_list = "TEST_CERTIFICATE_STATUS_LIST";
|
||||||
|
* wvpl_status = wvpl_cas_proxy_environment->SetDeviceCertificateStatusList(
|
||||||
|
* certificate_status_list);
|
||||||
|
* WvPLCASProxySession** wvpl_cas_proxy_session = nullptr;
|
||||||
|
* std::string license_request_from_cdm = "TEST_LICENSE_REQUEST";
|
||||||
|
* wvpl_status = wvpl_cas_proxy_environment->CreateSession(
|
||||||
|
* license_request_from_cdm, &wvpl_cas_proxy_session);
|
||||||
|
*/
|
||||||
|
|
||||||
class WvPLCASProxyEnvironment : public WvPLSDKEnvironment {
|
class WvPLCASProxyEnvironment : public WvPLSDKEnvironment {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -9,8 +9,6 @@
|
|||||||
#include "media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_session.h"
|
#include "media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_session.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace util = widevine::util;
|
|
||||||
|
|
||||||
namespace widevine_server {
|
namespace widevine_server {
|
||||||
namespace wv_pl_sdk {
|
namespace wv_pl_sdk {
|
||||||
|
|
||||||
@@ -30,12 +28,5 @@ WvPLCASProxySession::WvPLCASProxySession(
|
|||||||
const std::string& cas_license_request_from_cdm)
|
const std::string& cas_license_request_from_cdm)
|
||||||
: WvPLSDKSession(drm_root_certificate) {}
|
: WvPLSDKSession(drm_root_certificate) {}
|
||||||
|
|
||||||
WvPLStatus WvPLCASProxySession::ParsePsshData(
|
|
||||||
WvPLWidevinePsshData* wvpl_widevine_pssh_data) const {
|
|
||||||
// TODO(user): Implement this functionality in WvPLSdk and remove the
|
|
||||||
// implementation in the classes derived from WvPLSdk.
|
|
||||||
return util::OkStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace wv_pl_sdk
|
} // namespace wv_pl_sdk
|
||||||
} // namespace widevine_server
|
} // namespace widevine_server
|
||||||
|
|||||||
@@ -76,9 +76,6 @@ class WvPLCASProxySession : public WvPLSDKSession {
|
|||||||
WvPLCASProxySession(
|
WvPLCASProxySession(
|
||||||
const widevine::DrmRootCertificate* drm_root_certificate,
|
const widevine::DrmRootCertificate* drm_root_certificate,
|
||||||
const std::string& cas_license_request_from_cdm);
|
const std::string& cas_license_request_from_cdm);
|
||||||
|
|
||||||
WvPLStatus ParsePsshData(
|
|
||||||
WvPLWidevinePsshData* wvpl_widevine_pssh_data) const override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace wv_pl_sdk
|
} // namespace wv_pl_sdk
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ message DrmCertificate {
|
|||||||
SERVICE = 3;
|
SERVICE = 3;
|
||||||
PROVISIONER = 4;
|
PROVISIONER = 4;
|
||||||
}
|
}
|
||||||
|
enum ServiceType {
|
||||||
|
UNKNOWN = 0; LICENSE_SERVER_SDK = 1; LICENSE_SERVER_PROXY_SDK = 2;
|
||||||
|
}
|
||||||
// Type of certificate. Required.
|
// Type of certificate. Required.
|
||||||
optional Type type = 1;
|
optional Type type = 1;
|
||||||
// 128-bit globally unique serial number of certificate.
|
// 128-bit globally unique serial number of certificate.
|
||||||
@@ -47,4 +49,7 @@ message DrmCertificate {
|
|||||||
// Service identifier (web origin) for the provider which owns the
|
// Service identifier (web origin) for the provider which owns the
|
||||||
// certificate. Required for service and provisioner certificates.
|
// certificate. Required for service and provisioner certificates.
|
||||||
optional string provider_id = 7;
|
optional string provider_id = 7;
|
||||||
|
// This field is used only when type = SERVICE to specify which SDK uses
|
||||||
|
// service certificate.
|
||||||
|
optional ServiceType service_type = 8 [default = UNKNOWN];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -191,6 +191,8 @@ message License {
|
|||||||
optional HdcpSrmRule hdcp_srm_rule = 3 [default = HDCP_SRM_RULE_NONE];
|
optional HdcpSrmRule hdcp_srm_rule = 3 [default = HDCP_SRM_RULE_NONE];
|
||||||
// Optional requirement to indicate analog output is not allowed.
|
// Optional requirement to indicate analog output is not allowed.
|
||||||
optional bool disable_analog_output = 4 [default = false];
|
optional bool disable_analog_output = 4 [default = false];
|
||||||
|
// Optional requirement to indicate digital output is not allowed.
|
||||||
|
optional bool disable_digital_output = 5 [default = false];
|
||||||
}
|
}
|
||||||
|
|
||||||
message VideoResolutionConstraint {
|
message VideoResolutionConstraint {
|
||||||
@@ -273,6 +275,7 @@ message License {
|
|||||||
enum ProtocolVersion {
|
enum ProtocolVersion {
|
||||||
VERSION_2_0 = 20;
|
VERSION_2_0 = 20;
|
||||||
VERSION_2_1 = 21;
|
VERSION_2_1 = 21;
|
||||||
|
VERSION_2_2 = 22;
|
||||||
}
|
}
|
||||||
|
|
||||||
message LicenseRequest {
|
message LicenseRequest {
|
||||||
|
|||||||
16
sdk/external/common/wvpl/BUILD
vendored
16
sdk/external/common/wvpl/BUILD
vendored
@@ -23,7 +23,7 @@ cc_library(
|
|||||||
"wvpl_types.h",
|
"wvpl_types.h",
|
||||||
],
|
],
|
||||||
deps = [
|
deps = [
|
||||||
"//util:status",
|
"//common:status",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -40,12 +40,13 @@ cc_library(
|
|||||||
# 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",
|
":wvpl_types",
|
||||||
"//base",
|
"//base",
|
||||||
"//util:status",
|
"@abseil_repo//absl/memory",
|
||||||
"//common:client_cert",
|
"//common:client_cert",
|
||||||
"//common:error_space",
|
|
||||||
"//common:remote_attestation_verifier",
|
|
||||||
"//common:drm_root_certificate",
|
"//common:drm_root_certificate",
|
||||||
"//common:drm_service_certificate",
|
"//common:drm_service_certificate",
|
||||||
|
"//common:error_space",
|
||||||
|
"//common:remote_attestation_verifier",
|
||||||
|
"//common:status",
|
||||||
"//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",
|
||||||
@@ -54,6 +55,7 @@ cc_library(
|
|||||||
"//protos/public:license_protocol_proto",
|
"//protos/public:license_protocol_proto",
|
||||||
"//protos/public:license_server_sdk_proto",
|
"//protos/public:license_server_sdk_proto",
|
||||||
"//protos/public:provisioned_device_info_proto",
|
"//protos/public:provisioned_device_info_proto",
|
||||||
|
"//protos/public:widevine_pssh_proto",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -71,13 +73,13 @@ cc_library(
|
|||||||
"//base",
|
"//base",
|
||||||
"@abseil_repo//absl/strings",
|
"@abseil_repo//absl/strings",
|
||||||
"@abseil_repo//absl/synchronization",
|
"@abseil_repo//absl/synchronization",
|
||||||
"//util:status",
|
|
||||||
"//common:aes_cbc_util",
|
"//common:aes_cbc_util",
|
||||||
"//common:device_status_list",
|
"//common:device_status_list",
|
||||||
"//common:drm_root_certificate",
|
"//common:drm_root_certificate",
|
||||||
"//common:error_space",
|
"//common:error_space",
|
||||||
"//common:drm_service_certificate",
|
"//common:drm_service_certificate",
|
||||||
"//common:sha_util",
|
"//common:sha_util",
|
||||||
|
"//common:status",
|
||||||
"//license_server_sdk/internal:sdk",
|
"//license_server_sdk/internal:sdk",
|
||||||
"//protos/public:device_certificate_status_proto",
|
"//protos/public:device_certificate_status_proto",
|
||||||
"//protos/public:errors_proto",
|
"//protos/public:errors_proto",
|
||||||
@@ -96,9 +98,9 @@ cc_library(
|
|||||||
deps = [
|
deps = [
|
||||||
":wvpl_types",
|
":wvpl_types",
|
||||||
"//base",
|
"//base",
|
||||||
|
"@abseil_repo//absl/memory",
|
||||||
"@abseil_repo//absl/strings",
|
"@abseil_repo//absl/strings",
|
||||||
"@abseil_repo//absl/synchronization",
|
"@abseil_repo//absl/synchronization",
|
||||||
"//util:status",
|
|
||||||
"//common:aes_cbc_util",
|
"//common:aes_cbc_util",
|
||||||
"//common:client_cert",
|
"//common:client_cert",
|
||||||
"//common:device_status_list",
|
"//common:device_status_list",
|
||||||
@@ -107,6 +109,7 @@ cc_library(
|
|||||||
"//common:error_space",
|
"//common:error_space",
|
||||||
"//common:remote_attestation_verifier",
|
"//common:remote_attestation_verifier",
|
||||||
"//common:sha_util",
|
"//common:sha_util",
|
||||||
|
"//common:status",
|
||||||
"//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",
|
||||||
@@ -115,5 +118,6 @@ cc_library(
|
|||||||
"//protos/public:license_protocol_proto",
|
"//protos/public:license_protocol_proto",
|
||||||
"//protos/public:license_server_sdk_proto",
|
"//protos/public:license_server_sdk_proto",
|
||||||
"//protos/public:provisioned_device_info_proto",
|
"//protos/public:provisioned_device_info_proto",
|
||||||
|
"//protos/public:widevine_pssh_proto",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|||||||
38
sdk/external/common/wvpl/wvpl_sdk_environment.cc
vendored
38
sdk/external/common/wvpl/wvpl_sdk_environment.cc
vendored
@@ -10,16 +10,15 @@
|
|||||||
#include "glog/logging.h"
|
#include "glog/logging.h"
|
||||||
#include "absl/strings/escaping.h"
|
#include "absl/strings/escaping.h"
|
||||||
#include "absl/synchronization/mutex.h"
|
#include "absl/synchronization/mutex.h"
|
||||||
#include "util/status.h"
|
|
||||||
#include "common/aes_cbc_util.h"
|
#include "common/aes_cbc_util.h"
|
||||||
#include "common/device_status_list.h"
|
#include "common/device_status_list.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"
|
||||||
|
#include "common/status.h"
|
||||||
#include "license_server_sdk/internal/generate_error_response.h"
|
#include "license_server_sdk/internal/generate_error_response.h"
|
||||||
#include "protos/public/errors.pb.h"
|
#include "protos/public/errors.pb.h"
|
||||||
|
|
||||||
namespace util = widevine::util;
|
|
||||||
using widevine::DeviceCertificateStatus;
|
using widevine::DeviceCertificateStatus;
|
||||||
using widevine::DeviceCertificateStatusList;
|
using widevine::DeviceCertificateStatusList;
|
||||||
using widevine::DeviceStatusList;
|
using widevine::DeviceStatusList;
|
||||||
@@ -32,6 +31,8 @@ using widevine::ProvisionedDeviceInfo;
|
|||||||
using widevine::SignedDeviceCertificateStatusList;
|
using widevine::SignedDeviceCertificateStatusList;
|
||||||
using widevine::crypto_util::EncryptAesCbc;
|
using widevine::crypto_util::EncryptAesCbc;
|
||||||
|
|
||||||
|
namespace error = widevine::error;
|
||||||
|
|
||||||
namespace widevine_server {
|
namespace widevine_server {
|
||||||
namespace wv_pl_sdk {
|
namespace wv_pl_sdk {
|
||||||
|
|
||||||
@@ -93,9 +94,9 @@ bool WvPLSDKEnvironment::GenerateErrorResponse(
|
|||||||
|
|
||||||
WvPLStatus WvPLSDKEnvironment::LookupDeviceInfo(
|
WvPLStatus WvPLSDKEnvironment::LookupDeviceInfo(
|
||||||
uint32_t system_id, ProvisionedDeviceInfo* provisioned_device_info) {
|
uint32_t system_id, ProvisionedDeviceInfo* provisioned_device_info) {
|
||||||
WvPLStatus status = util::OkStatus();
|
WvPLStatus status;
|
||||||
if (provisioned_device_info == nullptr) {
|
if (provisioned_device_info == nullptr) {
|
||||||
return WvPLStatus(error_space, util::error::INVALID_ARGUMENT,
|
return WvPLStatus(error_space, error::INVALID_ARGUMENT,
|
||||||
"provisioned_device_info should not be null");
|
"provisioned_device_info should not be null");
|
||||||
}
|
}
|
||||||
const ProvisionedDeviceInfoMap& device_info_map =
|
const ProvisionedDeviceInfoMap& device_info_map =
|
||||||
@@ -114,7 +115,7 @@ WvPLStatus WvPLSDKEnvironment::LookupDeviceInfo(
|
|||||||
|
|
||||||
WvPLStatus WvPLSDKEnvironment::UpdateProvisionedDeviceInfoMap(
|
WvPLStatus WvPLSDKEnvironment::UpdateProvisionedDeviceInfoMap(
|
||||||
const DeviceCertificateStatusList& certificate_status_list) {
|
const DeviceCertificateStatusList& certificate_status_list) {
|
||||||
WvPLStatus status = util::OkStatus();
|
WvPLStatus status;
|
||||||
for (const DeviceCertificateStatus& cert_status :
|
for (const DeviceCertificateStatus& cert_status :
|
||||||
certificate_status_list.certificate_status()) {
|
certificate_status_list.certificate_status()) {
|
||||||
if (cert_status.has_device_info()) {
|
if (cert_status.has_device_info()) {
|
||||||
@@ -145,11 +146,11 @@ WvPLStatus WvPLSDKEnvironment::GenerateSignature(const std::string& plain_text,
|
|||||||
std::string* signature) {
|
std::string* signature) {
|
||||||
DCHECK(signature);
|
DCHECK(signature);
|
||||||
if (plain_text.empty()) {
|
if (plain_text.empty()) {
|
||||||
return WvPLStatus(error_space, util::error::INVALID_ARGUMENT,
|
return WvPLStatus(error_space, error::INVALID_ARGUMENT,
|
||||||
"Plain_text for signature is empty.");
|
"Plain_text for signature is empty.");
|
||||||
}
|
}
|
||||||
if (signature == nullptr) {
|
if (signature == nullptr) {
|
||||||
return WvPLStatus(error_space, util::error::INVALID_ARGUMENT,
|
return WvPLStatus(error_space, error::INVALID_ARGUMENT,
|
||||||
"Signature must not be null.");
|
"Signature must not be null.");
|
||||||
}
|
}
|
||||||
const std::map<std::string, std::string>* config_values = GetConfigValue();
|
const std::map<std::string, std::string>* config_values = GetConfigValue();
|
||||||
@@ -161,31 +162,30 @@ WvPLStatus WvPLSDKEnvironment::GenerateSignature(const std::string& plain_text,
|
|||||||
if (it != config_values->end()) {
|
if (it != config_values->end()) {
|
||||||
provider_iv = absl::HexStringToBytes((*it).second);
|
provider_iv = absl::HexStringToBytes((*it).second);
|
||||||
if (provider_iv.empty()) {
|
if (provider_iv.empty()) {
|
||||||
return WvPLStatus(error_space, util::error::NOT_FOUND,
|
return WvPLStatus(error_space, error::NOT_FOUND, "Provider IV is empty.");
|
||||||
"Provider IV is empty.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
it = config_values->find(kProviderKey);
|
it = config_values->find(kProviderKey);
|
||||||
if (it != config_values->end()) {
|
if (it != config_values->end()) {
|
||||||
provider_key = absl::HexStringToBytes((*it).second);
|
provider_key = absl::HexStringToBytes((*it).second);
|
||||||
if (provider_key.empty()) {
|
if (provider_key.empty()) {
|
||||||
return WvPLStatus(error_space, util::error::NOT_FOUND,
|
return WvPLStatus(error_space, error::NOT_FOUND,
|
||||||
"Provider Key is empty.");
|
"Provider Key is empty.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string hashed_text = widevine::Sha1_Hash(plain_text);
|
std::string hashed_text = widevine::Sha1_Hash(plain_text);
|
||||||
if (hashed_text.empty()) {
|
if (hashed_text.empty()) {
|
||||||
return util::Status(error_space, util::error::INVALID_ARGUMENT,
|
return WvPLStatus(error_space, error::INVALID_ARGUMENT,
|
||||||
"Hash for signature is empty.");
|
"Hash for signature is empty.");
|
||||||
} else {
|
} else {
|
||||||
*signature = EncryptAesCbc(provider_key, provider_iv, hashed_text);
|
*signature = EncryptAesCbc(provider_key, provider_iv, hashed_text);
|
||||||
if (signature->empty()) {
|
if (signature->empty()) {
|
||||||
return util::Status(error_space, util::error::INVALID_ARGUMENT,
|
return WvPLStatus(error_space, error::INVALID_ARGUMENT,
|
||||||
"Generated signature failed");
|
"Generated signature failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return util::OkStatus();
|
return WvPLStatus();
|
||||||
}
|
}
|
||||||
std::map<std::string, std::string>* WvPLSDKEnvironment::config_values_ =
|
std::map<std::string, std::string>* WvPLSDKEnvironment::config_values_ =
|
||||||
new std::map<std::string, std::string>();
|
new std::map<std::string, std::string>();
|
||||||
@@ -200,7 +200,7 @@ void WvPLSDKEnvironment::SetConfigValue(
|
|||||||
|
|
||||||
WvPLStatus WvPLSDKEnvironment::SetDeviceCertificateStatusList(
|
WvPLStatus WvPLSDKEnvironment::SetDeviceCertificateStatusList(
|
||||||
const std::string& cert_list) const {
|
const std::string& cert_list) const {
|
||||||
WvPLStatus status = util::OkStatus();
|
WvPLStatus status;
|
||||||
SignedDeviceCertificateStatusList device_certificate_status_list;
|
SignedDeviceCertificateStatusList device_certificate_status_list;
|
||||||
std::string decoded_certificate_status_list;
|
std::string decoded_certificate_status_list;
|
||||||
std::string device_certicate_status_list;
|
std::string device_certicate_status_list;
|
||||||
@@ -210,9 +210,9 @@ WvPLStatus WvPLSDKEnvironment::SetDeviceCertificateStatusList(
|
|||||||
if (!status.ok()) return status;
|
if (!status.ok()) return status;
|
||||||
DeviceCertificateStatusList certificate_status_list;
|
DeviceCertificateStatusList certificate_status_list;
|
||||||
if (!certificate_status_list.ParseFromString(device_certicate_status_list)) {
|
if (!certificate_status_list.ParseFromString(device_certicate_status_list)) {
|
||||||
return util::Status(error_space,
|
return WvPLStatus(error_space,
|
||||||
widevine::INVALID_CERTIFICATE_STATUS_LIST,
|
widevine::INVALID_CERTIFICATE_STATUS_LIST,
|
||||||
"certificate status list parse error");
|
"certificate status list parse error");
|
||||||
}
|
}
|
||||||
status = DeviceStatusList::Instance()->UpdateStatusList(
|
status = DeviceStatusList::Instance()->UpdateStatusList(
|
||||||
drm_root_certificate_->public_key(), decoded_certificate_status_list,
|
drm_root_certificate_->public_key(), decoded_certificate_status_list,
|
||||||
|
|||||||
181
sdk/external/common/wvpl/wvpl_sdk_session.cc
vendored
181
sdk/external/common/wvpl/wvpl_sdk_session.cc
vendored
@@ -8,21 +8,24 @@
|
|||||||
#include "sdk/external/common/wvpl/wvpl_sdk_session.h"
|
#include "sdk/external/common/wvpl/wvpl_sdk_session.h"
|
||||||
|
|
||||||
#include "glog/logging.h"
|
#include "glog/logging.h"
|
||||||
#include "util/status.h"
|
|
||||||
#include "absl/memory/memory.h"
|
#include "absl/memory/memory.h"
|
||||||
#include "common/client_cert.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/status.h"
|
||||||
#include "common/verified_media_pipeline.h"
|
#include "common/verified_media_pipeline.h"
|
||||||
|
#include "license_server_sdk/internal/parse_content_id.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/license_protocol.pb.h"
|
||||||
#include "protos/public/provisioned_device_info.pb.h"
|
#include "protos/public/provisioned_device_info.pb.h"
|
||||||
|
#include "protos/public/widevine_pssh.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 in wvpl_session and wvpl_proxy_session to base
|
||||||
// and wvpl_proxy_session to base class.
|
// class.
|
||||||
// TODO(user): Set SerialNumber and ServiceId field of WvPLDeviceInfo in
|
// TODO(user): Set SerialNumber and ServiceId field of WvPLDeviceInfo in
|
||||||
// getDeviceInfo function.
|
// getDeviceInfo function.
|
||||||
// TODO(user): Move the related Copy* function test cases to
|
// TODO(user): Move the related Copy* function test cases to
|
||||||
@@ -31,23 +34,27 @@
|
|||||||
// 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
|
// TODO(user): Move all the protected memeber variables to private and use
|
||||||
// getter and setter to access it.
|
// 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
|
// TODO(user): (b/119566765) Refactor ParseLicenseRequest and break it into
|
||||||
// different classes.
|
// different classes.
|
||||||
|
|
||||||
namespace util = widevine::util;
|
|
||||||
using widevine::ClientCert;
|
using widevine::ClientCert;
|
||||||
using widevine::ClientIdentification;
|
using widevine::ClientIdentification;
|
||||||
|
using widevine::ContentInfo;
|
||||||
using widevine::DrmRootCertificate;
|
using widevine::DrmRootCertificate;
|
||||||
using widevine::DrmServiceCertificate;
|
using widevine::DrmServiceCertificate;
|
||||||
using widevine::error_space;
|
using widevine::error_space;
|
||||||
using widevine::KeyboxClientCert;
|
using widevine::KeyboxClientCert;
|
||||||
using widevine::License;
|
using widevine::License;
|
||||||
using widevine::LicenseRequest;
|
using widevine::LicenseRequest;
|
||||||
|
using widevine::LicenseType;
|
||||||
|
using widevine::OkStatus;
|
||||||
using widevine::ProvisionedDeviceInfo;
|
using widevine::ProvisionedDeviceInfo;
|
||||||
using widevine::RemoteAttestationVerifier;
|
using widevine::RemoteAttestationVerifier;
|
||||||
using widevine::SessionInit;
|
using widevine::SessionInit;
|
||||||
using widevine::SignedMessage;
|
using widevine::SignedMessage;
|
||||||
|
using widevine::WidevinePsshData;
|
||||||
|
|
||||||
|
namespace error = widevine::error;
|
||||||
|
|
||||||
namespace widevine_server {
|
namespace widevine_server {
|
||||||
namespace wv_pl_sdk {
|
namespace wv_pl_sdk {
|
||||||
@@ -59,7 +66,7 @@ WvPLSDKSession::~WvPLSDKSession() {}
|
|||||||
|
|
||||||
WvPLStatus WvPLSDKSession::AddKey(const WvPLKey& key) {
|
WvPLStatus WvPLSDKSession::AddKey(const WvPLKey& key) {
|
||||||
keys_.push_back(key);
|
keys_.push_back(key);
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WvPLSDKSession::CopyPlaybackPolicy(const WvPLPlaybackPolicy& wvpl_policy,
|
void WvPLSDKSession::CopyPlaybackPolicy(const WvPLPlaybackPolicy& wvpl_policy,
|
||||||
@@ -227,6 +234,11 @@ void WvPLSDKSession::CopyHDCP(
|
|||||||
output_protection->set_hdcp(
|
output_protection->set_hdcp(
|
||||||
License::KeyContainer::OutputProtection::HDCP_NONE);
|
License::KeyContainer::OutputProtection::HDCP_NONE);
|
||||||
break;
|
break;
|
||||||
|
case HDCP_NO_DIGITAL_OUTPUT:
|
||||||
|
output_protection->set_hdcp(
|
||||||
|
License::KeyContainer::OutputProtection::HDCP_NO_DIGITAL_OUTPUT);
|
||||||
|
output_protection->set_disable_digital_output(true);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -306,23 +318,40 @@ void WvPLSDKSession::CopyOutputProtection(
|
|||||||
CopyHDCP(wvpl_key.output_protection().hdcp(),
|
CopyHDCP(wvpl_key.output_protection().hdcp(),
|
||||||
sdk_key_container->mutable_required_protection());
|
sdk_key_container->mutable_required_protection());
|
||||||
|
|
||||||
// Transfer HDCP from requested output protection value.
|
|
||||||
CopyHDCP(wvpl_key.requested_output_protection().hdcp(),
|
|
||||||
sdk_key_container->mutable_requested_protection());
|
|
||||||
|
|
||||||
CopySecurityLevel(wvpl_key.output_protection(), wvpl_key.track_type(),
|
CopySecurityLevel(wvpl_key.output_protection(), wvpl_key.track_type(),
|
||||||
sdk_key_container);
|
sdk_key_container);
|
||||||
|
|
||||||
sdk_key_container->mutable_requested_protection()->set_disable_analog_output(
|
sdk_key_container->mutable_required_protection()->set_disable_analog_output(
|
||||||
wvpl_key.output_protection().disable_analog_output());
|
wvpl_key.output_protection().disable_analog_output());
|
||||||
|
|
||||||
|
sdk_key_container->mutable_required_protection()->set_disable_digital_output(
|
||||||
|
wvpl_key.output_protection().disable_digital_output());
|
||||||
|
|
||||||
if (wvpl_key.output_protection().disable_digital_output()) {
|
if (wvpl_key.output_protection().disable_digital_output()) {
|
||||||
sdk_key_container->mutable_required_protection()->set_hdcp(
|
sdk_key_container->mutable_required_protection()->set_hdcp(
|
||||||
License::KeyContainer::OutputProtection::HDCP_NO_DIGITAL_OUTPUT);
|
License::KeyContainer::OutputProtection::HDCP_NO_DIGITAL_OUTPUT);
|
||||||
}
|
}
|
||||||
CopyCGMS(wvpl_key.output_protection().cgms(),
|
|
||||||
sdk_key_container->mutable_requested_protection());
|
|
||||||
|
|
||||||
|
// Transfer HDCP from requested output protection value.
|
||||||
|
CopyCGMS(wvpl_key.output_protection().cgms(),
|
||||||
|
sdk_key_container->mutable_required_protection());
|
||||||
|
if (wvpl_key.requested_output_protection().hdcp() != HDCP_NONE) {
|
||||||
|
CopyHDCP(wvpl_key.requested_output_protection().hdcp(),
|
||||||
|
sdk_key_container->mutable_requested_protection());
|
||||||
|
}
|
||||||
|
if (wvpl_key.requested_output_protection().disable_analog_output()) {
|
||||||
|
sdk_key_container->mutable_requested_protection()
|
||||||
|
->set_disable_analog_output(
|
||||||
|
wvpl_key.requested_output_protection().disable_analog_output());
|
||||||
|
}
|
||||||
|
if (wvpl_key.requested_output_protection().disable_digital_output()) {
|
||||||
|
sdk_key_container->mutable_requested_protection()->set_hdcp(
|
||||||
|
License::KeyContainer::OutputProtection::HDCP_NO_DIGITAL_OUTPUT);
|
||||||
|
}
|
||||||
|
if (wvpl_key.requested_output_protection().cgms() != CGMS_NONE) {
|
||||||
|
CopyCGMS(wvpl_key.requested_output_protection().cgms(),
|
||||||
|
sdk_key_container->mutable_requested_protection());
|
||||||
|
}
|
||||||
// Transfer Video resultion constraints.
|
// Transfer Video resultion constraints.
|
||||||
const std::vector<WvPLVideoResolutionConstraint>& video_constraints =
|
const std::vector<WvPLVideoResolutionConstraint>& video_constraints =
|
||||||
wvpl_key.video_resolution_constraints();
|
wvpl_key.video_resolution_constraints();
|
||||||
@@ -400,7 +429,7 @@ void WvPLSDKSession::CopyProvisionedDeviceInfo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
WvPLStatus WvPLSDKSession::ParseLicenseRequest() {
|
WvPLStatus WvPLSDKSession::ParseLicenseRequest() {
|
||||||
WvPLStatus status = util::OkStatus();
|
WvPLStatus status;
|
||||||
if (license_request_from_cdm_.empty() && sdk_license_request_ == nullptr) {
|
if (license_request_from_cdm_.empty() && sdk_license_request_ == nullptr) {
|
||||||
return WvPLStatus(error_space, widevine::SIGNED_MESSAGE_PARSE_ERROR,
|
return WvPLStatus(error_space, widevine::SIGNED_MESSAGE_PARSE_ERROR,
|
||||||
"License request from cdm is empty or null");
|
"License request from cdm is empty or null");
|
||||||
@@ -491,7 +520,7 @@ WvPLStatus WvPLSDKSession::ParseLicenseRequest() {
|
|||||||
}
|
}
|
||||||
request_type_ = sdk_license_request_->type();
|
request_type_ = sdk_license_request_->type();
|
||||||
}
|
}
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WvPLSDKSession::IsChromeCDM() const {
|
bool WvPLSDKSession::IsChromeCDM() const {
|
||||||
@@ -503,9 +532,9 @@ bool WvPLSDKSession::IsChromeCDM() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
WvPLStatus WvPLSDKSession::GetClientInfo(WvPLClientInfo* client_info) const {
|
WvPLStatus WvPLSDKSession::GetClientInfo(WvPLClientInfo* client_info) const {
|
||||||
WvPLStatus status = util::OkStatus();
|
WvPLStatus status;
|
||||||
if (client_info == nullptr) {
|
if (client_info == nullptr) {
|
||||||
return WvPLStatus(error_space, util::error::INVALID_ARGUMENT,
|
return WvPLStatus(error_space, error::INVALID_ARGUMENT,
|
||||||
"client_info is NULL");
|
"client_info is NULL");
|
||||||
}
|
}
|
||||||
if (!has_client_id_) {
|
if (!has_client_id_) {
|
||||||
@@ -557,11 +586,11 @@ WvPLStatus WvPLSDKSession::GetClientInfo(WvPLClientInfo* client_info) const {
|
|||||||
WvPLStatus WvPLSDKSession::VerifyRemoteAttestation() {
|
WvPLStatus WvPLSDKSession::VerifyRemoteAttestation() {
|
||||||
DCHECK(signed_message_request_from_cdm_);
|
DCHECK(signed_message_request_from_cdm_);
|
||||||
if (!signed_message_request_from_cdm_->has_remote_attestation()) {
|
if (!signed_message_request_from_cdm_->has_remote_attestation()) {
|
||||||
return WvPLStatus(error_space, util::error::INTERNAL,
|
return WvPLStatus(error_space, error::INTERNAL,
|
||||||
"Remote Attestation not specified");
|
"Remote Attestation not specified");
|
||||||
} else if (!signed_message_request_from_cdm_->remote_attestation()
|
} else if (!signed_message_request_from_cdm_->remote_attestation()
|
||||||
.has_certificate()) {
|
.has_certificate()) {
|
||||||
return WvPLStatus(error_space, util::error::INVALID_ARGUMENT,
|
return WvPLStatus(error_space, error::INVALID_ARGUMENT,
|
||||||
"Remote Attestation Certificate not specified");
|
"Remote Attestation Certificate not specified");
|
||||||
} else {
|
} else {
|
||||||
WvPLStatus ra_status =
|
WvPLStatus ra_status =
|
||||||
@@ -570,14 +599,14 @@ WvPLStatus WvPLSDKSession::VerifyRemoteAttestation() {
|
|||||||
signed_message_request_from_cdm_->remote_attestation(),
|
signed_message_request_from_cdm_->remote_attestation(),
|
||||||
&remote_attestation_cert_serial_number_);
|
&remote_attestation_cert_serial_number_);
|
||||||
}
|
}
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
WvPLStatus WvPLSDKSession::GetClientCapabilities(
|
WvPLStatus WvPLSDKSession::GetClientCapabilities(
|
||||||
WvPLClientCapabilities* client_capabilities) const {
|
WvPLClientCapabilities* client_capabilities) const {
|
||||||
WvPLStatus status = util::OkStatus();
|
WvPLStatus status;
|
||||||
if (client_capabilities == nullptr) {
|
if (client_capabilities == nullptr) {
|
||||||
return WvPLStatus(error_space, util::error::INVALID_ARGUMENT,
|
return WvPLStatus(error_space, error::INVALID_ARGUMENT,
|
||||||
"client_capabilities is NULL");
|
"client_capabilities is NULL");
|
||||||
}
|
}
|
||||||
if (!has_client_id_) {
|
if (!has_client_id_) {
|
||||||
@@ -592,9 +621,9 @@ WvPLStatus WvPLSDKSession::GetClientCapabilities(
|
|||||||
WvPLStatus WvPLSDKSession::GetWvPLClientCapabilities(
|
WvPLStatus WvPLSDKSession::GetWvPLClientCapabilities(
|
||||||
const widevine::ClientIdentification& client_id,
|
const widevine::ClientIdentification& client_id,
|
||||||
WvPLClientCapabilities* client_capabilities) const {
|
WvPLClientCapabilities* client_capabilities) const {
|
||||||
WvPLStatus status = util::OkStatus();
|
WvPLStatus status;
|
||||||
if (client_capabilities == nullptr) {
|
if (client_capabilities == nullptr) {
|
||||||
return WvPLStatus(error_space, util::error::INVALID_ARGUMENT,
|
return WvPLStatus(error_space, error::INVALID_ARGUMENT,
|
||||||
"client_capabilities is NULL");
|
"client_capabilities is NULL");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -653,22 +682,86 @@ WvPLStatus WvPLSDKSession::GetPsshData(
|
|||||||
WvPLWidevinePsshData* wvpl_widevine_pssh_data) const {
|
WvPLWidevinePsshData* wvpl_widevine_pssh_data) const {
|
||||||
DCHECK(wvpl_widevine_pssh_data);
|
DCHECK(wvpl_widevine_pssh_data);
|
||||||
if (wvpl_widevine_pssh_data == nullptr) {
|
if (wvpl_widevine_pssh_data == nullptr) {
|
||||||
return WvPLStatus(error_space, util::error::INVALID_ARGUMENT,
|
return WvPLStatus(error_space, error::INVALID_ARGUMENT,
|
||||||
"wvpl_widevine_pssh_data is null");
|
"wvpl_widevine_pssh_data is null");
|
||||||
}
|
}
|
||||||
if (!has_pssh_data_) {
|
if (!has_pssh_data_) {
|
||||||
// TODO(b/115784237): Fix calling ParsePsshData within base class.
|
DCHECK(sdk_license_request_);
|
||||||
WvPLStatus status = ParsePsshData(wvpl_widevine_pssh_data);
|
if (sdk_license_request_ == nullptr) {
|
||||||
return status;
|
return WvPLStatus(error_space, error::INVALID_ARGUMENT,
|
||||||
|
"sdk_license_request_ is null");
|
||||||
|
}
|
||||||
|
if (request_type() == LicenseRequest::NEW) {
|
||||||
|
ContentInfo content_info;
|
||||||
|
WvPLStatus status = widevine::ParseContentId(
|
||||||
|
sdk_license_request_->content_id(), &content_info);
|
||||||
|
if (!status.ok()) {
|
||||||
|
return WvPLStatus(error_space, error::INTERNAL,
|
||||||
|
"Failed to get pssh data. GetContentInfo() failed.");
|
||||||
|
}
|
||||||
|
if (content_info.content_info_entry().empty()) {
|
||||||
|
return WvPLStatus(error_space, error::INTERNAL,
|
||||||
|
"Failed to get pssh data. ContentInfo is empty.");
|
||||||
|
}
|
||||||
|
WidevinePsshData wv_pssh;
|
||||||
|
if (content_info.init_data_type() ==
|
||||||
|
LicenseRequest::ContentIdentification::InitData::CENC) {
|
||||||
|
for (size_t i = 0; i < content_info.content_info_entry().size(); ++i) {
|
||||||
|
if (!content_info.content_info_entry(i).has_pssh()) {
|
||||||
|
return WvPLStatus(error_space,
|
||||||
|
widevine::INVALID_WIDEVINE_PSSH_DATA,
|
||||||
|
"wvpl_widevine_pssh_data is empty");
|
||||||
|
}
|
||||||
|
if (content_info.content_info_entry(i).pssh().has_widevine_data()) {
|
||||||
|
wv_pssh = content_info.content_info_entry(i).pssh().widevine_data();
|
||||||
|
}
|
||||||
|
if (wv_pssh.has_content_id()) {
|
||||||
|
wvpl_widevine_pssh_data->set_content_id(wv_pssh.content_id());
|
||||||
|
}
|
||||||
|
for (int idx = 0; idx < wv_pssh.key_ids().size(); ++idx) {
|
||||||
|
wvpl_widevine_pssh_data->set_key_id(wv_pssh.key_ids(idx));
|
||||||
|
}
|
||||||
|
for (int idx = 0; idx < wv_pssh.entitled_keys().size(); ++idx) {
|
||||||
|
WvPLEntitledKey wvpl_entitled_key;
|
||||||
|
wvpl_entitled_key.set_entitlement_key_id(
|
||||||
|
wv_pssh.entitled_keys(idx).entitlement_key_id());
|
||||||
|
wvpl_entitled_key.set_key_id(wv_pssh.entitled_keys(idx).key_id());
|
||||||
|
wvpl_entitled_key.set_key_bytes(wv_pssh.entitled_keys(idx).key());
|
||||||
|
wvpl_entitled_key.set_entitlement_key_iv(
|
||||||
|
wv_pssh.entitled_keys(idx).iv());
|
||||||
|
wvpl_entitled_key.set_entitlement_key_size_bytes(
|
||||||
|
wv_pssh.entitled_keys(idx).entitlement_key_size_bytes());
|
||||||
|
wvpl_widevine_pssh_data->add_entitled_key(wvpl_entitled_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
} else if (content_info.init_data_type() ==
|
||||||
|
LicenseRequest::ContentIdentification::InitData::WEBM) {
|
||||||
|
for (size_t i = 0; i < content_info.content_info_entry().size(); ++i) {
|
||||||
|
for (int idx = 0;
|
||||||
|
idx < content_info.content_info_entry(i).key_ids().size();
|
||||||
|
++idx) {
|
||||||
|
wvpl_widevine_pssh_data->set_key_id(
|
||||||
|
content_info.content_info_entry(i).key_ids(idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return WvPLStatus(error_space, error::INVALID_ARGUMENT,
|
||||||
|
"Failed to get pssh data. Widevine PSSH not found.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// A PSSH with the widevine header wasn't found, so return error.
|
||||||
|
return WvPLStatus(error_space, error::NOT_FOUND,
|
||||||
|
"Failed to get pssh data. Widevine PSSH not found.");
|
||||||
}
|
}
|
||||||
*wvpl_widevine_pssh_data = pssh_data_;
|
*wvpl_widevine_pssh_data = pssh_data_;
|
||||||
return util::OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
WvPLStatus WvPLSDKSession::GetDeviceInfo(WvPLDeviceInfo* device_info) const {
|
WvPLStatus WvPLSDKSession::GetDeviceInfo(WvPLDeviceInfo* device_info) const {
|
||||||
WvPLStatus status = util::OkStatus();
|
WvPLStatus status;
|
||||||
if (device_info == nullptr) {
|
if (device_info == nullptr) {
|
||||||
return WvPLStatus(error_space, util::error::INVALID_ARGUMENT,
|
return WvPLStatus(error_space, error::INVALID_ARGUMENT,
|
||||||
"device_info is NULL");
|
"device_info is NULL");
|
||||||
}
|
}
|
||||||
if (!HasSystemId()) {
|
if (!HasSystemId()) {
|
||||||
@@ -733,5 +826,31 @@ uint32_t WvPLSDKSession::GetSystemId() const {
|
|||||||
CHECK(system_id_);
|
CHECK(system_id_);
|
||||||
return *system_id_;
|
return *system_id_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WvPLSDKSession::is_offline_license() const {
|
||||||
|
DCHECK(sdk_license_request_);
|
||||||
|
if (sdk_license_request_ == nullptr) return false;
|
||||||
|
|
||||||
|
if (!sdk_license_request_->has_content_id()) return false;
|
||||||
|
const LicenseRequest::ContentIdentification& content_id =
|
||||||
|
sdk_license_request_->content_id();
|
||||||
|
if (content_id.has_init_data()) {
|
||||||
|
return content_id.init_data().license_type() == widevine::OFFLINE;
|
||||||
|
}
|
||||||
|
if (content_id.has_cenc_id_deprecated()) {
|
||||||
|
return content_id.cenc_id_deprecated().license_type() ==
|
||||||
|
widevine::OFFLINE;
|
||||||
|
}
|
||||||
|
if (content_id.has_webm_id_deprecated()) {
|
||||||
|
return content_id.webm_id_deprecated().license_type() ==
|
||||||
|
widevine::OFFLINE;
|
||||||
|
}
|
||||||
|
if (content_id.has_existing_license()) {
|
||||||
|
return content_id.existing_license().license_id().type() ==
|
||||||
|
widevine::OFFLINE;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace wv_pl_sdk
|
} // namespace wv_pl_sdk
|
||||||
} // namespace widevine_server
|
} // namespace widevine_server
|
||||||
|
|||||||
15
sdk/external/common/wvpl/wvpl_sdk_session.h
vendored
15
sdk/external/common/wvpl/wvpl_sdk_session.h
vendored
@@ -105,6 +105,13 @@ class WvPLSDKSession {
|
|||||||
return request_type_;
|
return request_type_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the license type is offline, otherwise return false.
|
||||||
|
*
|
||||||
|
* @return bool.
|
||||||
|
*/
|
||||||
|
virtual bool is_offline_license() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const widevine::DrmRootCertificate* drm_root_certificate_;
|
const widevine::DrmRootCertificate* drm_root_certificate_;
|
||||||
std::string user_agent_;
|
std::string user_agent_;
|
||||||
@@ -206,14 +213,6 @@ class WvPLSDKSession {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<uint32_t> system_id_;
|
std::unique_ptr<uint32_t> system_id_;
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses WvPLWidevinePsshData in the new license request.
|
|
||||||
*
|
|
||||||
* @return WvPLStatus - Status::OK if success, else error.
|
|
||||||
*/
|
|
||||||
virtual WvPLStatus ParsePsshData(
|
|
||||||
WvPLWidevinePsshData* wvpl_widevine_pssh_data) const = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace wv_pl_sdk
|
} // namespace wv_pl_sdk
|
||||||
|
|||||||
4
sdk/external/common/wvpl/wvpl_types.h
vendored
4
sdk/external/common/wvpl/wvpl_types.h
vendored
@@ -15,7 +15,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "util/status.h"
|
#include "common/status.h"
|
||||||
|
|
||||||
// TODO(user) Split wvpl_types.h into wvpl_common_types.h ,
|
// TODO(user) Split wvpl_types.h into wvpl_common_types.h ,
|
||||||
// wvpl_license_sdk_types.h, wvpl_proxy_sdk_types.h and
|
// wvpl_license_sdk_types.h, wvpl_proxy_sdk_types.h and
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
namespace widevine_server {
|
namespace widevine_server {
|
||||||
namespace wv_pl_sdk {
|
namespace wv_pl_sdk {
|
||||||
typedef widevine::util::Status WvPLStatus;
|
typedef widevine::Status WvPLStatus;
|
||||||
typedef uint32_t uint32_t;
|
typedef uint32_t uint32_t;
|
||||||
typedef int64_t int64_t;
|
typedef int64_t int64_t;
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ cc_library(
|
|||||||
],
|
],
|
||||||
deps = [
|
deps = [
|
||||||
"//external:gtest",
|
"//external:gtest",
|
||||||
"//util:status",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,7 @@
|
|||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
#define EXPECT_OK(expression) \
|
#define EXPECT_OK(expression) EXPECT_EQ(error::OK, expression.error_code())
|
||||||
EXPECT_EQ(util::error::OK, expression.error_code())
|
#define ASSERT_OK(expression) ASSERT_EQ(error::OK, expression.error_code())
|
||||||
#define ASSERT_OK(expression) \
|
|
||||||
ASSERT_EQ(util::error::OK, expression.error_code())
|
|
||||||
|
|
||||||
#endif // TESTING_GUNIT_H_
|
#endif // TESTING_GUNIT_H_
|
||||||
|
|||||||
27
util/BUILD
27
util/BUILD
@@ -15,22 +15,6 @@ filegroup(
|
|||||||
name = "binary_release_files",
|
name = "binary_release_files",
|
||||||
srcs = [
|
srcs = [
|
||||||
"error_space.h",
|
"error_space.h",
|
||||||
"status.h",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
cc_library(
|
|
||||||
name = "status",
|
|
||||||
srcs = [
|
|
||||||
"status.cc",
|
|
||||||
],
|
|
||||||
hdrs = [
|
|
||||||
"status.h",
|
|
||||||
],
|
|
||||||
deps = [
|
|
||||||
":error_space",
|
|
||||||
"//base",
|
|
||||||
"@abseil_repo//absl/strings",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -43,17 +27,8 @@ cc_library(
|
|||||||
name = "proto_status",
|
name = "proto_status",
|
||||||
hdrs = ["proto_status.h"],
|
hdrs = ["proto_status.h"],
|
||||||
deps = [
|
deps = [
|
||||||
":status",
|
|
||||||
"//external:protobuf",
|
"//external:protobuf",
|
||||||
],
|
"//util:error_space",
|
||||||
)
|
|
||||||
|
|
||||||
cc_test(
|
|
||||||
name = "status_test",
|
|
||||||
srcs = ["status_test.cc"],
|
|
||||||
deps = [
|
|
||||||
":status",
|
|
||||||
"//testing:gunit_main",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -49,11 +49,11 @@ class ErrorSpaceImpl : public ErrorSpace {
|
|||||||
// pointer to stateless static methods, so that clients of ErrorSpaceImpl are
|
// pointer to stateless static methods, so that clients of ErrorSpaceImpl are
|
||||||
// safe to have constexpr global instances.
|
// safe to have constexpr global instances.
|
||||||
static std::string SpaceNameImpl(const ErrorSpace* /*space*/) {
|
static std::string SpaceNameImpl(const ErrorSpace* /*space*/) {
|
||||||
return T::SpaceName();
|
return T::space_name();
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string CodeToStringImpl(const ErrorSpace* /*space*/, int code) {
|
static std::string CodeToStringImpl(const ErrorSpace* /*space*/, int code) {
|
||||||
return T::CodeToString(code);
|
return T::code_to_string(code);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -16,14 +16,16 @@ namespace {
|
|||||||
|
|
||||||
class Space1 : public util::ErrorSpaceImpl<Space1> {
|
class Space1 : public util::ErrorSpaceImpl<Space1> {
|
||||||
public:
|
public:
|
||||||
static std::string SpaceName() { return "Space1"; }
|
static std::string space_name() { return "Space1"; }
|
||||||
static std::string CodeToString(int code) { return "Test" + std::to_string(code); }
|
static std::string code_to_string(int code) {
|
||||||
|
return "Test" + std::to_string(code);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(ErrorSpaceTest, Basic) {
|
TEST(ErrorSpaceTest, Basic) {
|
||||||
const ErrorSpace* space1 = Space1::Get();
|
const ErrorSpace* space1 = Space1::Get();
|
||||||
EXPECT_EQ("Space1", space1->SpaceName());
|
EXPECT_EQ("Space1", space1->SpaceName());
|
||||||
EXPECT_EQ(Space1::CodeToString(23), space1->String(23));
|
EXPECT_EQ(Space1::code_to_string(23), space1->String(23));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@@ -11,24 +11,26 @@
|
|||||||
|
|
||||||
#include "google/protobuf/descriptor.h"
|
#include "google/protobuf/descriptor.h"
|
||||||
#include "google/protobuf/generated_enum_reflection.h"
|
#include "google/protobuf/generated_enum_reflection.h"
|
||||||
#include "util/status.h"
|
#include "util/error_space.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
namespace util {
|
namespace util {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class ProtoEnumErrorSpace : public ErrorSpaceImpl<ProtoEnumErrorSpace<T>> {
|
class ProtoEnumErrorSpace
|
||||||
|
: public util::ErrorSpaceImpl<ProtoEnumErrorSpace<T>> {
|
||||||
public:
|
public:
|
||||||
static std::string SpaceName() {
|
static std::string space_name() {
|
||||||
return google::protobuf::GetEnumDescriptor<T>()->full_name();
|
return google::protobuf::GetEnumDescriptor<T>()->full_name();
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string CodeToString(int code) {
|
static std::string code_to_string(int code) {
|
||||||
const google::protobuf::EnumValueDescriptor* v =
|
const google::protobuf::EnumValueDescriptor* v =
|
||||||
google::protobuf::GetEnumDescriptor<T>()->FindValueByNumber(code);
|
google::protobuf::GetEnumDescriptor<T>()->FindValueByNumber(code);
|
||||||
if (v) return v->name();
|
if (v) return v->name();
|
||||||
return std::to_string(code);
|
return std::to_string(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace util
|
} // namespace util
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "util/proto_status.h"
|
#include "util/proto_status.h"
|
||||||
|
|
||||||
#include "testing/gunit.h"
|
#include "testing/gunit.h"
|
||||||
|
#include "common/status.h"
|
||||||
#include "protos/public/errors.pb.h"
|
#include "protos/public/errors.pb.h"
|
||||||
|
|
||||||
namespace widevine {
|
namespace widevine {
|
||||||
@@ -31,10 +32,18 @@ TEST(StatusTest, Same) {
|
|||||||
Status status1(ProtoEnumErrorSpace<Errors>::Get(), PROVIDER_ID_MISMATCH,
|
Status status1(ProtoEnumErrorSpace<Errors>::Get(), PROVIDER_ID_MISMATCH,
|
||||||
"provider_id_mismatch");
|
"provider_id_mismatch");
|
||||||
Status status2(ProtoEnumErrorSpace<Errors>::Get(), PROVIDER_ID_MISMATCH,
|
Status status2(ProtoEnumErrorSpace<Errors>::Get(), PROVIDER_ID_MISMATCH,
|
||||||
"this is a provider_id_mismatch error");
|
"provider_id_mismatch");
|
||||||
EXPECT_EQ(status1, status2);
|
EXPECT_EQ(status1, status2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(StatusTest, ErrorMessageMismatch) {
|
||||||
|
Status status1(ProtoEnumErrorSpace<Errors>::Get(), PROVIDER_ID_MISMATCH,
|
||||||
|
"provider_id_mismatch");
|
||||||
|
Status status2(ProtoEnumErrorSpace<Errors>::Get(), PROVIDER_ID_MISMATCH,
|
||||||
|
"this is a provider_id_mismatch error");
|
||||||
|
EXPECT_NE(status1, status2);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(StatusTest, NotTheSameStatus) {
|
TEST(StatusTest, NotTheSameStatus) {
|
||||||
Status status1(ProtoEnumErrorSpace<Errors>::Get(), PROVIDER_ID_MISMATCH,
|
Status status1(ProtoEnumErrorSpace<Errors>::Get(), PROVIDER_ID_MISMATCH,
|
||||||
"provider_id_mismatch");
|
"provider_id_mismatch");
|
||||||
|
|||||||
@@ -1,62 +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 <string>
|
|
||||||
|
|
||||||
#include "base/macros.h"
|
|
||||||
#include "absl/strings/str_cat.h"
|
|
||||||
#include "util/status.h"
|
|
||||||
|
|
||||||
namespace widevine {
|
|
||||||
namespace util {
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
const char* kLicenseServerStatusMessage[] = {"OK",
|
|
||||||
"UNKNOWN_ERROR",
|
|
||||||
"UNKNOWN_ERROR",
|
|
||||||
"INVALID_ARGUMENT",
|
|
||||||
"UNKNOWN_ERROR",
|
|
||||||
"NOT_FOUND",
|
|
||||||
"ALREADY_EXISTS",
|
|
||||||
"PERMISSION_DENIED",
|
|
||||||
"UNKNOWN_ERROR",
|
|
||||||
"UNKNOWN_ERROR",
|
|
||||||
"UNKNOWN_ERROR",
|
|
||||||
"UNKNOWN_ERROR",
|
|
||||||
"UNIMPLEMENTED",
|
|
||||||
"INTERNAL",
|
|
||||||
"UNAVAILABLE"};
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
std::string GenericErrorSpace::SpaceName() { return "generic"; }
|
|
||||||
|
|
||||||
std::string GenericErrorSpace::CodeToString(int code) {
|
|
||||||
static_assert(
|
|
||||||
arraysize(kLicenseServerStatusMessage) == error::NUM_ERRORS,
|
|
||||||
"mismatching license_server_sdk status message and license_server_sdk "
|
|
||||||
"status.");
|
|
||||||
|
|
||||||
if (code >= 0 && code < error::NUM_ERRORS)
|
|
||||||
return kLicenseServerStatusMessage[code];
|
|
||||||
return std::to_string(code);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Status::ToString() const {
|
|
||||||
if (status_code_ == error::OK) return "OK";
|
|
||||||
return absl::StrCat("Errors::", error_space_->String(status_code_), ": ",
|
|
||||||
error_message_);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, const Status& x) {
|
|
||||||
os << x.ToString();
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace util
|
|
||||||
} // namespace widevine
|
|
||||||
Reference in New Issue
Block a user