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:
Fang Yu
2019-01-02 14:37:34 -08:00
parent a991e2dbb3
commit 79f14e6e0b
76 changed files with 2072 additions and 1513 deletions

2
BUILD
View File

@@ -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",

View File

@@ -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",
], ],
) )

View File

@@ -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,11 +192,11 @@ 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
@@ -205,18 +205,18 @@ 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());
@@ -224,7 +224,7 @@ util::Status CertificateClientCert::Initialize(
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());
@@ -232,29 +232,31 @@ util::Status CertificateClientCert::Initialize(
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

View File

@@ -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,8 +46,7 @@ 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.
@@ -118,9 +117,9 @@ 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; }
@@ -148,7 +147,7 @@ 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; }
@@ -162,7 +161,7 @@ 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;

View File

@@ -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,36 +410,35 @@ 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")),
}; };
@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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,46 +52,46 @@ 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");
} }
@@ -105,43 +106,43 @@ 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 =
@@ -154,14 +155,14 @@ 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() &&
@@ -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,7 +284,7 @@ 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.");
} }
} }
@@ -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

View File

@@ -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,11 +37,11 @@ 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_; }
@@ -58,8 +58,7 @@ 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).
@@ -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.

View File

@@ -114,8 +114,7 @@ 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));
} }
@@ -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,7 +313,7 @@ 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,
@@ -331,7 +330,7 @@ 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));
@@ -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,

View File

@@ -265,7 +265,7 @@ 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) {
@@ -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,11 +291,11 @@ 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");
} }
@@ -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,16 +341,15 @@ 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);
@@ -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,7 +445,7 @@ 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");
} }
@@ -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

View File

@@ -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,17 +56,14 @@ 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(
const std::string& serialized_certificate,
SignedDrmCertificate* signed_certificate, SignedDrmCertificate* signed_certificate,
DrmCertificate* certificate) const; DrmCertificate* certificate) const;
@@ -86,11 +83,11 @@ 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;

View File

@@ -33,7 +33,7 @@ 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,7 +44,7 @@ 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,7 +55,7 @@ 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,7 +111,7 @@ 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_));
} }
@@ -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,7 +153,7 @@ 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(
@@ -162,7 +162,7 @@ TEST_F(DrmRootCertificateTest, SuccessWithOutput) {
} }
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));
} }
@@ -170,7 +170,7 @@ TEST_F(DrmRootCertificateTest, InvalidSignedDrmCertificate) {
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

View File

@@ -107,40 +107,40 @@ 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");
} }
@@ -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,28 +181,28 @@ 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;
@@ -210,7 +210,7 @@ util::Status DrmServiceCertificate::DecryptClientIdentification(
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,11 +219,11 @@ 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() + ")");
} }
@@ -231,44 +231,44 @@ util::Status DrmServiceCertificate::DecryptClientIdentification(
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(

View File

@@ -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);

View File

@@ -69,7 +69,7 @@ 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(
@@ -79,13 +79,13 @@ 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(
@@ -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,8 +140,7 @@ 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,8 +219,7 @@ 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));
@@ -229,8 +227,7 @@ TEST_F(DrmServiceCertificateTest, MultipleCertsPerService) {
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));
@@ -238,8 +235,7 @@ TEST_F(DrmServiceCertificateTest, MultipleCertsPerService) {
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,8 +288,7 @@ 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,8 +305,7 @@ 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();
@@ -324,8 +318,7 @@ 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();
@@ -349,8 +342,7 @@ 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));

View File

@@ -113,35 +113,35 @@ 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()) + ")"));
} }
@@ -149,32 +149,32 @@ util::Status RemoteAttestationVerifier::VerifyRemoteAttestation(
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()) + ")"));
} }
@@ -183,26 +183,26 @@ util::Status RemoteAttestationVerifier::VerifyRemoteAttestation(
&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 +
")")); ")"));
@@ -217,8 +217,7 @@ 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()));
} }
@@ -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

View File

@@ -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,8 +50,8 @@ 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
@@ -61,8 +61,8 @@ 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:
@@ -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_;

View File

@@ -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

View File

@@ -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.

View File

@@ -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");

View File

@@ -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

View File

@@ -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

View File

@@ -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 {

View File

@@ -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

View File

@@ -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
View 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

View File

@@ -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_

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -18,31 +18,30 @@
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;
} }
@@ -53,8 +52,7 @@ 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;
} }

View File

@@ -14,7 +14,7 @@
#include <string> #include <string>
#include "util/status.h" #include "common/status.h"
namespace widevine { namespace widevine {
@@ -23,7 +23,7 @@ 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);

View File

@@ -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:

View File

@@ -13,15 +13,14 @@
#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

View File

@@ -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,7 +298,7 @@ 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");
} }
} }
@@ -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

View File

@@ -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; }

View File

@@ -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,7 +108,7 @@ 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) {
@@ -117,7 +117,7 @@ util::Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token,
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,
@@ -129,11 +129,10 @@ 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.");
} }
@@ -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,7 +161,7 @@ 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()) {
@@ -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");
} }
} }

View File

@@ -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);

View File

@@ -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());
} }

View File

@@ -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,16 +281,16 @@ 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");
} }
@@ -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,43 +352,41 @@ 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);
@@ -354,22 +399,20 @@ 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) {
@@ -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

View File

@@ -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_;

View File

@@ -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(&not_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(&not_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
View 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"],
)

View 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;
}

View 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;
}

View File

@@ -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",

View File

@@ -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()) {

View File

@@ -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_

View File

@@ -37,18 +37,17 @@ 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(
@@ -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,7 +107,7 @@ 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);
@@ -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,14 +128,14 @@ 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));
} }
@@ -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,14 +203,12 @@ 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);
@@ -235,7 +224,7 @@ 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");
} }

View File

@@ -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,8 +20,7 @@ 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

View File

@@ -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,8 +210,8 @@ 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));
} }
@@ -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());

View File

@@ -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,7 +364,7 @@ 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;
} }
@@ -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,7 +702,7 @@ 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;
} }
@@ -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,16 +804,11 @@ util::Status SessionImpl::GenerateSignedLicense(
*license.add_key() = *iter; *license.add_key() = *iter;
} }
} }
if (license_request_->type() == LicenseRequest::NEW) {
std::string provider_client_token = std::string provider_client_token =
GetProviderClientToken(*session_init, license_request_->client_id()); GetProviderClientToken(*session_init, license_request_->client_id());
if (!provider_client_token.empty()) {
license.set_provider_client_token(provider_client_token);
}
if (session_state) { if (session_state) {
if (license.has_provider_client_token()) { if (!provider_client_token.empty()) {
session_state->set_provider_client_token( session_state->set_provider_client_token(provider_client_token);
license.provider_client_token());
} else if (license_request_->client_id().has_provider_client_token()) { } else if (license_request_->client_id().has_provider_client_token()) {
session_state->set_provider_client_token( session_state->set_provider_client_token(
license_request_->client_id().provider_client_token()); license_request_->client_id().provider_client_token());
@@ -818,6 +816,10 @@ util::Status SessionImpl::GenerateSignedLicense(
session_state->set_license_counter( session_state->set_license_counter(
license_request_->client_id().license_counter()); license_request_->client_id().license_counter());
} }
if (license_request_->type() == LicenseRequest::NEW) {
if (!provider_client_token.empty()) {
license.set_provider_client_token(provider_client_token);
}
// 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,7 +849,7 @@ 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,7 +870,7 @@ 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;
} }
@@ -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:
break;
case PLATFORM_HARDWARE_VERIFIED:
// TODO(b/65054419): Deprecate remote_attestation_verified altogether.
license.set_remote_attestation_verified(true);
ABSL_FALLTHROUGH_INTENDED;
default:
license.set_platform_verification_status(platform_verification_status_); license.set_platform_verification_status(platform_verification_status_);
break; }
// TODO(b/65054419): Deprecate remote_attestation_verified altogether.
if (remote_attestation_verified_) {
license.set_remote_attestation_verified(true);
} }
@@ -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,8 +1054,7 @@ 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
@@ -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,7 +1092,7 @@ 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.");
} }
} }
@@ -1095,18 +1100,18 @@ util::Status SessionImpl::VerifyDeviceCapabilities(
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

View File

@@ -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,7 +65,7 @@ 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;
@@ -112,9 +112,9 @@ 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
@@ -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,12 +143,12 @@ 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;
@@ -160,13 +160,13 @@ 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);
@@ -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

View File

@@ -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();
} }

View File

@@ -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:
/** /**

View File

@@ -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

View File

@@ -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

View File

@@ -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];
} }

View File

@@ -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 {

View File

@@ -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",
], ],
) )

View File

@@ -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,7 +210,7 @@ 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");
} }

View File

@@ -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 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; 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

View File

@@ -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

View File

@@ -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;

View File

@@ -18,7 +18,6 @@ cc_library(
], ],
deps = [ deps = [
"//external:gtest", "//external:gtest",
"//util:status",
], ],
) )

View File

@@ -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_

View File

@@ -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",
], ],
) )

View File

@@ -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);
} }
}; };

View File

@@ -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

View File

@@ -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

View File

@@ -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");

View File

@@ -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