Update Simulcrypt ECMg

This commit is contained in:
Lu Chen
2020-07-24 18:17:12 -07:00
parent ed5a1d5db1
commit 785df31261
97 changed files with 3671 additions and 987 deletions

View File

@@ -16,10 +16,30 @@ filegroup(
name = "binary_release_files",
srcs = [
"certificate_type.h",
"default_device_security_profile_list.h",
"security_profile_list.h",
"status.h",
],
)
cc_library(
name = "playready_interface",
hdrs = ["playready_interface.h"],
deps = [
"//util:error_space",
"//protos/public:license_protocol_cc_proto",
],
)
cc_library(
name = "playready_sdk_impl",
hdrs = ["playready_sdk_impl.h"],
deps = [
":playready_interface",
"//protos/public:license_protocol_cc_proto",
],
)
cc_library(
name = "content_id_util",
srcs = ["content_id_util.cc"],
@@ -27,6 +47,7 @@ cc_library(
deps = [
":error_space",
":status",
"//base",
"//license_server_sdk/internal:sdk",
"//protos/public:errors_cc_proto",
"//protos/public:external_license_cc_proto",
@@ -67,9 +88,14 @@ cc_library(
hdrs = ["security_profile_list.h"],
deps = [
":client_id_util",
":device_status_list",
"//base",
"//external:protobuf",
"@abseil_repo//absl/synchronization",
"//protos/public:client_identification_cc_proto",
"//protos/public:device_certificate_status_cc_proto",
"//protos/public:device_common_cc_proto",
"//protos/public:device_security_profile_data_cc_proto",
"//protos/public:provisioned_device_info_cc_proto",
"//protos/public:security_profile_cc_proto",
],
@@ -80,6 +106,7 @@ cc_test(
timeout = "short",
srcs = ["security_profile_list_test.cc"],
deps = [
":client_id_util",
":security_profile_list",
"//base",
"//external:protobuf",
@@ -90,6 +117,40 @@ cc_test(
],
)
cc_library(
name = "default_device_security_profile_list",
srcs = ["default_device_security_profile_list.cc"],
hdrs = ["default_device_security_profile_list.h"],
deps = [
":client_id_util",
":device_status_list",
":security_profile_list",
"//base",
"//external:protobuf",
"//protos/public:client_identification_cc_proto",
"//protos/public:device_certificate_status_cc_proto",
"//protos/public:device_common_cc_proto",
"//protos/public:provisioned_device_info_cc_proto",
"//protos/public:security_profile_cc_proto",
],
)
cc_test(
name = "default_device_security_profile_list_test",
timeout = "short",
srcs = ["default_device_security_profile_list_test.cc"],
deps = [
":client_id_util",
":default_device_security_profile_list",
"//base",
"//external:protobuf",
"//testing:gunit_main",
"@abseil_repo//absl/memory",
"//protos/public:device_common_cc_proto",
"//protos/public:security_profile_cc_proto",
],
)
cc_library(
name = "status",
srcs = ["status.cc"],
@@ -120,6 +181,8 @@ cc_library(
"certificate_client_cert.cc",
"certificate_client_cert.h",
"client_cert.cc",
"dual_certificate_client_cert.cc",
"dual_certificate_client_cert.h",
"keybox_client_cert.cc",
],
hdrs = [
@@ -132,6 +195,7 @@ cc_library(
":ec_key",
":ec_util",
":error_space",
":hash_algorithm",
":openssl_util",
":random_util",
":rsa_key",
@@ -155,8 +219,11 @@ cc_test(
srcs = ["client_cert_test.cc"],
deps = [
":client_cert",
":ec_key",
":ec_test_keys",
":error_space",
":hash_algorithm",
":hash_algorithm_util",
":rsa_key",
":rsa_test_keys",
":sha_util",
@@ -179,6 +246,8 @@ cc_library(
":client_cert",
":drm_service_certificate",
":error_space",
":hash_algorithm",
":hash_algorithm_util",
":rsa_key",
":status",
"//base",
@@ -211,6 +280,8 @@ cc_test(
deps = [
":client_cert",
":device_status_list",
":hash_algorithm",
":hash_algorithm_util",
":rsa_key",
":rsa_test_keys",
":status",
@@ -235,6 +306,8 @@ cc_library(
":certificate_type",
":ec_key",
":error_space",
":hash_algorithm",
":hash_algorithm_util",
":rsa_key",
":sha_util",
":signer_public_key",
@@ -258,6 +331,8 @@ cc_test(
":ec_key",
":ec_test_keys",
":error_space",
":hash_algorithm",
":hash_algorithm_util",
":rsa_key",
":rsa_test_keys",
":test_drm_certificates",
@@ -338,9 +413,12 @@ cc_library(
srcs = ["rsa_key.cc"],
hdrs = ["rsa_key.h"],
deps = [
":hash_algorithm",
":rsa_util",
":sha_util",
"//base",
"@abseil_repo//absl/base:core_headers",
"@abseil_repo//absl/strings",
"//external:openssl",
],
)
@@ -371,6 +449,7 @@ cc_library(
testonly = 1,
hdrs = ["mock_rsa_key.h"],
deps = [
":hash_algorithm",
":rsa_key",
"//testing:gunit",
],
@@ -384,9 +463,11 @@ cc_library(
"ec_util.h",
],
deps = [
":hash_algorithm",
":openssl_util",
":private_key_util",
"//base",
"@abseil_repo//absl/base:core_headers",
"@abseil_repo//absl/memory",
"//external:openssl",
],
@@ -415,9 +496,11 @@ cc_library(
deps = [
":aes_cbc_util",
":ec_util",
":hash_algorithm",
":openssl_util",
":sha_util",
"//base",
"@abseil_repo//absl/base:core_headers",
"@abseil_repo//absl/memory",
"//external:openssl",
],
@@ -671,6 +754,7 @@ cc_library(
hdrs = ["signature_util.h"],
deps = [
":aes_cbc_util",
":hash_algorithm",
":rsa_key",
":sha_util",
":status",
@@ -774,6 +858,7 @@ cc_library(
":status",
":x509_cert",
"//base",
"@abseil_repo//absl/base:core_headers",
"@abseil_repo//absl/strings",
"@abseil_repo//absl/synchronization",
"//protos/public:client_identification_cc_proto",
@@ -795,6 +880,7 @@ cc_library(
":rsa_util",
":status",
"//base",
"@abseil_repo//absl/base:core_headers",
"@abseil_repo//absl/strings",
"@abseil_repo//absl/synchronization",
"//util/gtl:map_util",
@@ -813,6 +899,7 @@ cc_test(
":aes_cbc_util",
":drm_root_certificate",
":drm_service_certificate",
":hash_algorithm_util",
":rsa_key",
":rsa_test_keys",
":rsa_util",
@@ -849,6 +936,7 @@ cc_library(
":rsa_key",
":status",
"//base",
"@abseil_repo//absl/base:core_headers",
"@abseil_repo//absl/strings",
"@abseil_repo//absl/synchronization",
"//external:openssl",
@@ -887,6 +975,7 @@ cc_library(
deps = [
":certificate_type",
":error_space",
":hash_algorithm_util",
":rsa_key",
":status",
":x509_cert",
@@ -901,6 +990,7 @@ cc_test(
timeout = "short",
srcs = ["vmp_checker_test.cc"],
deps = [
":hash_algorithm_util",
":rsa_key",
":vmp_checker",
"//base",
@@ -1012,6 +1102,7 @@ cc_library(
hdrs = ["signer_public_key.h"],
deps = [
":ec_key",
":hash_algorithm",
":rsa_key",
"@abseil_repo//absl/memory",
"//protos/public:drm_certificate_cc_proto",
@@ -1024,6 +1115,7 @@ cc_test(
deps = [
":ec_key",
":ec_test_keys",
":hash_algorithm",
":rsa_key",
":rsa_test_keys",
":signer_public_key",
@@ -1041,3 +1133,29 @@ cc_library(
"//common/oemcrypto_core_message/odk:kdo",
],
)
cc_library(
name = "hash_algorithm",
hdrs = ["hash_algorithm.h"],
)
cc_library(
name = "hash_algorithm_util",
srcs = ["hash_algorithm_util.cc"],
hdrs = ["hash_algorithm_util.h"],
deps = [
":hash_algorithm",
"//base",
"//protos/public:hash_algorithm_cc_proto",
],
)
cc_test(
name = "hash_algorithm_util_test",
srcs = ["hash_algorithm_util_test.cc"],
deps = [
":hash_algorithm",
":hash_algorithm_util",
"//testing:gunit_main",
],
)

View File

@@ -7,6 +7,7 @@
////////////////////////////////////////////////////////////////////////////////
#include "common/aes_cbc_util.h"
#include "testing/gmock.h"
#include "testing/gunit.h"

View File

@@ -66,10 +66,11 @@ class ClientCertAlgorithmRSA : public ClientCertAlgorithm {
}
Status VerifySignature(const std::string& message,
HashAlgorithm hash_algorithm,
const std::string& signature) const override {
CHECK(rsa_public_key_);
if (!rsa_public_key_->VerifySignature(message, signature)) {
if (!rsa_public_key_->VerifySignature(message, hash_algorithm, signature)) {
return Status(error_space, INVALID_SIGNATURE, "");
}
return OkStatus();
@@ -143,10 +144,12 @@ class ClientCertAlgorithmECC : public ClientCertAlgorithm {
}
Status VerifySignature(const std::string& message,
HashAlgorithm hash_algorithm,
const std::string& signature) const override {
CHECK(client_ecc_public_key_);
if (!client_ecc_public_key_->VerifySignature(message, signature)) {
if (!client_ecc_public_key_->VerifySignature(message, hash_algorithm,
signature)) {
return Status(error_space, INVALID_SIGNATURE, "");
}
return OkStatus();
@@ -165,7 +168,7 @@ class ClientCertAlgorithmECC : public ClientCertAlgorithm {
}
SignedMessage::SessionKeyType session_key_type() const override {
return SignedMessage::EPHERMERAL_ECC_PUBLIC_KEY;
return SignedMessage::EPHEMERAL_ECC_PUBLIC_KEY;
}
private:
@@ -259,11 +262,11 @@ Status CertificateClientCert::Initialize(
}
Status CertificateClientCert::VerifySignature(
const std::string& message, const std::string& signature,
ProtocolVersion protocol_version) const {
const std::string& message, HashAlgorithm hash_algorithm,
const std::string& signature, ProtocolVersion protocol_version) const {
return algorithm_->VerifySignature(
protocol_version < VERSION_2_2 ? message : Sha512_Hash(message),
signature);
hash_algorithm, signature);
}
void CertificateClientCert::GenerateSigningKey(

View File

@@ -10,6 +10,7 @@
#define COMMON_CERTIFICATE_CLIENT_CERT_H_
#include "common/client_cert.h"
#include "common/hash_algorithm.h"
#include "protos/public/drm_certificate.pb.h"
namespace widevine {
@@ -30,6 +31,7 @@ class ClientCertAlgorithm {
// Verify the |signature| of an incoming request |message| using the public
// key from the drm certificate.
virtual Status VerifySignature(const std::string& message,
HashAlgorithm hash_algorithm,
const std::string& signature) const = 0;
// Returns the key to be used in key derivation of the license
@@ -57,6 +59,7 @@ class CertificateClientCert : public ClientCert {
const std::string& serialized_certificate);
Status VerifySignature(const std::string& message,
HashAlgorithm hash_algorithm,
const std::string& signature,
ProtocolVersion protocol_version) const override;
@@ -70,6 +73,7 @@ class CertificateClientCert : public ClientCert {
SignedMessage::SessionKeyType key_type() const override {
return algorithm_->session_key_type();
}
bool using_dual_certificate() const override { return false; }
const std::string& serial_number() const override {
return device_cert_.serial_number();
}

View File

@@ -17,6 +17,7 @@
#include "absl/strings/escaping.h"
#include "common/certificate_client_cert.h"
#include "common/crypto_util.h"
#include "common/dual_certificate_client_cert.h"
#include "common/error_space.h"
#include "common/keybox_client_cert.h"
#include "common/random_util.h"
@@ -52,23 +53,34 @@ uint32_t KeyboxClientCert::GetSystemId(const std::string& keybox_bytes) {
return WvmTokenHandler::GetSystemId(keybox_bytes);
}
Status ClientCert::Create(
const DrmRootCertificate* root_certificate,
widevine::ClientIdentification::TokenType token_type,
const std::string& token, std::unique_ptr<ClientCert>* client_cert) {
Status ClientCert::Create(const DrmRootCertificate* root_certificate,
const widevine::ClientIdentification& client_id,
std::unique_ptr<ClientCert>* client_cert) {
CHECK(client_cert);
Status status;
switch (token_type) {
switch (client_id.type()) {
case ClientIdentification::KEYBOX:
return CreateWithKeybox(token, client_cert);
return CreateWithKeybox(client_id.token(), client_cert);
case ClientIdentification::DRM_DEVICE_CERTIFICATE:
return CreateWithDrmCertificate(root_certificate, token, client_cert);
if (!client_id.has_device_credentials()) {
return CreateWithDrmCertificate(root_certificate, client_id.token(),
client_cert);
}
// Assumes |client_id.token| is the signing cert and
// |client_id.device_credentials().token| is the encryption cert.
if (client_id.device_credentials().type() !=
ClientIdentification::DRM_DEVICE_CERTIFICATE)
return Status(error_space, INVALID_DRM_CERTIFICATE,
"unsupported-encryption-certificate");
return CreateWithDualDrmCertificates(
root_certificate, client_id.token(),
client_id.device_credentials().token(), client_cert);
default:
return Status(error_space, error::UNIMPLEMENTED,
"client-type-not-implemented");
}
return OkStatus();
}
@@ -78,6 +90,7 @@ Status ClientCert::CreateWithDrmCertificate(
const DrmRootCertificate* root_certificate,
const std::string& drm_certificate,
std::unique_ptr<ClientCert>* client_cert) {
CHECK(root_certificate);
CHECK(client_cert);
auto device_cert = absl::make_unique<CertificateClientCert>();
Status status = device_cert->Initialize(root_certificate, drm_certificate);
@@ -87,6 +100,22 @@ Status ClientCert::CreateWithDrmCertificate(
return status;
}
Status ClientCert::CreateWithDualDrmCertificates(
const DrmRootCertificate* root_certificate,
const std::string& signing_drm_certificate,
const std::string& encryption_drm_certificate,
std::unique_ptr<ClientCert>* client_cert) {
CHECK(root_certificate);
CHECK(client_cert);
auto device_cert = absl::make_unique<DualCertificateClientCert>();
Status status = device_cert->Initialize(
root_certificate, signing_drm_certificate, encryption_drm_certificate);
if (status.ok()) {
*client_cert = std::move(device_cert);
}
return status;
}
Status ClientCert::CreateWithKeybox(const std::string& keybox_token,
std::unique_ptr<ClientCert>* client_cert) {
CHECK(client_cert);

View File

@@ -12,8 +12,11 @@
#include <memory>
#include "common/drm_root_certificate.h"
#include "common/error_space.h"
#include "common/hash_algorithm.h"
#include "common/status.h"
#include "protos/public/client_identification.pb.h"
#include "protos/public/errors.pb.h"
#include "protos/public/license_protocol.pb.h"
namespace widevine {
@@ -24,17 +27,10 @@ class ClientCert {
ClientCert() = default;
public:
// Creates a ClientCert from the |token|. The type of ClientCert created is
// determined by the |token_type|.
static Status Create(
const DrmRootCertificate* root_certificate,
widevine::ClientIdentification::TokenType token_type,
const std::string& token, std::unique_ptr<ClientCert>* client_cert);
// Creates a Keybox based ClientCert. The |client_cert| is a caller supplied
// unique_ptr to receive the new ClientCert.
static Status CreateWithKeybox(const std::string& keybox_token,
std::unique_ptr<ClientCert>* client_cert);
// Creates a Device Certificate from the supplied |client_id|.
static Status Create(const DrmRootCertificate* root_certificate,
const widevine::ClientIdentification& client_id,
std::unique_ptr<ClientCert>* client_cert);
// Creates a Device Certificate based ClientCert.
static Status CreateWithDrmCertificate(
@@ -42,6 +38,21 @@ class ClientCert {
const std::string& drm_certificate,
std::unique_ptr<ClientCert>* client_cert);
// Creates a Device Certificate using the supplied certificates.
// The|signing_drm_certificate| will be used to verify an incoming request.
// The |encryption_drm_certificate| will be used to define the session key
// used to protect a response message.
static Status CreateWithDualDrmCertificates(
const DrmRootCertificate* root_certificate,
const std::string& signing_drm_certificate,
const std::string& encryption_drm_certificate,
std::unique_ptr<ClientCert>* client_cert);
// Creates a Keybox based ClientCert. The |client_cert| is a caller supplied
// unique_ptr to receive the new ClientCert.
static Status CreateWithKeybox(const std::string& keybox_token,
std::unique_ptr<ClientCert>* client_cert);
virtual ~ClientCert() = default;
ClientCert(const ClientCert&) = delete;
ClientCert& operator=(const ClientCert&) = delete;
@@ -50,6 +61,7 @@ class ClientCert {
// classes information and the passed in message. Returns OK if signature
// is valid.
virtual Status VerifySignature(const std::string& message,
HashAlgorithm hash_algorithm,
const std::string& signature,
ProtocolVersion protocol_version) const = 0;
@@ -61,6 +73,7 @@ class ClientCert {
virtual const std::string& encrypted_key() const = 0;
virtual const std::string& key() const = 0;
virtual SignedMessage::SessionKeyType key_type() const = 0;
virtual bool using_dual_certificate() const = 0;
virtual const std::string& serial_number() const = 0;
virtual const std::string& service_id() const = 0;
virtual const std::string& signing_key() const = 0;
@@ -71,6 +84,14 @@ class ClientCert {
virtual widevine::ClientIdentification::TokenType type() const = 0;
virtual const std::string& encrypted_unique_id() const = 0;
virtual const std::string& unique_id_hash() const = 0;
virtual Status SystemIdUnknownError() const {
return Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN,
"device-certificate-status-unknown");
}
virtual Status SystemIdRevokedError() const {
return Status(error_space, DRM_DEVICE_CERTIFICATE_REVOKED,
"device-certificate-revoked");
}
};
} // namespace widevine

View File

@@ -9,12 +9,16 @@
#include "common/client_cert.h"
#include <memory>
#include <tuple>
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "absl/strings/escaping.h"
#include "common/ec_key.h"
#include "common/ec_test_keys.h"
#include "common/error_space.h"
#include "common/hash_algorithm.h"
#include "common/hash_algorithm_util.h"
#include "common/keybox_client_cert.h"
#include "common/rsa_key.h"
#include "common/rsa_test_keys.h"
@@ -35,13 +39,16 @@ const DrmCertificate::Type kNoSigner = DrmCertificate::ROOT;
const DrmCertificate::Type kDeviceModelSigner = DrmCertificate::DEVICE_MODEL;
const DrmCertificate::Type kProvisionerSigner = DrmCertificate::PROVISIONER;
const HashAlgorithm kSha256 = HashAlgorithm::kSha256;
// TODO(user): Change these tests to use on-the-fly generated intermediate
// and device certificates based on RsaTestKeys.
// TODO(user): Add testcase(s) CreateSignature,
// and GenerateSigningKey.
class ClientCertTest
: public ::testing::TestWithParam<DrmCertificate::Algorithm> {
: public ::testing::TestWithParam<
std::tuple<DrmCertificate::Algorithm, DrmCertificate::Algorithm>> {
public:
~ClientCertTest() override = default;
void SetUp() override {
@@ -74,16 +81,30 @@ class ClientCertTest
class TestCertificateAndData {
public:
const std::string certificate_;
const std::string encryption_certificate_;
const std::string expected_serial_number_;
uint32_t expected_system_id_;
Status expected_status_;
SignedMessage::SessionKeyType expected_key_type_;
TestCertificateAndData(const std::string& certificate,
const std::string& expected_serial_number,
uint32_t expected_system_id, Status expected_status)
: certificate_(certificate),
expected_serial_number_(expected_serial_number),
expected_system_id_(expected_system_id),
expected_status_(expected_status) {}
expected_status_(expected_status),
expected_key_type_(SignedMessage::WRAPPED_AES_KEY) {}
TestCertificateAndData(const std::string& certificate,
const std::string& encryption_certificate,
const std::string& expected_serial_number,
uint32_t expected_system_id, Status expected_status,
SignedMessage::SessionKeyType expected_key_type)
: certificate_(certificate),
encryption_certificate_(encryption_certificate),
expected_serial_number_(expected_serial_number),
expected_system_id_(expected_system_id),
expected_status_(expected_status),
expected_key_type_(expected_key_type) {}
};
void TestBasicValidation(const TestTokenAndKeys& expectation,
@@ -94,31 +115,32 @@ class ClientCertTest
void GenerateSignature(const std::string& message,
const std::string& private_key,
std::string* signature);
SignedDrmCertificate* SignCertificate(const DrmCertificate& certificate,
SignedDrmCertificate* signer,
const std::string& private_key);
DrmCertificate* GenerateProvisionerCertificate(
HashAlgorithm hash_algorithm, std::string* signature);
std::unique_ptr<SignedDrmCertificate> SignCertificate(
const DrmCertificate& certificate, const SignedDrmCertificate* signer,
const std::string& private_key);
std::unique_ptr<DrmCertificate> GenerateProvisionerCertificate(
uint32_t system_id, const std::string& serial_number,
const std::string& provider_id);
SignedDrmCertificate* GenerateSignedProvisionerCertificate(
std::unique_ptr<SignedDrmCertificate> GenerateSignedProvisionerCertificate(
uint32_t system_id, const std::string& serial_number,
const std::string& service_id);
DrmCertificate* GenerateIntermediateCertificate(
std::unique_ptr<DrmCertificate> GenerateIntermediateCertificate(
uint32_t system_id, const std::string& serial_number);
SignedDrmCertificate* GenerateSignedIntermediateCertificate(
std::unique_ptr<SignedDrmCertificate> GenerateSignedIntermediateCertificate(
SignedDrmCertificate* signer, uint32_t system_id,
const std::string& serial_number, DrmCertificate::Type signer_cert_type);
DrmCertificate* GenerateDrmCertificate(
std::unique_ptr<DrmCertificate> GenerateDrmCertificate(
uint32_t system_id, const std::string& serial_number,
DrmCertificate::Algorithm = DrmCertificate::RSA);
SignedDrmCertificate* GenerateSignedDrmCertificate(
std::unique_ptr<SignedDrmCertificate> GenerateSignedDrmCertificate(
SignedDrmCertificate* signer, uint32_t system_id,
const std::string& serial_number,
DrmCertificate::Algorithm = DrmCertificate::RSA);
std::string GetPublicKeyByCertType(DrmCertificate::Type cert_type);
std::string GetPrivateKeyByCertType(DrmCertificate::Type cert_type);
std::string GetECCPrivateKey(DrmCertificate::Algorithm algorithm);
std::string GetECCPublicKey(DrmCertificate::Algorithm algorithm);
RsaTestKeys test_rsa_keys_;
@@ -136,8 +158,11 @@ void ClientCertTest::TestBasicValidation(const TestTokenAndKeys& expectation,
Status status;
std::unique_ptr<ClientCert> keybox_cert;
status = ClientCert::Create(root_cert_.get(), ClientIdentification::KEYBOX,
expectation.token_, &keybox_cert);
ClientIdentification client_id;
client_id.set_type(ClientIdentification::KEYBOX);
client_id.set_token(expectation.token_);
status = ClientCert::Create(root_cert_.get(), client_id, &keybox_cert);
if (expect_success) {
ASSERT_EQ(OkStatus(), status);
ASSERT_TRUE(keybox_cert.get());
@@ -163,12 +188,25 @@ void ClientCertTest::TestBasicValidationDrmCertificate(
// Test validation of a valid request.
Status status;
std::unique_ptr<ClientCert> drm_certificate_cert;
status = ClientCert::Create(root_cert_.get(),
ClientIdentification::DRM_DEVICE_CERTIFICATE,
expectation.certificate_, &drm_certificate_cert);
ClientIdentification client_id;
client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE);
client_id.set_token(expectation.certificate_);
if (!expectation.encryption_certificate_.empty()) {
client_id.mutable_device_credentials()->set_token(
expectation.encryption_certificate_);
client_id.mutable_device_credentials()->set_type(
ClientIdentification::DRM_DEVICE_CERTIFICATE);
}
status =
ClientCert::Create(root_cert_.get(), client_id, &drm_certificate_cert);
ASSERT_EQ(expectation.expected_status_, status);
if (expectation.expected_status_.ok()) {
ASSERT_TRUE(drm_certificate_cert.get());
if (!expectation.encryption_certificate_.empty()) {
ASSERT_TRUE(drm_certificate_cert->using_dual_certificate());
}
ASSERT_EQ(expectation.expected_key_type_, drm_certificate_cert->key_type());
if (compare_data) {
ASSERT_EQ(expectation.expected_serial_number_,
drm_certificate_cert->signer_serial_number());
@@ -182,26 +220,29 @@ void ClientCertTest::TestBasicValidationDrmCertificate(
void ClientCertTest::GenerateSignature(const std::string& message,
const std::string& private_key,
HashAlgorithm hash_algorithm,
std::string* signature) {
std::unique_ptr<RsaPrivateKey> rsa_private_key(
RsaPrivateKey::Create(private_key));
ASSERT_TRUE(rsa_private_key != nullptr);
rsa_private_key->GenerateSignature(message, signature);
rsa_private_key->GenerateSignature(message, hash_algorithm, signature);
}
// The caller relinquishes ownership of |signer|, which may also be nullptr.
SignedDrmCertificate* ClientCertTest::SignCertificate(
const DrmCertificate& certificate, SignedDrmCertificate* signer,
// The caller retains ownership of |signer|, which may also be nullptr.
std::unique_ptr<SignedDrmCertificate> ClientCertTest::SignCertificate(
const DrmCertificate& certificate, const SignedDrmCertificate* signer,
const std::string& private_key) {
std::unique_ptr<SignedDrmCertificate> signed_certificate(
new SignedDrmCertificate);
signed_certificate->set_drm_certificate(certificate.SerializeAsString());
GenerateSignature(signed_certificate->drm_certificate(), private_key,
signed_certificate->mutable_signature());
GenerateSignature(
signed_certificate->drm_certificate(), private_key,
HashAlgorithmProtoToEnum(signed_certificate->hash_algorithm()),
signed_certificate->mutable_signature());
if (signer != nullptr) {
signed_certificate->set_allocated_signer(signer);
*(signed_certificate->mutable_signer()) = *signer;
}
return signed_certificate.release();
return signed_certificate;
}
std::string ClientCertTest::GetPublicKeyByCertType(
@@ -224,6 +265,21 @@ std::string ClientCertTest::GetPrivateKeyByCertType(
return test_rsa_keys_.private_test_key_1_3072_bits();
}
std::string ClientCertTest::GetECCPrivateKey(
DrmCertificate::Algorithm algorithm) {
ECTestKeys keys;
switch (algorithm) {
case DrmCertificate::ECC_SECP256R1:
return keys.private_test_key_1_secp256r1();
case DrmCertificate::ECC_SECP384R1:
return keys.private_test_key_1_secp384r1();
case DrmCertificate::ECC_SECP521R1:
return keys.private_test_key_1_secp521r1();
default:
return "";
}
}
std::string ClientCertTest::GetECCPublicKey(
DrmCertificate::Algorithm algorithm) {
ECTestKeys keys;
@@ -239,7 +295,7 @@ std::string ClientCertTest::GetECCPublicKey(
}
}
DrmCertificate* ClientCertTest::GenerateIntermediateCertificate(
std::unique_ptr<DrmCertificate> ClientCertTest::GenerateIntermediateCertificate(
uint32_t system_id, const std::string& serial_number) {
std::unique_ptr<DrmCertificate> intermediate_certificate(new DrmCertificate);
intermediate_certificate->set_type(DrmCertificate::DEVICE_MODEL);
@@ -248,10 +304,11 @@ DrmCertificate* ClientCertTest::GenerateIntermediateCertificate(
GetPublicKeyByCertType(DrmCertificate::DEVICE_MODEL));
intermediate_certificate->set_system_id(system_id);
intermediate_certificate->set_creation_time_seconds(1234);
return intermediate_certificate.release();
return intermediate_certificate;
}
SignedDrmCertificate* ClientCertTest::GenerateSignedIntermediateCertificate(
std::unique_ptr<SignedDrmCertificate>
ClientCertTest::GenerateSignedIntermediateCertificate(
SignedDrmCertificate* signer, uint32_t system_id,
const std::string& serial_number, DrmCertificate::Type signer_cert_type) {
std::unique_ptr<DrmCertificate> intermediate_certificate(
@@ -261,7 +318,7 @@ SignedDrmCertificate* ClientCertTest::GenerateSignedIntermediateCertificate(
GetPrivateKeyByCertType(signer_cert_type));
}
DrmCertificate* ClientCertTest::GenerateDrmCertificate(
std::unique_ptr<DrmCertificate> ClientCertTest::GenerateDrmCertificate(
uint32_t system_id, const std::string& serial_number,
DrmCertificate::Algorithm algorithm) {
std::unique_ptr<DrmCertificate> drm_certificate(new DrmCertificate);
@@ -274,10 +331,11 @@ DrmCertificate* ClientCertTest::GenerateDrmCertificate(
: GetECCPublicKey(algorithm));
drm_certificate->set_creation_time_seconds(4321);
drm_certificate->set_algorithm(algorithm);
return drm_certificate.release();
return drm_certificate;
}
SignedDrmCertificate* ClientCertTest::GenerateSignedDrmCertificate(
std::unique_ptr<SignedDrmCertificate>
ClientCertTest::GenerateSignedDrmCertificate(
SignedDrmCertificate* signer, uint32_t system_id,
const std::string& serial_number, DrmCertificate::Algorithm algorithm) {
std::unique_ptr<DrmCertificate> drm_certificate(
@@ -285,10 +343,10 @@ SignedDrmCertificate* ClientCertTest::GenerateSignedDrmCertificate(
std::unique_ptr<SignedDrmCertificate> signed_drm_certificate(
SignCertificate(*drm_certificate, signer,
GetPrivateKeyByCertType(DrmCertificate::DEVICE_MODEL)));
return signed_drm_certificate.release();
return signed_drm_certificate;
}
DrmCertificate* ClientCertTest::GenerateProvisionerCertificate(
std::unique_ptr<DrmCertificate> ClientCertTest::GenerateProvisionerCertificate(
uint32_t system_id, const std::string& serial_number,
const std::string& provider_id) {
std::unique_ptr<DrmCertificate> provisioner_certificate(new DrmCertificate);
@@ -299,10 +357,11 @@ DrmCertificate* ClientCertTest::GenerateProvisionerCertificate(
provisioner_certificate->set_system_id(system_id);
provisioner_certificate->set_provider_id(provider_id);
provisioner_certificate->set_creation_time_seconds(1234);
return provisioner_certificate.release();
return provisioner_certificate;
}
SignedDrmCertificate* ClientCertTest::GenerateSignedProvisionerCertificate(
std::unique_ptr<SignedDrmCertificate>
ClientCertTest::GenerateSignedProvisionerCertificate(
uint32_t system_id, const std::string& serial_number,
const std::string& service_id) {
std::unique_ptr<DrmCertificate> provisioner_certificate(
@@ -341,22 +400,48 @@ TEST_F(ClientCertTest, BasicValidation) {
TEST_P(ClientCertTest, BasicCertValidation) {
const uint32_t system_id = 1234;
const std::string serial_number("serial_number");
std::unique_ptr<SignedDrmCertificate> signed_cert(
GenerateSignedDrmCertificate(
GenerateSignedIntermediateCertificate(nullptr, system_id,
serial_number, kNoSigner),
system_id, serial_number + "-device", GetParam()));
std::unique_ptr<SignedDrmCertificate> intermediate_certificate =
GenerateSignedIntermediateCertificate(nullptr, system_id, serial_number,
kNoSigner);
std::unique_ptr<SignedDrmCertificate> signed_cert =
GenerateSignedDrmCertificate(intermediate_certificate.get(), system_id,
serial_number + "-device1",
std::get<0>(GetParam()));
SignedMessage::SessionKeyType expected_key_type =
std::get<0>(GetParam()) != DrmCertificate::RSA
? SignedMessage::EPHEMERAL_ECC_PUBLIC_KEY
: SignedMessage::WRAPPED_AES_KEY;
std::unique_ptr<SignedDrmCertificate> encryption_certificate;
if (std::get<1>(GetParam()) != DrmCertificate::UNKNOWN_ALGORITHM) {
encryption_certificate = GenerateSignedDrmCertificate(
intermediate_certificate.get(), system_id, serial_number + "-device2",
std::get<1>(GetParam()));
expected_key_type = std::get<1>(GetParam()) != DrmCertificate::RSA
? SignedMessage::EPHEMERAL_ECC_PUBLIC_KEY
: SignedMessage::WRAPPED_AES_KEY;
}
const TestCertificateAndData kValidCertificateAndExpectedData(
signed_cert->SerializeAsString(), serial_number, system_id, OkStatus());
signed_cert->SerializeAsString(),
encryption_certificate == nullptr
? std::string()
: encryption_certificate->SerializeAsString(),
serial_number, system_id, OkStatus(), expected_key_type);
const bool compare_data = true;
TestBasicValidationDrmCertificate(kValidCertificateAndExpectedData,
compare_data);
}
INSTANTIATE_TEST_SUITE_P(BasicCertValidation, ClientCertTest,
testing::Values(DrmCertificate::RSA,
DrmCertificate::ECC_SECP256R1,
DrmCertificate::ECC_SECP384R1,
DrmCertificate::ECC_SECP521R1));
INSTANTIATE_TEST_SUITE_P(
BasicCertValidation, ClientCertTest,
testing::Combine(testing::Values(DrmCertificate::RSA,
DrmCertificate::ECC_SECP256R1,
DrmCertificate::ECC_SECP384R1,
DrmCertificate::ECC_SECP521R1),
testing::Values(DrmCertificate::UNKNOWN_ALGORITHM,
DrmCertificate::RSA,
DrmCertificate::ECC_SECP256R1,
DrmCertificate::ECC_SECP384R1,
DrmCertificate::ECC_SECP521R1)));
TEST_F(ClientCertTest, InvalidKeybox) {
const TestTokenAndKeys kInvalidTokenAndExpectedKeys[] = {
@@ -395,71 +480,80 @@ TEST_F(ClientCertTest, InvalidCertificate) {
std::unique_ptr<SignedDrmCertificate> invalid_drm_cert(
new SignedDrmCertificate);
invalid_drm_cert->set_drm_certificate("bad-serialized-cert");
GenerateSignature(invalid_drm_cert->drm_certificate(),
test_rsa_keys_.private_test_key_2_2048_bits(),
invalid_drm_cert->mutable_signature());
invalid_drm_cert->set_allocated_signer(GenerateSignedIntermediateCertificate(
nullptr, system_id, signer_sn, kNoSigner));
GenerateSignature(
invalid_drm_cert->drm_certificate(),
test_rsa_keys_.private_test_key_2_2048_bits(),
HashAlgorithmProtoToEnum(invalid_drm_cert->hash_algorithm()),
invalid_drm_cert->mutable_signature());
invalid_drm_cert->set_allocated_signer(
GenerateSignedIntermediateCertificate(nullptr, system_id, signer_sn,
kNoSigner)
.release());
// Invalid device public key.
dev_cert.reset(GenerateDrmCertificate(system_id, device_sn));
dev_cert = GenerateDrmCertificate(system_id, device_sn);
dev_cert->set_public_key("bad-device-public-key");
std::unique_ptr<SignedDrmCertificate> bad_device_public_key(
std::unique_ptr<SignedDrmCertificate> bad_device_public_key =
SignCertificate(*dev_cert,
GenerateSignedIntermediateCertificate(
nullptr, system_id, signer_sn, kNoSigner),
test_rsa_keys_.private_test_key_2_2048_bits()));
nullptr, system_id, signer_sn, kNoSigner)
.get(),
test_rsa_keys_.private_test_key_2_2048_bits());
// Invalid serialized intermediate certificate.
signed_signer.reset(GenerateSignedIntermediateCertificate(
nullptr, system_id, signer_sn, kNoSigner));
signed_signer = GenerateSignedIntermediateCertificate(nullptr, system_id,
signer_sn, kNoSigner);
signed_signer->set_drm_certificate("bad-serialized-cert");
GenerateSignature(signed_signer->drm_certificate(),
test_rsa_keys_.private_test_key_1_3072_bits(),
HashAlgorithmProtoToEnum(signed_signer->hash_algorithm()),
signed_signer->mutable_signature());
dev_cert.reset(GenerateDrmCertificate(system_id, device_sn));
dev_cert = GenerateDrmCertificate(system_id, device_sn);
std::unique_ptr<SignedDrmCertificate> invalid_signer(
SignCertificate(*dev_cert, signed_signer.release(),
SignCertificate(*dev_cert, signed_signer.get(),
test_rsa_keys_.private_test_key_2_2048_bits()));
// Invalid signer public key.
dev_cert.reset(GenerateDrmCertificate(system_id, device_sn));
signer_cert.reset(GenerateIntermediateCertificate(system_id, signer_sn));
dev_cert = GenerateDrmCertificate(system_id, device_sn);
signer_cert = GenerateIntermediateCertificate(system_id, signer_sn);
signer_cert->set_public_key("bad-signer-public-key");
std::unique_ptr<SignedDrmCertificate> bad_signer_public_key(SignCertificate(
*dev_cert,
SignCertificate(*signer_cert, nullptr,
test_rsa_keys_.private_test_key_1_3072_bits()),
test_rsa_keys_.private_test_key_1_3072_bits())
.get(),
test_rsa_keys_.private_test_key_2_2048_bits()));
// Invalid device certificate signature.
std::unique_ptr<SignedDrmCertificate> bad_device_signature(
GenerateSignedDrmCertificate(
GenerateSignedIntermediateCertificate(nullptr, system_id, signer_sn,
kNoSigner),
system_id, device_sn));
GenerateSignedDrmCertificate(GenerateSignedIntermediateCertificate(
nullptr, system_id, signer_sn, kNoSigner)
.get(),
system_id, device_sn));
bad_device_signature->set_signature("bad-signature");
// Missing model system ID.
dev_cert.reset(GenerateDrmCertificate(system_id, device_sn));
signer_cert.reset(GenerateIntermediateCertificate(system_id, signer_sn));
dev_cert = GenerateDrmCertificate(system_id, device_sn);
signer_cert = GenerateIntermediateCertificate(system_id, signer_sn);
signer_cert->clear_system_id();
std::unique_ptr<SignedDrmCertificate> missing_model_sn(SignCertificate(
*dev_cert,
SignCertificate(*signer_cert, nullptr,
test_rsa_keys_.private_test_key_1_3072_bits()),
test_rsa_keys_.private_test_key_1_3072_bits())
.get(),
test_rsa_keys_.private_test_key_2_2048_bits()));
// Missing signer serial number.
dev_cert.reset(GenerateDrmCertificate(system_id, device_sn));
signer_cert.reset(GenerateIntermediateCertificate(system_id, signer_sn));
dev_cert = GenerateDrmCertificate(system_id, device_sn);
signer_cert = GenerateIntermediateCertificate(system_id, signer_sn);
signer_cert->clear_serial_number();
std::unique_ptr<SignedDrmCertificate> missing_signer_sn(SignCertificate(
*dev_cert,
SignCertificate(*signer_cert, nullptr,
test_rsa_keys_.private_test_key_1_3072_bits()),
test_rsa_keys_.private_test_key_1_3072_bits())
.get(),
test_rsa_keys_.private_test_key_2_2048_bits()));
// Invalid serialized intermediate certificate.
dev_cert.reset(GenerateDrmCertificate(system_id, device_sn));
signed_signer.reset(GenerateSignedIntermediateCertificate(
nullptr, system_id, signer_sn, kNoSigner));
dev_cert = GenerateDrmCertificate(system_id, device_sn);
signed_signer = GenerateSignedIntermediateCertificate(nullptr, system_id,
signer_sn, kNoSigner);
signed_signer->set_signature("bad-signature");
std::unique_ptr<SignedDrmCertificate> bad_signer_signature(
SignCertificate(*dev_cert, signed_signer.release(),
SignCertificate(*dev_cert, signed_signer.get(),
test_rsa_keys_.private_test_key_2_2048_bits()));
const TestCertificateAndData kInvalidCertificate[] = {
@@ -504,8 +598,11 @@ TEST_F(ClientCertTest, MissingPreProvKey) {
"beaa24924907e128f9ff49b54a165cd9c33e6547537eb4d29fb7e8df3c2c1cd9"
"2517a12f4922953e"));
std::unique_ptr<ClientCert> client_cert_ptr;
Status status = ClientCert::Create(
root_cert_.get(), ClientIdentification::KEYBOX, token, &client_cert_ptr);
ClientIdentification client_id;
client_id.set_type(ClientIdentification::KEYBOX);
client_id.set_token(token);
Status status =
ClientCert::Create(root_cert_.get(), client_id, &client_cert_ptr);
ASSERT_EQ(MISSING_PRE_PROV_KEY, status.error_code());
}
@@ -516,26 +613,27 @@ TEST_F(ClientCertTest, ValidProvisionerDeviceCert) {
const std::string intermediate_serial_number("intermediate-serial-number");
const std::string provisioner_serial_number("provisioner-serial-number");
std::unique_ptr<SignedDrmCertificate> signed_provisioner_cert(
std::unique_ptr<SignedDrmCertificate> signed_provisioner_cert =
GenerateSignedProvisionerCertificate(system_id, provisioner_serial_number,
service_id));
service_id);
std::unique_ptr<SignedDrmCertificate> signed_intermediate_cert(
std::unique_ptr<SignedDrmCertificate> signed_intermediate_cert =
GenerateSignedIntermediateCertificate(
signed_provisioner_cert.release(), system_id,
intermediate_serial_number, kProvisionerSigner));
signed_provisioner_cert.get(), system_id, intermediate_serial_number,
kProvisionerSigner);
std::unique_ptr<SignedDrmCertificate> signed_device_cert(
GenerateSignedDrmCertificate(signed_intermediate_cert.release(),
system_id, device_serial_number));
std::unique_ptr<SignedDrmCertificate> signed_device_cert =
GenerateSignedDrmCertificate(signed_intermediate_cert.get(), system_id,
device_serial_number);
std::string serialized_cert;
signed_device_cert->SerializeToString(&serialized_cert);
std::unique_ptr<ClientCert> drm_cert;
ClientIdentification client_id;
client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE);
client_id.set_token(serialized_cert);
EXPECT_OK(ClientCert::Create(root_cert_.get(),
ClientIdentification::DRM_DEVICE_CERTIFICATE,
serialized_cert, &drm_cert));
EXPECT_OK(ClientCert::Create(root_cert_.get(), client_id, &drm_cert));
ASSERT_TRUE(drm_cert);
EXPECT_EQ(service_id, drm_cert->service_id());
@@ -551,27 +649,28 @@ TEST_F(ClientCertTest, InvalidProvisionerDeviceCertEmptyServiceId) {
const std::string intermediate_serial_number("intermediate-serial-number");
const std::string provisioner_serial_number("provisioner-serial-number");
std::unique_ptr<SignedDrmCertificate> signed_provisioner_cert(
std::unique_ptr<SignedDrmCertificate> signed_provisioner_cert =
GenerateSignedProvisionerCertificate(system_id, provisioner_serial_number,
service_id));
service_id);
std::unique_ptr<SignedDrmCertificate> signed_intermediate_cert(
GenerateSignedIntermediateCertificate(
signed_provisioner_cert.release(), system_id,
intermediate_serial_number, kProvisionerSigner));
signed_provisioner_cert.get(), system_id, intermediate_serial_number,
kProvisionerSigner));
std::unique_ptr<SignedDrmCertificate> signed_device_cert(
GenerateSignedDrmCertificate(signed_intermediate_cert.release(),
system_id, device_serial_number));
std::unique_ptr<SignedDrmCertificate> signed_device_cert =
GenerateSignedDrmCertificate(signed_intermediate_cert.get(), system_id,
device_serial_number);
std::string serialized_cert;
signed_device_cert->SerializeToString(&serialized_cert);
std::unique_ptr<ClientCert> client_cert_ptr;
ClientIdentification client_id;
client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE);
client_id.set_token(serialized_cert);
EXPECT_EQ("missing-provisioning-service-id",
ClientCert::Create(root_cert_.get(),
ClientIdentification::DRM_DEVICE_CERTIFICATE,
serialized_cert, &client_cert_ptr)
ClientCert::Create(root_cert_.get(), client_id, &client_cert_ptr)
.error_message());
EXPECT_FALSE(client_cert_ptr);
}
@@ -584,29 +683,30 @@ TEST_F(ClientCertTest, InvalidProvisionerDeviceCertChain) {
const std::string intermediate_serial_number("intermediate-serial-number");
const std::string intermediate_serial_number2("intermediate-serial-number-2");
std::unique_ptr<SignedDrmCertificate> signed_intermediate_cert2(
std::unique_ptr<SignedDrmCertificate> signed_intermediate_cert2 =
GenerateSignedIntermediateCertificate(
nullptr, system_id2, intermediate_serial_number2, kNoSigner));
nullptr, system_id2, intermediate_serial_number2, kNoSigner);
// Instead of using a provisioner certificate to sign this intermediate
// certificate, use another intermediate certificate. This is an invalid
// chain and should generate an error when trying to create a client
// certificate.
std::unique_ptr<SignedDrmCertificate> signed_intermediate_cert(
std::unique_ptr<SignedDrmCertificate> signed_intermediate_cert =
GenerateSignedIntermediateCertificate(
signed_intermediate_cert2.release(), system_id,
intermediate_serial_number, kDeviceModelSigner));
std::unique_ptr<SignedDrmCertificate> signed_device_cert(
GenerateSignedDrmCertificate(signed_intermediate_cert.release(),
system_id, device_serial_number));
signed_intermediate_cert2.get(), system_id,
intermediate_serial_number, kDeviceModelSigner);
std::unique_ptr<SignedDrmCertificate> signed_device_cert =
GenerateSignedDrmCertificate(signed_intermediate_cert.get(), system_id,
device_serial_number);
std::string serialized_cert;
signed_device_cert->SerializeToString(&serialized_cert);
std::unique_ptr<ClientCert> client_cert_ptr;
ClientIdentification client_id;
client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE);
client_id.set_token(serialized_cert);
ASSERT_EQ("expected-provisioning-provider-certificate-type",
ClientCert::Create(root_cert_.get(),
ClientIdentification::DRM_DEVICE_CERTIFICATE,
serialized_cert, &client_cert_ptr)
ClientCert::Create(root_cert_.get(), client_id, &client_cert_ptr)
.error_message());
EXPECT_FALSE(client_cert_ptr);
}
@@ -619,32 +719,33 @@ TEST_F(ClientCertTest, InvalidDeviceCertChainSize_TooLong) {
const std::string intermediate_serial_number2("intermediate-serial-number-2");
const std::string provisioner_serial_number("provisioner-serial-number");
std::unique_ptr<SignedDrmCertificate> signed_provisioner_cert(
std::unique_ptr<SignedDrmCertificate> signed_provisioner_cert =
GenerateSignedProvisionerCertificate(system_id, provisioner_serial_number,
service_id));
service_id);
std::unique_ptr<SignedDrmCertificate> signed_intermediate_cert1(
std::unique_ptr<SignedDrmCertificate> signed_intermediate_cert1 =
GenerateSignedIntermediateCertificate(
signed_provisioner_cert.release(), system_id,
intermediate_serial_number1, kProvisionerSigner));
signed_provisioner_cert.get(), system_id, intermediate_serial_number1,
kProvisionerSigner);
std::unique_ptr<SignedDrmCertificate> signed_intermediate_cert2(
std::unique_ptr<SignedDrmCertificate> signed_intermediate_cert2 =
GenerateSignedIntermediateCertificate(
signed_intermediate_cert1.release(), system_id,
intermediate_serial_number2, kDeviceModelSigner));
signed_intermediate_cert1.get(), system_id,
intermediate_serial_number2, kDeviceModelSigner);
std::unique_ptr<SignedDrmCertificate> signed_device_cert(
GenerateSignedDrmCertificate(signed_intermediate_cert2.release(),
system_id, device_serial_number));
std::unique_ptr<SignedDrmCertificate> signed_device_cert =
GenerateSignedDrmCertificate(signed_intermediate_cert2.get(), system_id,
device_serial_number);
std::string serialized_cert;
signed_device_cert->SerializeToString(&serialized_cert);
std::unique_ptr<ClientCert> client_cert_ptr = nullptr;
ClientIdentification client_id;
client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE);
client_id.set_token(serialized_cert);
ASSERT_EQ("certificate-chain-size-exceeded",
ClientCert::Create(root_cert_.get(),
ClientIdentification::DRM_DEVICE_CERTIFICATE,
serialized_cert, &client_cert_ptr)
ClientCert::Create(root_cert_.get(), client_id, &client_cert_ptr)
.error_message());
EXPECT_FALSE(client_cert_ptr);
}
@@ -656,26 +757,27 @@ TEST_F(ClientCertTest, DeviceCertTypeNotLeaf) {
const std::string provisioner_serial_number("provisioner-serial-number");
const std::string drm_serial_number("drm-serial-number");
std::unique_ptr<SignedDrmCertificate> signed_provisioner_cert(
std::unique_ptr<SignedDrmCertificate> signed_provisioner_cert =
GenerateSignedProvisionerCertificate(system_id, provisioner_serial_number,
service_id));
service_id);
// Use a DEVICE certificate as the intermediate certificate.
std::unique_ptr<SignedDrmCertificate> signed_intermediate_cert(
GenerateSignedDrmCertificate(signed_provisioner_cert.release(), system_id,
intermediate_serial_number));
std::unique_ptr<SignedDrmCertificate> signed_intermediate_cert =
GenerateSignedDrmCertificate(signed_provisioner_cert.get(), system_id,
intermediate_serial_number);
std::unique_ptr<SignedDrmCertificate> signed_drm_cert(
GenerateSignedDrmCertificate(signed_intermediate_cert.release(),
system_id, drm_serial_number));
std::unique_ptr<SignedDrmCertificate> signed_drm_cert =
GenerateSignedDrmCertificate(signed_intermediate_cert.get(), system_id,
drm_serial_number);
std::string serialized_cert;
signed_drm_cert->SerializeToString(&serialized_cert);
std::unique_ptr<ClientCert> client_cert_ptr;
ClientIdentification client_id;
client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE);
client_id.set_token(serialized_cert);
EXPECT_EQ("device-cert-must-be-leaf",
ClientCert::Create(root_cert_.get(),
ClientIdentification::DRM_DEVICE_CERTIFICATE,
serialized_cert, &client_cert_ptr)
ClientCert::Create(root_cert_.get(), client_id, &client_cert_ptr)
.error_message());
EXPECT_FALSE(client_cert_ptr);
}
@@ -686,21 +788,22 @@ TEST_F(ClientCertTest, InvalidLeafCertificateType) {
const std::string intermediate_serial_number("intermediate-serial-number");
const std::string provisioner_serial_number("provisioner-serial-number");
std::unique_ptr<SignedDrmCertificate> signed_provisioner_cert(
std::unique_ptr<SignedDrmCertificate> signed_provisioner_cert =
GenerateSignedProvisionerCertificate(system_id, provisioner_serial_number,
service_id));
std::unique_ptr<SignedDrmCertificate> signed_intermediate_cert(
service_id);
std::unique_ptr<SignedDrmCertificate> signed_intermediate_cert =
GenerateSignedIntermediateCertificate(
signed_provisioner_cert.release(), system_id,
intermediate_serial_number, kProvisionerSigner));
signed_provisioner_cert.get(), system_id, intermediate_serial_number,
kProvisionerSigner);
std::string serialized_cert;
signed_intermediate_cert->SerializeToString(&serialized_cert);
std::unique_ptr<ClientCert> client_cert_ptr;
ClientIdentification client_id;
client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE);
client_id.set_token(serialized_cert);
// Leaf certificate must be a device certificate.
EXPECT_EQ("expected-device-certificate-type",
ClientCert::Create(root_cert_.get(),
ClientIdentification::DRM_DEVICE_CERTIFICATE,
serialized_cert, &client_cert_ptr)
ClientCert::Create(root_cert_.get(), client_id, &client_cert_ptr)
.error_message());
EXPECT_FALSE(client_cert_ptr);
}
@@ -709,9 +812,10 @@ TEST_F(ClientCertTest, Protocol21WithDrmCert) {
const char message[] = "A weekend wasted is a weekend well spent.";
std::unique_ptr<ClientCert> client_cert;
ASSERT_OK(ClientCert::Create(
root_cert_.get(), ClientIdentification::DRM_DEVICE_CERTIFICATE,
test_drm_certs_.test_user_device_certificate(), &client_cert));
ClientIdentification client_id;
client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE);
client_id.set_token(test_drm_certs_.test_user_device_certificate());
ASSERT_OK(ClientCert::Create(root_cert_.get(), client_id, &client_cert));
std::unique_ptr<RsaPrivateKey> private_key(
RsaPrivateKey::Create(test_rsa_keys_.private_test_key_3_2048_bits()));
@@ -719,14 +823,16 @@ TEST_F(ClientCertTest, Protocol21WithDrmCert) {
// Success
std::string signature;
ASSERT_TRUE(private_key->GenerateSignature(message, &signature));
EXPECT_OK(client_cert->VerifySignature(message, signature, VERSION_2_1));
ASSERT_TRUE(private_key->GenerateSignature(message, kSha256, &signature));
EXPECT_OK(
client_cert->VerifySignature(message, kSha256, signature, VERSION_2_1));
// Failure
ASSERT_EQ(256, signature.size());
++signature[127];
EXPECT_FALSE(
client_cert->VerifySignature(message, signature, VERSION_2_1).ok());
client_cert->VerifySignature(message, kSha256, signature, VERSION_2_1)
.ok());
}
TEST_F(ClientCertTest, Protocol22WithDrmCert) {
@@ -734,9 +840,10 @@ TEST_F(ClientCertTest, Protocol22WithDrmCert) {
const std::string message_hash(Sha512_Hash(message));
std::unique_ptr<ClientCert> client_cert;
ASSERT_OK(ClientCert::Create(
root_cert_.get(), ClientIdentification::DRM_DEVICE_CERTIFICATE,
test_drm_certs_.test_user_device_certificate(), &client_cert));
ClientIdentification client_id;
client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE);
client_id.set_token(test_drm_certs_.test_user_device_certificate());
ASSERT_OK(ClientCert::Create(root_cert_.get(), client_id, &client_cert));
std::unique_ptr<RsaPrivateKey> private_key(
RsaPrivateKey::Create(test_rsa_keys_.private_test_key_3_2048_bits()));
@@ -744,14 +851,17 @@ TEST_F(ClientCertTest, Protocol22WithDrmCert) {
// Success
std::string signature;
ASSERT_TRUE(private_key->GenerateSignature(message_hash, &signature));
EXPECT_OK(client_cert->VerifySignature(message, signature, VERSION_2_2));
ASSERT_TRUE(
private_key->GenerateSignature(message_hash, kSha256, &signature));
EXPECT_OK(
client_cert->VerifySignature(message, kSha256, signature, VERSION_2_2));
// Failure
ASSERT_EQ(256, signature.size());
++signature[127];
EXPECT_FALSE(
client_cert->VerifySignature(message, signature, VERSION_2_2).ok());
client_cert->VerifySignature(message, kSha256, signature, VERSION_2_2)
.ok());
}
} // namespace widevine

View File

@@ -22,6 +22,11 @@ namespace widevine {
const char kModDrmMake[] = "company_name";
const char kModDrmModel[] = "model_name";
const char kModDrmDeviceName[] = "device_name";
const char kModDrmProductName[] = "product_name";
const char kModDrmBuildInfo[] = "build_info";
const char kModDrmOemCryptoSecurityPatchLevel[] =
"oem_crypto_security_patch_level";
void AddClientInfo(ClientIdentification* client_id, absl::string_view name,
absl::string_view value) {

View File

@@ -21,6 +21,10 @@ namespace widevine {
extern const char kModDrmMake[];
extern const char kModDrmModel[];
extern const char kModDrmDeviceName[];
extern const char kModDrmProductName[];
extern const char kModDrmBuildInfo[];
extern const char kModDrmOemCryptoSecurityPatchLevel[];
// Append the given name/value pair to client_id->client_info(). Does not
// check for duplicates.

View File

@@ -7,6 +7,7 @@
////////////////////////////////////////////////////////////////////////////////
#include "common/content_id_util.h"
#include "glog/logging.h"
#include "common/error_space.h"
#include "common/status.h"
#include "license_server_sdk/internal/parse_content_id.h"
@@ -18,33 +19,14 @@
namespace widevine {
// TODO(user): Move the util methods from
// //license_server_sdk/internal/parse_content_id.h
// into this file.
Status GetContentIdFromExternalLicenseRequest(
const ExternalLicenseRequest& external_license_request,
std::string* content_id) {
LicenseRequest::ContentIdentification content_identification =
external_license_request.content_id();
WidevinePsshData widevine_pssh_data;
if (content_identification.has_widevine_pssh_data()) {
widevine_pssh_data.ParseFromString(
content_identification.widevine_pssh_data().pssh_data(0));
} else if (content_identification.has_webm_key_id()) {
widevine_pssh_data.ParseFromString(
content_identification.webm_key_id().header());
} else if (content_identification.has_init_data()) {
ContentInfo content_info;
if (ParseContentId(content_identification, &content_info).ok()) {
widevine_pssh_data =
content_info.content_info_entry(0).pssh().widevine_data();
}
}
*content_id = widevine_pssh_data.content_id();
WidevinePsshData pssh_data;
Status status = ParsePsshData(external_license_request, &pssh_data);
*content_id = pssh_data.content_id();
return OkStatus();
}
Status GetContentIdFromSignedExternalLicenseRequest(
const SignedMessage& signed_message, std::string* content_id) {
if (signed_message.type() != SignedMessage::EXTERNAL_LICENSE_REQUEST) {
@@ -61,4 +43,41 @@ Status GetContentIdFromSignedExternalLicenseRequest(
content_id);
}
Status ParsePsshData(ExternalLicenseRequest external_license_request,
WidevinePsshData* widevine_pssh_data) {
if (!external_license_request.has_content_id()) {
std::string error = "ExternalLicenseRequest does not include ContentId";
LOG(ERROR) << error
<< ", request = " << external_license_request.ShortDebugString();
return Status(error_space, MISSING_CONTENT_ID, error);
}
ContentInfo content_info;
Status status =
ParseContentId(external_license_request.content_id(), &content_info);
if (!status.ok()) {
std::string error =
"Unable to retrieve ContentId from ExternalLicenseRequest";
LOG(ERROR) << error << ", status = " << status
<< ", request = " << external_license_request.ShortDebugString();
return Status(error_space, MISSING_CONTENT_ID, error);
}
switch (external_license_request.content_id().init_data().init_data_type()) {
case LicenseRequest::ContentIdentification::InitData::WEBM:
widevine_pssh_data->ParseFromString(
content_info.content_info_entry(0).key_ids(0));
break;
default:
*widevine_pssh_data =
content_info.content_info_entry(0).pssh().widevine_data();
break;
}
if (widevine_pssh_data->content_id().empty()) {
std::string error =
"Missing ContentId within Pssh data for ExternalLicenseRequest";
LOG(ERROR) << error
<< ", request = " << external_license_request.ShortDebugString();
return Status(error_space, MISSING_CONTENT_ID, error);
}
return OkStatus();
}
} // namespace widevine

View File

@@ -12,6 +12,7 @@
#include "common/status.h"
#include "protos/public/external_license.pb.h"
#include "protos/public/license_protocol.pb.h"
#include "protos/public/widevine_pssh.pb.h"
namespace widevine {
@@ -25,6 +26,12 @@ Status GetContentIdFromExternalLicenseRequest(
const ExternalLicenseRequest& external_license_request,
std::string* content_id);
// Returns OK if successful and |widevine_pssh_data| will be populated by
// parsing |external_license_request|. Else, error and |widevine_pssh_data|
// will not be set within this method.
Status ParsePsshData(ExternalLicenseRequest external_license_request,
WidevinePsshData* widevine_pssh_data);
} // namespace widevine
#endif // COMMON_CONTENT_ID_UTIL_H_

View File

@@ -8,6 +8,10 @@
#include "common/content_id_util.h"
#include <stddef.h>
#include <string>
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "protos/public/errors.pb.h"
@@ -23,9 +27,9 @@ const char kPlayReadyChallenge[] = "<TestPRChallenge></TestPRChallenge>";
namespace widevine {
// Builds a SignedMessage that includes an ExternalLicenseRequest.
SignedMessage BuildSignedExternalLicenseRequest(
const ExternalLicenseRequest::RequestType type, const std::string& request,
const std::string& content_id) {
SignedMessage BuildSignedExternalLicenseRequest(const ExternalLicenseType type,
const std::string& request,
const std::string& content_id) {
ExternalLicenseRequest external_license_request;
external_license_request.set_request_type(type);
external_license_request.set_request(request);
@@ -47,9 +51,8 @@ SignedMessage BuildSignedExternalLicenseRequest(
TEST(ContentIdUtil, GetContentId) {
std::string content_id;
EXPECT_OK(GetContentIdFromSignedExternalLicenseRequest(
BuildSignedExternalLicenseRequest(
ExternalLicenseRequest::PLAYREADY_LICENSE_REQUEST,
kPlayReadyChallenge, kContentId),
BuildSignedExternalLicenseRequest(PLAYREADY_LICENSE_NEW,
kPlayReadyChallenge, kContentId),
&content_id));
EXPECT_EQ(kContentId, content_id);
}
@@ -57,8 +60,7 @@ TEST(ContentIdUtil, GetContentId) {
TEST(ContentIdUtil, GetContentIdFailureWithIncorrectType) {
std::string content_id;
SignedMessage signed_message = BuildSignedExternalLicenseRequest(
ExternalLicenseRequest::PLAYREADY_LICENSE_REQUEST, kPlayReadyChallenge,
kContentId);
PLAYREADY_LICENSE_NEW, kPlayReadyChallenge, kContentId);
signed_message.set_type(SignedMessage::SERVICE_CERTIFICATE_REQUEST);
Status status =
GetContentIdFromSignedExternalLicenseRequest(signed_message, &content_id);
@@ -69,8 +71,7 @@ TEST(ContentIdUtil, GetContentIdFailureWithIncorrectType) {
TEST(ContentIdUtil, GetContentIdFailureWithInvalidExternalLicenseRequest) {
std::string content_id;
SignedMessage signed_message = BuildSignedExternalLicenseRequest(
ExternalLicenseRequest::PLAYREADY_LICENSE_REQUEST, kPlayReadyChallenge,
kContentId);
PLAYREADY_LICENSE_NEW, kPlayReadyChallenge, kContentId);
signed_message.set_msg("Invalid payload");
Status status =
GetContentIdFromSignedExternalLicenseRequest(signed_message, &content_id);

View File

@@ -42,7 +42,7 @@ bool GetCoreProvisioningResponse(
}
bool GetCoreRenewalOrReleaseLicenseResponse(
const std::string& request_core_message,
uint64_t renewal_duration_seconds, const std::string& request_core_message,
std::string* response_core_message) {
oemcrypto_core_message::ODK_RenewalRequest odk_renewal_request;
if (request_core_message.empty()) {
@@ -52,11 +52,6 @@ bool GetCoreRenewalOrReleaseLicenseResponse(
&odk_renewal_request)) {
return false;
}
// TODO(b/141762043): This function is going to need to know what the
// renewal license is, and extract the renewal duration. This should be the
// sum of renewal_delay_seconds + 2 * renewal_recovery_duration_seconds.
uint64_t renewal_duration_seconds =
3600; // PTAL when addressing b/141762043.
return CreateCoreRenewalResponse(
odk_renewal_request, renewal_duration_seconds, response_core_message);
}

View File

@@ -24,7 +24,7 @@ bool GetCoreProvisioningResponse(
// Gets the |response_core_message| by parsing |request_core_message| for
// release and renewal response. The output is held in |response_core_message|.
bool GetCoreRenewalOrReleaseLicenseResponse(
const std::string& request_core_message,
uint64_t renewal_duration_seconds, const std::string& request_core_message,
std::string* response_core_message);
// Gets the |response_core_message| by parsing |request_core_message| and

View File

@@ -11,6 +11,7 @@
#include "common/crypto_util.h"
#include "glog/logging.h"
#include "absl/strings/escaping.h"
#include "absl/strings/string_view.h"
#include "openssl/aes.h"
#include "openssl/cmac.h"
@@ -37,6 +38,8 @@ const char kGroupKeyLabel[] = "GROUP_ENCRYPTION";
// a real group master key in keystore.
// TODO(user): figure out why VerifySignatureHmacSha256 can not crypto_mcmcpy
// like VerifySignatureHmacSha1.
// TODO(user): Revert logging signature in VerifySignatureHmacSha256.
// function.
const char kPhonyGroupMasterKey[] = "fedcba9876543210";
const int kAes128KeySizeBits = 128;
const int kAes128KeySizeBytes = 16;

View File

@@ -0,0 +1,135 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 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.
////////////////////////////////////////////////////////////////////////////////
// Implementation of the DefaultDeviceSecurityProfileList class.
#include "common/default_device_security_profile_list.h"
#include <vector>
#include "glog/logging.h"
#include "google/protobuf/text_format.h"
#include "common/client_id_util.h"
#include "common/device_status_list.h"
#include "protos/public/client_identification.pb.h"
#include "protos/public/device_certificate_status.pb.h"
#include "protos/public/device_common.pb.h"
#include "protos/public/provisioned_device_info.pb.h"
#include "protos/public/security_profile.pb.h"
namespace widevine {
using ClientCapabilities = ClientIdentification::ClientCapabilities;
const char kWidevine[] = "widevine";
// Definition of Widevine default device security profiles.
// TODO(user): Add an OWNER file with per-file access to restrict changes to the
// profile definition.
const char kWidevineProfileMin[] =
(" name: \"minimum\""
" min_output_requirements {"
" hdcp_version: HDCP_NONE"
" analog_output_capabilities: ANALOG_OUTPUT_UNKNOWN"
" }"
" min_security_requirements {"
" oemcrypto_api_version: 0"
" security_level: LEVEL_3"
" resource_rating_tier: 0"
" vulnerability_level: VULNERABILITY_HIGH"
" }"
" owner: \"Widevine\"");
const char kWidevineProfileLow[] =
(" name: \"low\""
" min_output_requirements {"
" hdcp_version: HDCP_NONE"
" analog_output_capabilities: ANALOG_OUTPUT_UNKNOWN"
" }"
" min_security_requirements {"
" oemcrypto_api_version: 8"
" security_level: LEVEL_3"
" resource_rating_tier: 1"
" vulnerability_level: VULNERABILITY_MEDIUM"
" }"
" owner: \"Widevine\"");
const char kWidevineProfileMed[] =
(" name: \"medium\""
" min_output_requirements {"
" hdcp_version: HDCP_V1"
" analog_output_capabilities: ANALOG_OUTPUT_UNKNOWN"
" }"
" min_security_requirements {"
" oemcrypto_api_version: 12"
" security_level: LEVEL_3"
" resource_rating_tier: 1"
" vulnerability_level: VULNERABILITY_LOW"
" }"
" owner: \"Widevine\"");
const char kWidevineProfileHigh[] =
(" name: \"high\""
" min_output_requirements {"
" hdcp_version: HDCP_V1"
" analog_output_capabilities: ANALOG_OUTPUT_SUPPORTS_CGMS_A"
" }"
" min_security_requirements {"
" oemcrypto_api_version: 12"
" security_level: LEVEL_1"
" resource_rating_tier: 2"
" vulnerability_level: VULNERABILITY_NONE"
" }"
" owner: \"Widevine\"");
const char kWidevineProfileStrict[] =
(" name: \"strict\""
" min_output_requirements {"
" hdcp_version: HDCP_V2_2"
" analog_output_capabilities: ANALOG_OUTPUT_SUPPORTS_CGMS_A"
" }"
" min_security_requirements {"
" oemcrypto_api_version: 12"
" security_level: LEVEL_1"
" resource_rating_tier: 3"
" vulnerability_level: VULNERABILITY_NONE"
" }"
" owner: \"Widevine\"");
DefaultDeviceSecurityProfileList::DefaultDeviceSecurityProfileList()
: SecurityProfileList(kWidevine) {}
int DefaultDeviceSecurityProfileList::Init() { return AddDefaultProfiles(); }
int DefaultDeviceSecurityProfileList::AddDefaultProfiles() {
std::vector<std::string> default_profile_strings;
GetDefaultProfileStrings(&default_profile_strings);
for (auto& profile_string : default_profile_strings) {
SecurityProfile profile;
if (!google::protobuf::TextFormat::ParseFromString(profile_string, &profile)) {
LOG(ERROR) << "Unable to load default profile: " << profile.name();
ClearAllProfiles();
return 0;
}
InsertProfile(profile);
}
return NumProfiles();
}
int DefaultDeviceSecurityProfileList::GetDefaultProfileStrings(
std::vector<std::string>* default_profile_strings) const {
if (default_profile_strings == nullptr) {
return 0;
}
default_profile_strings->push_back(kWidevineProfileMin);
default_profile_strings->push_back(kWidevineProfileLow);
default_profile_strings->push_back(kWidevineProfileMed);
default_profile_strings->push_back(kWidevineProfileHigh);
default_profile_strings->push_back(kWidevineProfileStrict);
return default_profile_strings->size();
}
} // namespace widevine

View File

@@ -0,0 +1,39 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Container of Widevine default security profiless.
#ifndef COMMON_DEFAULT_DEVICE_SECURITY_PROFILE_LIST_H_
#define COMMON_DEFAULT_DEVICE_SECURITY_PROFILE_LIST_H_
#include "common/security_profile_list.h"
namespace widevine {
class DefaultDeviceSecurityProfileList : public SecurityProfileList {
public:
DefaultDeviceSecurityProfileList();
~DefaultDeviceSecurityProfileList() override {}
// Initialize the security profile list. The list is initially empty, this
// function will populate the list with default profiles. The size of the
// list is returned.
int Init() override;
private:
// Initialize the list with Widevine default profiles. The size of the
// profile list after the additions is returned.
virtual int AddDefaultProfiles();
virtual int GetDefaultProfileStrings(
std::vector<std::string>* default_profile_strings) const;
};
} // namespace widevine
#endif // COMMON_DEFAULT_DEVICE_SECURITY_PROFILE_LIST_H_

View File

@@ -0,0 +1,186 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 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/default_device_security_profile_list.h"
#include "glog/logging.h"
#include "google/protobuf/util/message_differencer.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "absl/memory/memory.h"
#include "common/client_id_util.h"
#include "protos/public/device_common.pb.h"
#include "protos/public/security_profile.pb.h"
namespace widevine {
namespace security_profile {
const uint32_t kResourceTierLow = 1;
const uint32_t kResourceTierMed = 2;
const uint32_t kResourceTierHigh = 3;
const char kMinProfileName[] = "minimum";
const char kLowProfileName[] = "low";
const char kMedProfileName[] = "medium";
const char kHighProfileName[] = "high";
const char kStrictProfileName[] = "strict";
class DefaultDeviceSecurityProfileListTest : public ::testing::Test {
public:
DefaultDeviceSecurityProfileListTest() {}
~DefaultDeviceSecurityProfileListTest() override {}
void SetUp() override {
SecurityProfile profile;
std::string profile_namespace = "widevine";
profile_list_ = absl::make_unique<DefaultDeviceSecurityProfileList>();
const int kNumWidevineProfiles = 5;
ASSERT_EQ(kNumWidevineProfiles, profile_list_->Init());
}
// Configure |client_id| and |device_info| with minimum settings.
void SetupMinDrmParams(ClientIdentification* client_id,
ProvisionedDeviceInfo* device_info) {
client_id->mutable_client_capabilities()->set_max_hdcp_version(
ClientCapabilities::HDCP_NONE);
client_id->mutable_client_capabilities()->set_analog_output_capabilities(
ClientCapabilities::ANALOG_OUTPUT_UNKNOWN);
client_id->mutable_client_capabilities()->set_oem_crypto_api_version(0);
client_id->mutable_client_capabilities()->set_resource_rating_tier(
kResourceTierLow);
device_info->set_security_level(ProvisionedDeviceInfo::LEVEL_3);
}
// Configure |client_id| and |device_info| with maximum settings.
void SetupMaxDrmParams(ClientIdentification* client_id,
ProvisionedDeviceInfo* device_info) {
client_id->mutable_client_capabilities()->set_max_hdcp_version(
ClientCapabilities::HDCP_V2_3);
client_id->mutable_client_capabilities()->set_analog_output_capabilities(
ClientCapabilities::ANALOG_OUTPUT_SUPPORTS_CGMS_A);
client_id->mutable_client_capabilities()->set_oem_crypto_api_version(16);
client_id->mutable_client_capabilities()->set_resource_rating_tier(
kResourceTierHigh);
device_info->set_security_level(ProvisionedDeviceInfo::LEVEL_1);
}
std::unique_ptr<SecurityProfileList> profile_list_;
};
TEST_F(DefaultDeviceSecurityProfileListTest, QualifiedProfiles) {
ClientIdentification client_id;
ProvisionedDeviceInfo device_info;
SetupMinDrmParams(&client_id, &device_info);
std::vector<std::string> qualified_profiles;
// Should only return the minimum profile.
ASSERT_EQ(1, profile_list_->GetQualifiedProfiles(client_id, device_info,
&qualified_profiles));
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kMinProfileName) != qualified_profiles.end());
// Increase the device capabilities to include the low profile.
client_id.mutable_client_capabilities()->set_oem_crypto_api_version(8);
ASSERT_EQ(2, profile_list_->GetQualifiedProfiles(client_id, device_info,
&qualified_profiles));
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kMinProfileName) != qualified_profiles.end());
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kLowProfileName) != qualified_profiles.end());
// Increase the device capabilities to include the med profile.
client_id.mutable_client_capabilities()->set_max_hdcp_version(
ClientCapabilities::HDCP_V1);
client_id.mutable_client_capabilities()->set_oem_crypto_api_version(12);
ASSERT_EQ(3, profile_list_->GetQualifiedProfiles(client_id, device_info,
&qualified_profiles));
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kMinProfileName) != qualified_profiles.end());
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kLowProfileName) != qualified_profiles.end());
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kMedProfileName) != qualified_profiles.end());
// Increase the device capabilities to include the high profile.
device_info.set_security_level(ProvisionedDeviceInfo::LEVEL_1);
client_id.mutable_client_capabilities()->set_analog_output_capabilities(
ClientCapabilities::ANALOG_OUTPUT_SUPPORTS_CGMS_A);
client_id.mutable_client_capabilities()->set_resource_rating_tier(
kResourceTierMed);
ASSERT_EQ(4, profile_list_->GetQualifiedProfiles(client_id, device_info,
&qualified_profiles));
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kMinProfileName) != qualified_profiles.end());
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kLowProfileName) != qualified_profiles.end());
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kMedProfileName) != qualified_profiles.end());
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kHighProfileName) != qualified_profiles.end());
// Increase the device capabilities to include the strict profile.
client_id.mutable_client_capabilities()->set_max_hdcp_version(
ClientCapabilities::HDCP_V2_2);
client_id.mutable_client_capabilities()->set_resource_rating_tier(
kResourceTierHigh);
ASSERT_EQ(5, profile_list_->GetQualifiedProfiles(client_id, device_info,
&qualified_profiles));
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kMinProfileName) != qualified_profiles.end());
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kLowProfileName) != qualified_profiles.end());
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kMedProfileName) != qualified_profiles.end());
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kHighProfileName) != qualified_profiles.end());
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kStrictProfileName) != qualified_profiles.end());
}
TEST_F(DefaultDeviceSecurityProfileListTest,
DeviceQualifiedProfilesForLowEndDevice) {
ClientIdentification client_id;
ProvisionedDeviceInfo device_info;
SetupMinDrmParams(&client_id, &device_info);
// Only 1 profile should qualify for this device.
std::vector<std::string> qualified_profiles;
ASSERT_EQ(1, profile_list_->GetQualifiedProfiles(client_id, device_info,
&qualified_profiles));
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kMinProfileName) != qualified_profiles.end());
}
TEST_F(DefaultDeviceSecurityProfileListTest,
QualifiedProfilesForHighEndDevice) {
ClientIdentification client_id;
ProvisionedDeviceInfo device_info;
SetupMaxDrmParams(&client_id, &device_info);
// All 5 default profiles should qualify for this device.
std::vector<std::string> qualified_profiles;
ASSERT_EQ(5, profile_list_->GetQualifiedProfiles(client_id, device_info,
&qualified_profiles));
}
// TODO(b/160019477): Add test once provisioned device info supports known
// vulnerability.
TEST_F(DefaultDeviceSecurityProfileListTest,
DISABLED_QualifiedProfilesByVunerabilityLevel) {
ClientIdentification client_id;
ProvisionedDeviceInfo device_info;
SetupMaxDrmParams(&client_id, &device_info);
std::vector<std::string> qualified_profiles;
ASSERT_EQ(0, profile_list_->GetQualifiedProfiles(client_id, device_info,
&qualified_profiles));
}
} // namespace security_profile
} // namespace widevine

View File

@@ -30,7 +30,7 @@ bool VerifyMakeModel(const ProvisionedDeviceInfo& device_info,
make_from_client, model_from_client)) {
return true;
}
for (DeviceModel product_info : device_info.model_info()) {
for (const DeviceModel& product_info : device_info.model_info()) {
if (IsMatchedMakeModel(product_info.manufacturer(),
product_info.model_name(), make_from_client,
model_from_client)) {

View File

@@ -7,6 +7,7 @@
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_DEVICE_INFO_UTIL_H_
#define COMMON_DEVICE_INFO_UTIL_H_
#include <string>
#include "protos/public/provisioned_device_info.pb.h"

View File

@@ -27,6 +27,7 @@
#include "common/client_cert.h"
#include "common/drm_service_certificate.h"
#include "common/error_space.h"
#include "common/hash_algorithm_util.h"
#include "common/keybox_client_cert.h"
#include "common/rsa_key.h"
#include "common/status.h"
@@ -63,7 +64,8 @@ DeviceStatusList::~DeviceStatusList() {}
Status DeviceStatusList::UpdateStatusList(
const std::string& root_certificate_public_key,
const std::string& serialized_device_certificate_status_list,
const std::string& signature, uint32_t expiration_period_seconds) {
HashAlgorithm hash_algorithm, const std::string& signature,
uint32_t expiration_period_seconds) {
if (serialized_device_certificate_status_list.empty()) {
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"missing-status-list");
@@ -79,7 +81,7 @@ Status DeviceStatusList::UpdateStatusList(
"invalid-root-public-key");
}
if (!root_key->VerifySignature(serialized_device_certificate_status_list,
signature)) {
hash_algorithm, signature)) {
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"invalid-status-list-signature");
}
@@ -117,29 +119,11 @@ Status DeviceStatusList::UpdateStatusList(
return OkStatus();
}
Status DeviceStatusList::GetCertStatus(const ClientCert& client_cert,
const std::string& device_manufacturer,
ProvisionedDeviceInfo* device_info) {
CHECK(device_info);
// Keybox checks.
if (client_cert.type() == ClientIdentification::KEYBOX) {
if (!KeyboxClientCert::IsSystemIdKnown(client_cert.system_id())) {
return Status(error_space, UNSUPPORTED_SYSTEM_ID,
"keybox-unsupported-system-id");
}
// Get device information from certificate status list if available.
if (!GetDeviceInfo(client_cert, device_info)) {
device_info->Clear();
}
return OkStatus();
}
// DRM certificate checks.
if (client_cert.type() != ClientIdentification::DRM_DEVICE_CERTIFICATE) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"device-certificate-unsupported-token-type");
}
Status DeviceStatusList::GetCertStatus(
const ClientCert& client_cert, const std::string& make,
const std::string& provider, bool allow_revoked_system_id,
DeviceCertificateStatus* device_certificate_status) {
CHECK(device_certificate_status);
absl::ReaderMutexLock lock(&status_map_lock_);
if (expiration_period_seconds_ &&
(GetCurrentTime() >
@@ -149,59 +133,67 @@ Status DeviceStatusList::GetCertStatus(const ClientCert& client_cert,
}
DeviceCertificateStatus* device_cert_status =
gtl::FindOrNull(device_status_map_, client_cert.system_id());
if (device_cert_status) {
*device_info = device_cert_status->device_info();
if (device_cert_status->status() ==
DeviceCertificateStatus::STATUS_REVOKED) {
if (IsRevokedSystemIdAllowed(client_cert.system_id())) {
LOG(WARNING) << "Allowing REVOKED device: "
<< device_info->ShortDebugString();
} else {
return Status(error_space, DRM_DEVICE_CERTIFICATE_REVOKED,
"device-certificate-revoked");
}
if (device_cert_status == nullptr) {
if (allow_unknown_devices_) {
return OkStatus();
}
if ((device_cert_status->status() ==
DeviceCertificateStatus::STATUS_TEST_ONLY) &&
!allow_test_only_devices_) {
if (IsTestOnlyDeviceAllowed(client_cert.system_id(),
device_manufacturer)) {
LOG(WARNING) << "Allowing TEST_ONLY device with systemId = "
<< client_cert.system_id()
<< "make = " << device_manufacturer
<< ", device info = " << device_info->ShortDebugString();
} else {
VLOG(2) << "Not allowing TEST ONLY device with systemId = "
<< client_cert.system_id() << "make = " << device_manufacturer
<< ", device info = " << device_info->ShortDebugString();
return Status(error_space, DEVELOPMENT_CERTIFICATE_NOT_ALLOWED,
"test-only-drm-certificate-not-allowed");
}
return client_cert.SystemIdUnknownError();
}
*device_certificate_status = *device_cert_status;
if (device_cert_status->status() == DeviceCertificateStatus::STATUS_REVOKED) {
if (IsRevokedSystemIdAllowed(client_cert.system_id()) ||
allow_revoked_system_id) {
LOG(WARNING) << "Allowing REVOKED device: "
<< device_cert_status->device_info().ShortDebugString();
} else {
return client_cert.SystemIdRevokedError();
}
if (!client_cert.signed_by_provisioner() &&
(client_cert.signer_serial_number() !=
device_cert_status->drm_serial_number())) {
// Widevine-provisioned device, and the intermediate certificate serial
// number does not match that in the status list. If the status list is
// newer than the certificate, indicate an invalid certificate, so that
// the device re-provisions. If, on the other hand, the certificate status
// list is older than the certificate, the certificate is for all purposes
// unknown.
if (client_cert.signer_creation_time_seconds() < creation_time_seconds_) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"intermediate-certificate-serial-number-mismatch");
}
return Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN,
"device-certificate-status-unknown");
}
} else {
if (!allow_unknown_devices_) {
return Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN,
"device-certificate-status-unknown");
}
device_info->Clear();
}
// The remainder of this function is for DRM certificates.
if (client_cert.type() == ClientIdentification::KEYBOX) {
return OkStatus();
}
// DRM certificate checks.
if (client_cert.type() != ClientIdentification::DRM_DEVICE_CERTIFICATE) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"device-certificate-unsupported-token-type");
}
if ((device_cert_status->status() ==
DeviceCertificateStatus::STATUS_TEST_ONLY) &&
!allow_test_only_devices_) {
if (IsTestOnlyDeviceAllowedByMake(client_cert.system_id(), make) &&
IsTestOnlyDeviceAllowedByProvider(client_cert.system_id(), provider)) {
LOG(WARNING) << "Allowing TEST_ONLY device with systemId = "
<< client_cert.system_id() << ", make = " << make
<< ", provider = " << provider << ", device info = "
<< device_cert_status->device_info().ShortDebugString();
} else {
VLOG(2) << "Not allowing TEST ONLY device with systemId = "
<< client_cert.system_id() << ", provider = " << provider
<< ", device info = "
<< device_cert_status->device_info().ShortDebugString();
return Status(error_space, DEVELOPMENT_CERTIFICATE_NOT_ALLOWED,
"test-only-drm-certificate-not-allowed");
}
}
if (!client_cert.signed_by_provisioner() &&
(client_cert.signer_serial_number() !=
device_cert_status->drm_serial_number())) {
// Widevine-provisioned device, and the intermediate certificate serial
// number does not match that in the status list. If the status list is
// newer than the certificate, indicate an invalid certificate, so that
// the device re-provisions. If, on the other hand, the certificate status
// list is older than the certificate, the certificate is for all purposes
// unknown.
if (client_cert.signer_creation_time_seconds() < creation_time_seconds_) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"intermediate-certificate-serial-number-mismatch");
}
return client_cert.SystemIdUnknownError();
}
return OkStatus();
}
@@ -268,29 +260,55 @@ void DeviceStatusList::AllowRevokedDevices(const std::string& system_id_list) {
std::sort(allowed_revoked_devices_.begin(), allowed_revoked_devices_.end());
}
void DeviceStatusList::AllowTestOnlyDevices(const std::string& device_list) {
void DeviceStatusList::AllowTestOnlyDevicesByMake(
const std::string& device_list_by_make) {
absl::WriterMutexLock lock(&allowed_test_only_devices_mutex_);
if (device_list.empty()) {
allowed_test_only_devices_.clear();
if (device_list_by_make.empty()) {
allowed_test_only_devices_by_make_.clear();
return;
}
for (absl::string_view device : absl::StrSplit(device_list, ',')) {
for (absl::string_view device : absl::StrSplit(device_list_by_make, ',')) {
const std::pair<absl::string_view, absl::string_view> device_split =
absl::StrSplit(device, ':');
if (device_split.second.empty() || device_split.second == "*") {
allowed_test_only_devices_.emplace(
allowed_test_only_devices_by_make_.emplace(
std::stoi(std::string(device_split.first)), "*");
VLOG(2) << "Whitelisting TEST_ONLY device: systemId = "
<< std::stoi(std::string(device_split.first))
<< ", manufacturer = *";
VLOG(2) << "Allowing TEST_ONLY device: systemId = "
<< std::stoi(std::string(device_split.first)) << ", make *";
} else {
allowed_test_only_devices_.emplace(
allowed_test_only_devices_by_make_.emplace(
std::stoi(std::string(device_split.first)),
absl::AsciiStrToUpper(device_split.second));
VLOG(2) << "Whitelisting TEST_ONLY device: systemId = "
VLOG(2) << "Allowing TEST_ONLY device: systemId = "
<< std::stoi(std::string(device_split.first))
<< ", manufacturer = "
<< absl::AsciiStrToUpper(device_split.second);
<< ", make = " << absl::AsciiStrToUpper(device_split.second);
}
}
}
void DeviceStatusList::AllowTestOnlyDevicesByProvider(
const std::string& device_list_by_provider) {
absl::WriterMutexLock lock(&allowed_test_only_devices_mutex_);
if (device_list_by_provider.empty()) {
allowed_test_only_devices_by_provider_.clear();
return;
}
for (absl::string_view device :
absl::StrSplit(device_list_by_provider, ',')) {
const std::pair<absl::string_view, absl::string_view> device_split =
absl::StrSplit(device, ':');
if (device_split.second.empty() || device_split.second == "*") {
allowed_test_only_devices_by_provider_.emplace(
std::stoi(std::string(device_split.first)), "*");
VLOG(2) << "Allowing TEST_ONLY device: systemId = "
<< std::stoi(std::string(device_split.first)) << ", provider *";
} else {
allowed_test_only_devices_by_provider_.emplace(
std::stoi(std::string(device_split.first)),
absl::AsciiStrToUpper(device_split.second));
VLOG(2) << "Allowing TEST_ONLY device: systemId = "
<< std::stoi(std::string(device_split.first))
<< ", provider = " << absl::AsciiStrToUpper(device_split.second);
}
}
}
@@ -301,17 +319,34 @@ bool DeviceStatusList::IsRevokedSystemIdAllowed(uint32_t system_id) {
return it;
}
bool DeviceStatusList::IsTestOnlyDeviceAllowed(uint32_t system_id,
const std::string manufacturer) {
bool DeviceStatusList::IsTestOnlyDeviceAllowedByMake(
uint32_t system_id, const std::string& manufacturer) {
absl::ReaderMutexLock lock(&allowed_test_only_devices_mutex_);
std::pair<std::multimap<uint32_t, std::string>::iterator,
std::multimap<uint32_t, std::string>::iterator>
allowed_manufacturers = allowed_test_only_devices_.equal_range(system_id);
for (auto it = allowed_manufacturers.first;
it != allowed_manufacturers.second; ++it) {
std::string allowed_manufacturer = (*it).second;
if (allowed_manufacturer == "*" ||
allowed_manufacturer == absl::AsciiStrToUpper(manufacturer)) {
allowed_makes = allowed_test_only_devices_by_make_.equal_range(system_id);
for (auto it = allowed_makes.first; it != allowed_makes.second; ++it) {
std::string allowed_makes = (*it).second;
if (allowed_makes == "*" ||
allowed_makes == absl::AsciiStrToUpper(manufacturer)) {
return true;
}
}
return false;
}
bool DeviceStatusList::IsTestOnlyDeviceAllowedByProvider(
uint32_t system_id, const std::string& provider) {
absl::ReaderMutexLock lock(&allowed_test_only_devices_mutex_);
std::pair<std::multimap<uint32_t, std::string>::iterator,
std::multimap<uint32_t, std::string>::iterator>
allowed_providers =
allowed_test_only_devices_by_provider_.equal_range(system_id);
for (auto it = allowed_providers.first; it != allowed_providers.second;
++it) {
std::string allowed_provider = (*it).second;
if (allowed_provider == "*" ||
allowed_provider == absl::AsciiStrToUpper(provider)) {
return true;
}
}
@@ -321,7 +356,8 @@ bool DeviceStatusList::IsTestOnlyDeviceAllowed(uint32_t system_id,
Status DeviceStatusList::DetermineAndDeserializeServiceResponse(
const std::string& service_response,
DeviceCertificateStatusList* certificate_status_list,
std::string* serialized_certificate_status_list, std::string* signature) {
std::string* serialized_certificate_status_list,
HashAlgorithm* hash_algorithm, std::string* signature) {
if (certificate_status_list == nullptr) {
return Status(error_space, error::INVALID_ARGUMENT,
"certificate_status_list is empty");
@@ -337,13 +373,15 @@ Status DeviceStatusList::DetermineAndDeserializeServiceResponse(
// payload. If that doesn't match, then the method will try to parse the
// serialized PublishedDeviceInfo proto.
Status status = ExtractPublishedDevicesInfo(
service_response, serialized_certificate_status_list, signature);
service_response, serialized_certificate_status_list, hash_algorithm,
signature);
// If the payload was not correctly parsed as a PublishedDevices proto.
// then attempt to parse it as a legacy payload.
if (!status.ok()) {
status = ExtractLegacyDeviceList(
service_response, serialized_certificate_status_list, signature);
status = ExtractLegacyDeviceList(service_response,
serialized_certificate_status_list,
hash_algorithm, signature);
// The payload could not be parsed in either format, return the failure
// information.
if (!status.ok()) {
@@ -361,7 +399,8 @@ Status DeviceStatusList::DetermineAndDeserializeServiceResponse(
Status DeviceStatusList::ExtractLegacyDeviceList(
const std::string& raw_certificate_provisioning_service_response,
std::string* serialized_certificate_status_list, std::string* signature) {
std::string* serialized_certificate_status_list,
HashAlgorithm* hash_algorithm, std::string* signature) {
// First, attempt to extract the legacy JSON response. Example legacy format.
// "signedList":"<b64 encoded data>"
// where the b64 encoded data is a DeviceCertificateStatusListResponse.
@@ -424,12 +463,13 @@ Status DeviceStatusList::ExtractLegacyDeviceList(
// and extract the serialized status list and signature.
return ParseLegacySignedDeviceCertificateStatusList(
serialized_signed_certificate_status_list,
serialized_certificate_status_list, signature);
serialized_certificate_status_list, hash_algorithm, signature);
}
Status DeviceStatusList::ExtractPublishedDevicesInfo(
const std::string& serialized_published_devices,
std::string* serialized_certificate_status_list, std::string* signature) {
std::string* serialized_certificate_status_list,
HashAlgorithm* hash_algorithm, std::string* signature) {
// TODO(b/139067045): Change from using the SignedDeviceInfo proto
// to using the correct proto from the API. This duplicate, wire-compatible
// proto was a temporary way to workaround Proto2/Proto3 compatibility issues.
@@ -440,6 +480,7 @@ Status DeviceStatusList::ExtractPublishedDevicesInfo(
}
*serialized_certificate_status_list =
devices_info.device_certificate_status_list();
*hash_algorithm = HashAlgorithmProtoToEnum(devices_info.hash_algorithm());
*signature = devices_info.signature();
return OkStatus();
}
@@ -470,12 +511,12 @@ Status DeviceStatusList::GenerateSignedDeviceCertificateStatusListRequest(
DrmServiceCertificate::GetDefaultDrmServiceCertificate();
if (sc == nullptr) {
signed_device_certificate_status_list_request->clear();
return Status(error_space, widevine::INVALID_SERVICE_CERTIFICATE,
return Status(error_space, widevine::SERVICE_CERTIFICATE_NOT_FOUND,
"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,
return Status(error_space, widevine::INVALID_SERVICE_PRIVATE_KEY,
"Private key in the service certificate is null.");
}
std::string signature;
@@ -490,7 +531,7 @@ Status DeviceStatusList::GenerateSignedDeviceCertificateStatusListRequest(
Status DeviceStatusList::ParseLegacySignedDeviceCertificateStatusList(
const std::string& serialized_signed_device_certificate_status_list,
std::string* serialized_device_certificate_status_list,
std::string* signature) {
HashAlgorithm* hash_algorithm, std::string* signature) {
// Parse the serialized_signed_device_certificate_status_list to extract the
// serialized_device_certificate_status_list
SignedDeviceCertificateStatusList signed_device_list;
@@ -509,6 +550,8 @@ Status DeviceStatusList::ParseLegacySignedDeviceCertificateStatusList(
}
*serialized_device_certificate_status_list =
signed_device_list.certificate_status_list();
*hash_algorithm =
HashAlgorithmProtoToEnum(signed_device_list.hash_algorithm());
*signature = signed_device_list.signature();
return OkStatus();
}
@@ -532,4 +575,24 @@ bool DeviceStatusList::IsDrmCertificateRevoked(
return false;
}
Status DeviceStatusList::GetDeviceCertificateStatusBySystemId(
uint32_t system_id, DeviceCertificateStatus* device_certificate_status) {
absl::ReaderMutexLock lock(&status_map_lock_);
if (expiration_period_seconds_ &&
(GetCurrentTime() >
(creation_time_seconds_ + expiration_period_seconds_))) {
return Status(error_space, EXPIRED_CERTIFICATE_STATUS_LIST,
"certificate-status-list-expired");
}
DeviceCertificateStatus* device_cert_status =
gtl::FindOrNull(device_status_map_, system_id);
if (device_cert_status == nullptr) {
return Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN,
"device-certificate-status-unknown");
} else {
*device_certificate_status = *device_cert_status;
}
return OkStatus();
}
} // namespace widevine

View File

@@ -16,6 +16,7 @@
#include <string>
#include "absl/synchronization/mutex.h"
#include "common/hash_algorithm.h"
#include "common/status.h"
#include "protos/public/device_certificate_status.pb.h"
#include "protos/public/provisioned_device_info.pb.h"
@@ -48,7 +49,8 @@ class DeviceStatusList {
Status UpdateStatusList(
const std::string& root_certificate_public_key,
const std::string& serialized_device_certificate_status_list,
const std::string& signature, uint32_t expiration_period_seconds);
HashAlgorithm hash_algorithm, const std::string& signature,
uint32_t expiration_period_seconds);
void set_allow_unknown_devices(bool flag) { allow_unknown_devices_ = flag; }
bool allow_unknown_devices() const { return allow_unknown_devices_; }
void set_allow_test_only_devices(bool allow) {
@@ -63,14 +65,15 @@ class DeviceStatusList {
// INVALID_DRM_CERTIFICATE
// DRM_DEVICE_CERTIFICATE_REVOKED
// DRM_DEVICE_CERTIFICATE_UNKNOWN
// If a TEST_ONLY device using "make" as identified by |device_manufacturer|,
// was not whitelisted, then will return
// DEVELOPMENT_CERTIFICATE_NOT_ALLOWED
// 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.
Status GetCertStatus(const ClientCert& client_cert,
const std::string& device_manufacturer,
widevine::ProvisionedDeviceInfo* device_info);
// |provider| is the service provider making the license request.
// If status is OK, a copy of the device certificate status is copied
// into |device_certificate_status|. Caller owns |device_certificate_status|
// and it must not be null.
Status GetCertStatus(
const ClientCert& client_cert, const std::string& make,
const std::string& provider, bool allow_revoked_system_id,
widevine::DeviceCertificateStatus* device_certificate_status);
// Returns true if the pre-provisioning key or certificate for the specified
// system ID are active (not disallowed or revoked).
bool IsSystemIdActive(uint32_t system_id);
@@ -107,8 +110,16 @@ class DeviceStatusList {
// of the format <system_id>:
// Example usage:
// const std::string device_list = "4121:LG,7912:*"
// AllowTestOnlyDevices(device_list);
virtual void AllowTestOnlyDevices(const std::string& device_list);
// AllowTestOnlyDevicesByMake(device_list_by_make);
virtual void AllowTestOnlyDevicesByMake(
const std::string& device_list_by_make);
// Same as above, except by providers instead of by manufacturers.
// Example usage:
// const std::string device_list = "4121:YouTube,4121:AndroidVideo"
// AllowTestOnlyDevicesByProvider(device_list);
virtual void AllowTestOnlyDevicesByProvider(
const std::string& device_list_by_provider);
// A comma separated list of DRM Certificate Serial Numbers that are revoked.
virtual void RevokedDrmCertificateSerialNumbers(
@@ -119,6 +130,12 @@ class DeviceStatusList {
bool IsDrmCertificateRevoked(
const std::string& device_certificate_serial_number);
// Returns OK if |system_id| was found in the device certificate status list
// and |device_certificate_status| is populated. If |system_id| is not found,
// this call returns an error.
virtual Status GetDeviceCertificateStatusBySystemId(
uint32_t system_id, DeviceCertificateStatus* device_certificate_status);
// Parses the serialized certificate status list and the signature from the
// service_response. The service_response is the JSON payload that comes
// in the response to a certificate status list request. Both the legacy
@@ -139,11 +156,13 @@ class DeviceStatusList {
// serialized proto against the |signature|.
// The |signature| is the signature of the serialized_certificate_status_list
// using RSASSA-PSS signed with the root certificate private key.
// The |hash_algorithm| is the hash algorithm used in signature.
// Returns WvPLStatus - Status::OK if success, else error.
static Status DetermineAndDeserializeServiceResponse(
const std::string& service_response,
DeviceCertificateStatusList* certificate_status_list,
std::string* serialized_certificate_status_list, std::string* signature);
std::string* serialized_certificate_status_list,
HashAlgorithm* hash_algorithm, std::string* signature);
/**
* Constructs signed device certificate status list request string.
@@ -157,6 +176,20 @@ class DeviceStatusList {
const std::string& serialized_service_certificate,
std::string* signed_device_certificate_status_list_request);
// Returns true if the system ID is allowed to be revoked.
// Caller owns |system_id|. They must not be null.
bool IsRevokedSystemIdAllowed(uint32_t system_id);
// Returns true if the device, which is identified by system_id and
// device_manufacturer, is present in |allowed_test_only_devices_by_make_|.
bool IsTestOnlyDeviceAllowedByMake(uint32_t system_id,
const std::string& device_manufacturer);
// Returns true if the device, which is identified by system_id and
// provider, is present in |allowed_test_only_devices_by_provider_|.
bool IsTestOnlyDeviceAllowedByProvider(uint32_t system_id,
const std::string& provider);
private:
friend class DeviceStatusListTest;
@@ -167,12 +200,14 @@ class DeviceStatusList {
*
* @param legacy_certificate_provisioning_service_response
* @param serialized_certificate_status_list
* @param hash_algorithm
* @param signature
* @return WvPLStatus - Status::OK if success, else error.
*/
static Status ExtractLegacyDeviceList(
const std::string& raw_certificate_provisioning_service_response,
std::string* serialized_certificate_status_list, std::string* signature);
std::string* serialized_certificate_status_list,
HashAlgorithm* hash_algorithm, std::string* signature);
/**
* Parses the serialized published devices response.
@@ -182,12 +217,14 @@ class DeviceStatusList {
* @param published_devices_response the serialized PublishedDevices proto
* containing the certificate status list.
* @param serialized_certificate_status_list
* @param hash_algorithm
* @param signature
* @return WvPLStatus - Status::OK if success, else error.
*/
static Status ExtractPublishedDevicesInfo(
const std::string& serialized_published_devices,
std::string* serialized_certificate_status_list, std::string* signature);
std::string* serialized_certificate_status_list,
HashAlgorithm* hash_algorithm, std::string* signature);
/**
* Returns a |serialized_device_certificate_status_list| in its output
@@ -196,25 +233,28 @@ class DeviceStatusList {
*
* @param serialized_signed_device_certificate_status_list
* @param serialized_device_certificate_status_list
*
* @param hash_algorithm
* @return Status - Status::OK if success, else error.
*/
static Status ParseLegacySignedDeviceCertificateStatusList(
const std::string& serialized_signed_device_certificate_status_list,
std::string* serialized_device_certificate_status_list,
std::string* signature);
HashAlgorithm* hash_algorithm, std::string* signature);
// Returns true if the system ID is allowed to be revoked.
// Caller owns |system_id|. They must not be null.
bool IsRevokedSystemIdAllowed(uint32_t system_id);
// Returns true if the device, which is identified by system_id and
// device_manufacturer, is present in |allowed_test_only_devices_|.
bool IsTestOnlyDeviceAllowed(uint32_t system_id,
const std::string device_manufacturer);
virtual size_t allowed_test_only_devices_by_make_size() {
absl::ReaderMutexLock lock(&allowed_test_only_devices_mutex_);
return allowed_test_only_devices_by_make_.size();
}
absl::Mutex status_map_lock_;
virtual size_t allowed_test_only_devices_by_provider_size() {
absl::ReaderMutexLock lock(&allowed_test_only_devices_mutex_);
return allowed_test_only_devices_by_provider_.size();
}
mutable absl::Mutex status_map_lock_;
// Key is the system id for the device.
std::map<uint32_t, widevine::DeviceCertificateStatus> device_status_map_;
std::map<uint32_t, widevine::DeviceCertificateStatus> device_status_map_
ABSL_GUARDED_BY(status_map_lock_);
uint32_t creation_time_seconds_ = 0;
uint32_t expiration_period_seconds_ = 0;
bool allow_unknown_devices_ = false;
@@ -222,10 +262,15 @@ class DeviceStatusList {
// Contains the list of system_id values that are allowed to succeed even if
// revoked.
std::vector<uint32_t> allowed_revoked_devices_;
absl::Mutex allowed_test_only_devices_mutex_;
// Contains a map of 'system_id' to 'make'. If 'make' value is "*", any
// 'make' for that 'system_id' is allowed.
std::multimap<uint32_t, std::string> allowed_test_only_devices_;
mutable absl::Mutex allowed_test_only_devices_mutex_;
// Contains a map of 'system_id' to 'manufacturer'. If manufacturer value is
// "*", any manufacturer using that system_id is allowed.
std::multimap<uint32_t, std::string> allowed_test_only_devices_by_make_
ABSL_GUARDED_BY(allowed_test_only_devices_mutex_);
// Contains a map of 'system_id' to 'provider'. If provider value is "*", any
// provider using that system_id is allowed.
std::multimap<uint32_t, std::string> allowed_test_only_devices_by_provider_
ABSL_GUARDED_BY(allowed_test_only_devices_mutex_);
// Revoked DRM certificate serial numbers.
std::set<std::string> revoked_drm_certificate_serial_numbers_;
};

View File

@@ -21,6 +21,8 @@
#include "absl/strings/escaping.h"
#include "absl/strings/str_cat.h"
#include "common/client_cert.h"
#include "common/hash_algorithm.h"
#include "common/hash_algorithm_util.h"
#include "common/keybox_client_cert.h"
#include "common/rsa_key.h"
#include "common/rsa_test_keys.h"
@@ -34,20 +36,19 @@
namespace {
const char kTestSystemId_1[] = "4121";
const char kTestManufacturer_LG[] = "LG";
const char kTestManufacturer_LGE[] = "LGE";
const char kTestSystemId_2[] = "8242";
const char kTestManufacturer_Samsung[] = "Samsung";
const char kTestSystemId_3[] = "6556";
const char kTestManufacturer[] = "TestManufacturer";
const char kTestProvider[] = "TestProvider";
const char kRevokedManufacturer[] = "RevokedManufacturer";
const widevine::HashAlgorithm kHashAlgorithm =
widevine::HashAlgorithm::kSha256;
} // namespace
namespace widevine {
using ::testing::_;
using ::testing::Return;
using ::testing::ReturnRef;
using ::testing::ReturnRefOfCopy;
const uint32_t kValidCertSystemId = 100;
const uint32_t kRevokedCertSystemId = 101;
@@ -66,32 +67,40 @@ const char kRevokedUniqueIdentifiers[] = "revoked-unique-identifiers";
const char kTestOnlySerialNumber[] = "test_only-serial-number";
const char kMismatchSerialNumber[] = "mismatch-serial-number";
const char kDeviceModel[] = "device-model-x";
const char kRevokedDeviceModel[] = "device-model-revoked";
const char kTestPreprovKey[] = "00112233445566778899aabbccddeeff";
const uint32_t kStatusListCreationTime = 17798001;
const uint32_t kDefaultExpirePeriod = 0;
const bool kDenyRevokedDevice = false;
const bool kAllowRevokedDevice = true;
class MockClientCert : public ClientCert {
public:
MockClientCert() {}
~MockClientCert() override {}
MOCK_CONST_METHOD0(system_id, uint32_t());
MOCK_CONST_METHOD0(signer_serial_number, std::string &());
MOCK_CONST_METHOD0(signer_creation_time_seconds, uint32_t());
MOCK_CONST_METHOD0(type, ClientIdentification::TokenType());
MOCK_CONST_METHOD0(encrypted_unique_id, const std::string &());
MOCK_CONST_METHOD0(unique_id_hash, const std::string &());
MOCK_CONST_METHOD0(signed_by_provisioner, bool());
MOCK_CONST_METHOD3(VerifySignature, Status(const std::string &message,
const std::string &signature,
ProtocolVersion protocol_version));
MOCK_METHOD2(GenerateSigningKey, void(const std::string &message,
ProtocolVersion protocol_version));
MOCK_CONST_METHOD0(serial_number, const std::string &());
MOCK_CONST_METHOD0(key, const std::string &());
MOCK_CONST_METHOD0(key_type, SignedMessage::SessionKeyType());
MOCK_CONST_METHOD0(service_id, const std::string &());
MOCK_CONST_METHOD0(encrypted_key, const std::string &());
MOCK_CONST_METHOD0(signing_key, const std::string &());
MOCK_METHOD(uint32_t, system_id, (), (const, override));
MOCK_METHOD(std::string &, signer_serial_number, (), (const, override));
MOCK_METHOD(uint32_t, signer_creation_time_seconds, (), (const, override));
MOCK_METHOD(ClientIdentification::TokenType, type, (), (const, override));
MOCK_METHOD(const std::string &, encrypted_unique_id, (), (const, override));
MOCK_METHOD(const std::string &, unique_id_hash, (), (const, override));
MOCK_METHOD(bool, signed_by_provisioner, (), (const, override));
MOCK_METHOD(Status, VerifySignature,
(const std::string &message, HashAlgorithm hash_algorithm,
const std::string &signature, ProtocolVersion protocol_version),
(const, override));
MOCK_METHOD(void, GenerateSigningKey,
(const std::string &message, ProtocolVersion protocol_version),
(override));
MOCK_METHOD(const std::string &, serial_number, (), (const, override));
MOCK_METHOD(const std::string &, key, (), (const, override));
MOCK_METHOD(SignedMessage::SessionKeyType, key_type, (), (const, override));
MOCK_METHOD(bool, using_dual_certificate, (), (const override));
MOCK_METHOD(const std::string &, service_id, (), (const, override));
MOCK_METHOD(const std::string &, encrypted_key, (), (const, override));
MOCK_METHOD(const std::string &, signing_key, (), (const, override));
MOCK_METHOD(Status, SystemIdUnknownError, (), (const, override));
MOCK_METHOD(Status, SystemIdRevokedError, (), (const, override));
};
class DeviceStatusListTest : public ::testing::Test {
@@ -116,6 +125,7 @@ class DeviceStatusListTest : public ::testing::Test {
cert_status = cert_status_list_.add_certificate_status();
cert_status->mutable_device_info()->set_system_id(kRevokedCertSystemId);
cert_status->set_drm_serial_number(kRevokedSerialNumber);
cert_status->mutable_device_info()->set_model(kRevokedDeviceModel);
cert_status->set_status(DeviceCertificateStatus::STATUS_REVOKED);
// Device cert with status REVOKED ALLOWED DEVICE.
@@ -141,6 +151,7 @@ class DeviceStatusListTest : public ::testing::Test {
ASSERT_TRUE(root_key);
cert_status_list_.SerializeToString(&serialized_cert_status_list_);
ASSERT_TRUE(root_key->GenerateSignature(serialized_cert_status_list_,
kHashAlgorithm,
&cert_status_list_signature_));
// Update the device_status_list_ with the serialized status list
@@ -148,11 +159,12 @@ class DeviceStatusListTest : public ::testing::Test {
ASSERT_EQ(OkStatus(),
device_status_list_.UpdateStatusList(
test_keys_.public_test_key_1_3072_bits(),
serialized_cert_status_list_, cert_status_list_signature_,
kDefaultExpirePeriod));
serialized_cert_status_list_, kHashAlgorithm,
cert_status_list_signature_, kDefaultExpirePeriod));
}
void GenerateTrivialValidStatusList(std::string *serialized_cert_status_list,
HashAlgorithm hash_algorithm,
std::string *signature) {
DeviceCertificateStatusList cert_status_list;
DeviceCertificateStatus *cert_status;
@@ -171,17 +183,27 @@ class DeviceStatusListTest : public ::testing::Test {
RsaPrivateKey::Create(test_keys_.private_test_key_1_3072_bits()));
ASSERT_TRUE(root_key);
cert_status_list.SerializeToString(serialized_cert_status_list);
ASSERT_TRUE(
root_key->GenerateSignature(*serialized_cert_status_list, signature));
ASSERT_TRUE(root_key->GenerateSignature(*serialized_cert_status_list,
hash_algorithm, signature));
}
int VerifyAllowedTestOnlyDevicesAdded() {
return device_status_list_.allowed_test_only_devices_.size();
int AllowedTestOnlyDevicesByMakeSize() {
return device_status_list_.allowed_test_only_devices_by_make_size();
}
bool VerifyIsTestOnlyDeviceAllowed(uint32_t system_id,
std::string manufacturer) {
return device_status_list_.IsTestOnlyDeviceAllowed(system_id, manufacturer);
int AllowedTestOnlyDevicesByProviderSize() {
return device_status_list_.allowed_test_only_devices_by_provider_size();
}
bool IsTestOnlyDeviceAllowedByMake(uint32_t system_id,
const std::string &make) {
return device_status_list_.IsTestOnlyDeviceAllowedByMake(system_id, make);
}
bool IsTestOnlyDeviceAllowedByProvider(uint32_t system_id,
const std::string &provider) {
return device_status_list_.IsTestOnlyDeviceAllowedByProvider(system_id,
provider);
}
int VerifyRevokedDeviceCertificatesCount() {
@@ -203,7 +225,7 @@ class DeviceStatusListTest : public ::testing::Test {
TEST_F(DeviceStatusListTest, CheckForValidAndRevokedCert) {
// Test case where the Certificate status is set to Valid.
ProvisionedDeviceInfo device_info;
DeviceCertificateStatus device_certificate_status;
MockClientCert valid_client_cert;
std::string valid_drm_serial_number(kValidSerialNumber);
EXPECT_CALL(valid_client_cert, type())
@@ -212,9 +234,10 @@ TEST_F(DeviceStatusListTest, CheckForValidAndRevokedCert) {
.WillRepeatedly(Return(kValidCertSystemId));
EXPECT_CALL(valid_client_cert, signer_serial_number())
.WillRepeatedly(ReturnRef(valid_drm_serial_number));
EXPECT_EQ(OkStatus(),
device_status_list_.GetCertStatus(valid_client_cert,
kTestManufacturer, &device_info));
EXPECT_EQ(OkStatus(), device_status_list_.GetCertStatus(
valid_client_cert, kTestManufacturer, kTestProvider,
kDenyRevokedDevice, &device_certificate_status));
ProvisionedDeviceInfo device_info = device_certificate_status.device_info();
EXPECT_TRUE(device_info.has_model());
EXPECT_EQ(kDeviceModel, device_info.model());
@@ -227,20 +250,25 @@ TEST_F(DeviceStatusListTest, CheckForValidAndRevokedCert) {
.WillRepeatedly(Return(kRevokedCertSystemId));
EXPECT_CALL(revoked_client_cert, signer_serial_number())
.WillRepeatedly(ReturnRef(revoked_drm_serial_number));
EXPECT_CALL(revoked_client_cert, SystemIdRevokedError())
.WillRepeatedly(
Return(Status(error_space, DRM_DEVICE_CERTIFICATE_REVOKED, "")));
EXPECT_EQ(
DRM_DEVICE_CERTIFICATE_REVOKED,
device_status_list_
.GetCertStatus(revoked_client_cert, kTestManufacturer, &device_info)
.GetCertStatus(revoked_client_cert, kTestManufacturer, kTestProvider,
kDenyRevokedDevice, &device_certificate_status)
.error_code());
// Test case where the revoked cert is allowed.
device_status_list_.AllowRevokedDevices(absl::StrCat(kRevokedCertSystemId));
EXPECT_OK(device_status_list_.GetCertStatus(revoked_client_cert,
kTestManufacturer, &device_info));
EXPECT_OK(device_status_list_.GetCertStatus(
revoked_client_cert, kTestManufacturer, kTestProvider, kDenyRevokedDevice,
&device_certificate_status));
}
TEST_F(DeviceStatusListTest, TestOnlyCertNotAllowed) {
ProvisionedDeviceInfo device_info;
DeviceCertificateStatus device_certificate_status;
MockClientCert test_only_client_cert;
std::string test_only_drm_serial_number(kTestOnlySerialNumber);
EXPECT_CALL(test_only_client_cert, type())
@@ -249,11 +277,12 @@ TEST_F(DeviceStatusListTest, TestOnlyCertNotAllowed) {
.WillRepeatedly(Return(kTestOnlyCertSystemId));
EXPECT_CALL(test_only_client_cert, signer_serial_number())
.WillRepeatedly(ReturnRef(test_only_drm_serial_number));
EXPECT_EQ(
DEVELOPMENT_CERTIFICATE_NOT_ALLOWED,
device_status_list_
.GetCertStatus(test_only_client_cert, kTestManufacturer, &device_info)
.error_code());
EXPECT_EQ(DEVELOPMENT_CERTIFICATE_NOT_ALLOWED,
device_status_list_
.GetCertStatus(test_only_client_cert, kTestManufacturer,
kTestProvider, kDenyRevokedDevice,
&device_certificate_status)
.error_code());
}
TEST_F(DeviceStatusListTest, GetRevokedIfentifiers) {
@@ -269,7 +298,7 @@ TEST_F(DeviceStatusListTest, GetRevokedIfentifiers) {
}
TEST_F(DeviceStatusListTest, TestOnlyCertAllowed) {
ProvisionedDeviceInfo device_info;
DeviceCertificateStatus device_certificate_status;
MockClientCert test_only_client_cert;
std::string test_only_drm_serial_number(kTestOnlySerialNumber);
device_status_list_.set_allow_test_only_devices(true);
@@ -280,41 +309,98 @@ TEST_F(DeviceStatusListTest, TestOnlyCertAllowed) {
EXPECT_CALL(test_only_client_cert, signer_serial_number())
.WillRepeatedly(ReturnRef(test_only_drm_serial_number));
EXPECT_EQ(OkStatus(),
device_status_list_.GetCertStatus(test_only_client_cert,
kTestManufacturer, &device_info));
device_status_list_.GetCertStatus(
test_only_client_cert, kTestManufacturer, kTestProvider,
kDenyRevokedDevice, &device_certificate_status));
}
TEST_F(DeviceStatusListTest, ValidAndUnknownKeybox) {
TEST_F(DeviceStatusListTest, RevokedSystemIdAllowed) {
DeviceCertificateStatus device_certificate_status;
MockClientCert revoked_client_cert;
std::string revoked_drm_serial_number(kRevokedSerialNumber);
EXPECT_CALL(revoked_client_cert, type())
.WillRepeatedly(Return(ClientIdentification::DRM_DEVICE_CERTIFICATE));
EXPECT_CALL(revoked_client_cert, system_id())
.WillRepeatedly(Return(kRevokedCertSystemId));
EXPECT_CALL(revoked_client_cert, signer_serial_number())
.WillRepeatedly(ReturnRef(revoked_drm_serial_number));
EXPECT_EQ(OkStatus(),
device_status_list_.GetCertStatus(
revoked_client_cert, kRevokedManufacturer, kTestProvider,
kAllowRevokedDevice, &device_certificate_status));
}
// Test case where the Certificate status is set to Valid.
TEST_F(DeviceStatusListTest, ValidKeybox) {
std::multimap<uint32_t, std::string> preprov_keys;
preprov_keys.insert(std::make_pair(kValidCertSystemId, kTestPreprovKey));
KeyboxClientCert::SetPreProvisioningKeys(preprov_keys);
// Test case where the Certificate status is set to Valid.
ProvisionedDeviceInfo device_info;
DeviceCertificateStatus device_certificate_status;
MockClientCert valid_client_keybox;
std::string valid_drm_serial_number(kValidSerialNumber);
EXPECT_CALL(valid_client_keybox, type())
.WillRepeatedly(Return(ClientIdentification::KEYBOX));
EXPECT_CALL(valid_client_keybox, system_id())
.WillRepeatedly(Return(kValidCertSystemId));
EXPECT_EQ(OkStatus(),
device_status_list_.GetCertStatus(valid_client_keybox,
kTestManufacturer, &device_info));
EXPECT_TRUE(device_info.has_model());
device_status_list_.GetCertStatus(
valid_client_keybox, kTestManufacturer, kTestProvider,
kDenyRevokedDevice, &device_certificate_status));
ProvisionedDeviceInfo device_info = device_certificate_status.device_info();
ASSERT_TRUE(device_info.has_model());
EXPECT_EQ(kDeviceModel, device_info.model());
}
// Test case where the keybox was not loaded into the pre-prov list.
TEST_F(DeviceStatusListTest, UnknownKeybox) {
std::multimap<uint32_t, std::string> preprov_keys;
preprov_keys.insert(std::make_pair(kValidCertSystemId, kTestPreprovKey));
KeyboxClientCert::SetPreProvisioningKeys(preprov_keys);
DeviceCertificateStatus device_certificate_status;
MockClientCert unknown_client_keybox;
EXPECT_CALL(unknown_client_keybox, type())
.WillRepeatedly(Return(ClientIdentification::KEYBOX));
EXPECT_CALL(unknown_client_keybox, system_id())
.WillRepeatedly(Return(kUnknownSystemId));
EXPECT_EQ(
UNSUPPORTED_SYSTEM_ID,
device_status_list_
.GetCertStatus(unknown_client_keybox, kTestManufacturer, &device_info)
.error_code());
EXPECT_TRUE(device_info.has_model());
EXPECT_EQ(kDeviceModel, device_info.model());
EXPECT_CALL(unknown_client_keybox, SystemIdUnknownError())
.WillRepeatedly(Return(Status(error_space, UNSUPPORTED_SYSTEM_ID, "")));
EXPECT_EQ(UNSUPPORTED_SYSTEM_ID,
device_status_list_
.GetCertStatus(unknown_client_keybox, kTestManufacturer,
kTestProvider, kDenyRevokedDevice,
&device_certificate_status)
.error_code());
ProvisionedDeviceInfo device_info = device_certificate_status.device_info();
ASSERT_FALSE(device_info.has_model());
}
// Test case where the keybox was loaded into the pre-prov list but it's
// certificate status is REVOKED.
TEST_F(DeviceStatusListTest, RevokedKeybox) {
std::multimap<uint32_t, std::string> preprov_keys;
preprov_keys.insert(std::make_pair(kRevokedCertSystemId, kTestPreprovKey));
KeyboxClientCert::SetPreProvisioningKeys(preprov_keys);
DeviceCertificateStatus device_certificate_status;
MockClientCert revoked_client_keybox;
EXPECT_CALL(revoked_client_keybox, type())
.WillRepeatedly(Return(ClientIdentification::KEYBOX));
EXPECT_CALL(revoked_client_keybox, system_id())
.WillRepeatedly(Return(kRevokedCertSystemId));
EXPECT_CALL(revoked_client_keybox, SystemIdRevokedError())
.WillRepeatedly(
Return(Status(error_space, DRM_DEVICE_CERTIFICATE_REVOKED, "")));
EXPECT_EQ(DRM_DEVICE_CERTIFICATE_REVOKED,
device_status_list_
.GetCertStatus(revoked_client_keybox, kTestManufacturer,
kTestProvider, kDenyRevokedDevice,
&device_certificate_status)
.error_code());
ProvisionedDeviceInfo device_info = device_certificate_status.device_info();
ASSERT_TRUE(device_info.has_model());
EXPECT_EQ(kRevokedDeviceModel, device_info.model());
}
TEST_F(DeviceStatusListTest, SignerSerialNumberMismatch) {
@@ -323,7 +409,7 @@ TEST_F(DeviceStatusListTest, SignerSerialNumberMismatch) {
// Test case where the signer certificate is older than the current status
// list.
MockClientCert older_client_cert;
ProvisionedDeviceInfo device_info;
DeviceCertificateStatus device_certificate_status;
std::string mismatch_drm_serial_number(kMismatchSerialNumber);
EXPECT_CALL(older_client_cert, type())
.WillRepeatedly(Return(ClientIdentification::DRM_DEVICE_CERTIFICATE));
@@ -336,20 +422,23 @@ TEST_F(DeviceStatusListTest, SignerSerialNumberMismatch) {
EXPECT_EQ(
INVALID_DRM_CERTIFICATE,
device_status_list_
.GetCertStatus(older_client_cert, kTestManufacturer, &device_info)
.GetCertStatus(older_client_cert, kTestManufacturer, kTestProvider,
kDenyRevokedDevice, &device_certificate_status)
.error_code());
// We allow this case only for certs signed by a provisioner cert.
EXPECT_CALL(older_client_cert, signed_by_provisioner())
.WillOnce(Return(true));
EXPECT_EQ(OkStatus(),
device_status_list_.GetCertStatus(older_client_cert,
kTestManufacturer, &device_info));
EXPECT_EQ(OkStatus(), device_status_list_.GetCertStatus(
older_client_cert, kTestManufacturer, kTestProvider,
kDenyRevokedDevice, &device_certificate_status));
ProvisionedDeviceInfo device_info = device_certificate_status.device_info();
EXPECT_TRUE(device_info.has_system_id());
EXPECT_EQ(kValidCertSystemId, device_info.system_id());
// Test case where the signer certificate is newer than the current status
// list, and unknown devices are allowed.
device_certificate_status.Clear();
MockClientCert newer_client_cert1;
EXPECT_CALL(newer_client_cert1, type())
.WillRepeatedly(Return(ClientIdentification::DRM_DEVICE_CERTIFICATE));
@@ -359,14 +448,19 @@ TEST_F(DeviceStatusListTest, SignerSerialNumberMismatch) {
.WillRepeatedly(ReturnRef(mismatch_drm_serial_number));
EXPECT_CALL(newer_client_cert1, signer_creation_time_seconds())
.WillRepeatedly(Return(kStatusListCreationTime));
EXPECT_CALL(newer_client_cert1, SystemIdUnknownError())
.WillRepeatedly(
Return(Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN, "")));
EXPECT_EQ(
DRM_DEVICE_CERTIFICATE_UNKNOWN,
device_status_list_
.GetCertStatus(newer_client_cert1, kTestManufacturer, &device_info)
.GetCertStatus(newer_client_cert1, kTestManufacturer, kTestProvider,
kDenyRevokedDevice, &device_certificate_status)
.error_code());
// Test case where the signer certificate is newer than the current status
// list, and unknown devices are not allowed.
device_certificate_status.Clear();
device_status_list_.set_allow_unknown_devices(false);
MockClientCert newer_client_cert2;
EXPECT_CALL(newer_client_cert2, type())
@@ -377,10 +471,14 @@ TEST_F(DeviceStatusListTest, SignerSerialNumberMismatch) {
.WillRepeatedly(ReturnRef(mismatch_drm_serial_number));
EXPECT_CALL(newer_client_cert2, signer_creation_time_seconds())
.WillRepeatedly(Return(kStatusListCreationTime + 1));
EXPECT_CALL(newer_client_cert2, SystemIdUnknownError())
.WillRepeatedly(
Return(Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN, "")));
EXPECT_EQ(
DRM_DEVICE_CERTIFICATE_UNKNOWN,
device_status_list_
.GetCertStatus(newer_client_cert2, kTestManufacturer, &device_info)
.GetCertStatus(newer_client_cert2, kTestManufacturer, kTestProvider,
kDenyRevokedDevice, &device_certificate_status)
.error_code());
}
@@ -388,7 +486,7 @@ TEST_F(DeviceStatusListTest, InvalidStatusList) {
EXPECT_EQ(INVALID_CERTIFICATE_STATUS_LIST,
device_status_list_
.UpdateStatusList(test_keys_.public_test_key_2_2048_bits(),
serialized_cert_status_list_,
serialized_cert_status_list_, kHashAlgorithm,
cert_status_list_signature_, 0)
.error_code());
@@ -396,14 +494,14 @@ TEST_F(DeviceStatusListTest, InvalidStatusList) {
EXPECT_EQ(INVALID_CERTIFICATE_STATUS_LIST,
device_status_list_
.UpdateStatusList(test_keys_.public_test_key_1_3072_bits(),
serialized_cert_status_list_,
serialized_cert_status_list_, kHashAlgorithm,
cert_status_list_signature_, 0)
.error_code());
}
class MockDeviceStatusList : public DeviceStatusList {
public:
MOCK_CONST_METHOD0(GetCurrentTime, uint32_t());
MOCK_METHOD(uint32_t, GetCurrentTime, (), (const, override));
};
TEST_F(DeviceStatusListTest, ExpiredStatusListOnSet) {
@@ -414,12 +512,12 @@ TEST_F(DeviceStatusListTest, ExpiredStatusListOnSet) {
.WillOnce(Return(kStatusListCreationTime + 101));
EXPECT_EQ(OkStatus(), mock_device_status_list.UpdateStatusList(
test_keys_.public_test_key_1_3072_bits(),
serialized_cert_status_list_,
serialized_cert_status_list_, kHashAlgorithm,
cert_status_list_signature_, 100));
EXPECT_EQ(EXPIRED_CERTIFICATE_STATUS_LIST,
mock_device_status_list
.UpdateStatusList(test_keys_.public_test_key_1_3072_bits(),
serialized_cert_status_list_,
serialized_cert_status_list_, kHashAlgorithm,
cert_status_list_signature_, 100)
.error_code());
}
@@ -433,10 +531,10 @@ TEST_F(DeviceStatusListTest, ExpiredStatusListOnCertCheck) {
.WillOnce(Return(kStatusListCreationTime + 101));
EXPECT_EQ(OkStatus(), mock_device_status_list.UpdateStatusList(
test_keys_.public_test_key_1_3072_bits(),
serialized_cert_status_list_,
serialized_cert_status_list_, kHashAlgorithm,
cert_status_list_signature_, 100));
ProvisionedDeviceInfo device_info;
DeviceCertificateStatus device_certificate_status;
MockClientCert valid_client_cert;
std::string valid_drm_serial_number(kValidSerialNumber);
EXPECT_CALL(valid_client_cert, type())
@@ -447,14 +545,15 @@ TEST_F(DeviceStatusListTest, ExpiredStatusListOnCertCheck) {
.WillRepeatedly(ReturnRef(valid_drm_serial_number));
EXPECT_CALL(valid_client_cert, signer_creation_time_seconds())
.WillRepeatedly(Return(kStatusListCreationTime - 1));
EXPECT_EQ(OkStatus(),
mock_device_status_list.GetCertStatus(
valid_client_cert, kTestManufacturer, &device_info));
EXPECT_EQ(OkStatus(), mock_device_status_list.GetCertStatus(
valid_client_cert, kTestManufacturer, kTestProvider,
kDenyRevokedDevice, &device_certificate_status));
EXPECT_EQ(
EXPIRED_CERTIFICATE_STATUS_LIST,
mock_device_status_list
.GetCertStatus(valid_client_cert, kTestManufacturer, &device_info)
.GetCertStatus(valid_client_cert, kTestManufacturer, kTestProvider,
kDenyRevokedDevice, &device_certificate_status)
.error_code());
}
@@ -477,49 +576,109 @@ TEST_F(DeviceStatusListTest, IsSystemIdActive) {
device_status_list_.IsSystemIdActive(kRevokedAllowedDeviceCertSystemId));
}
TEST_F(DeviceStatusListTest, IsTestOnlyDeviceAllowed) {
std::string whitelisted_device_list =
std::string(kTestSystemId_1) + ":" + std::string(kTestManufacturer_LG);
whitelisted_device_list += "," + std::string(kTestSystemId_2) + ":" +
std::string(kTestManufacturer_Samsung);
whitelisted_device_list += "," + std::string(kTestSystemId_3) + ":";
whitelisted_device_list += ", " + std::string(kTestSystemId_1) + ":" +
std::string(kTestManufacturer_LGE);
device_status_list_.AllowTestOnlyDevices(whitelisted_device_list);
EXPECT_EQ(4, VerifyAllowedTestOnlyDevicesAdded());
TEST_F(DeviceStatusListTest, IsTestOnlyDeviceAllowedByMake) {
const char kTestManufacturer_AA[] = "AA";
const char kTestManufacturer_AAA[] = "AAA";
const char kTestManufacturer_BBB[] = "BBB";
const char kTestManufacturer_BbB[] = "BbB";
const char kTestManufacturer_bbb[] = "bbb";
const char kTestManufacturer_CCC[] = "CCC";
const char kTestManufacturer_DDD[] = "AAA";
std::string allowed_device_list =
std::string(kTestSystemId_1) + ":" + std::string(kTestManufacturer_AA);
allowed_device_list += "," + std::string(kTestSystemId_2) + ":" +
std::string(kTestManufacturer_BBB);
allowed_device_list += "," + std::string(kTestSystemId_3) + ":";
allowed_device_list += ", " + std::string(kTestSystemId_1) + ":" +
std::string(kTestManufacturer_AAA);
device_status_list_.AllowTestOnlyDevicesByMake(allowed_device_list);
EXPECT_EQ(4, AllowedTestOnlyDevicesByMakeSize());
// Verify that device with system_id = kTestSystemId_1 and
// manufacturer = kTestManufacturer_LG is allowed.
EXPECT_TRUE(VerifyIsTestOnlyDeviceAllowed(std::stoi(kTestSystemId_1),
kTestManufacturer_LG));
// manufacturer AA is allowed.
EXPECT_TRUE(IsTestOnlyDeviceAllowedByMake(std::stoi(kTestSystemId_1),
kTestManufacturer_AA));
// Verify that device with system_id = kTestSystemId_1 and
// manufacturer = kTestManufacturer_LGE is allowed.
EXPECT_TRUE(VerifyIsTestOnlyDeviceAllowed(std::stoi(kTestSystemId_1),
kTestManufacturer_LGE));
// manufacturer AAA is allowed.
EXPECT_TRUE(IsTestOnlyDeviceAllowedByMake(std::stoi(kTestSystemId_1),
kTestManufacturer_AAA));
// Verify that device with system_id = kTestSystemId_2 and
// manufacturer = kTestManufacturer_LGE is not allowed.
// This is because this combination is not 'whitelisted'.
EXPECT_FALSE(VerifyIsTestOnlyDeviceAllowed(std::stoi(kTestSystemId_2),
kTestManufacturer_LGE));
// manufacturer AAA is not allowed.
// This is because this combination is not in the allowed list.
EXPECT_FALSE(IsTestOnlyDeviceAllowedByMake(std::stoi(kTestSystemId_2),
kTestManufacturer_AAA));
// Verify that device with system_id = kTestSystemId_2 and
// manufacturer = kTestManufacturer_Samsung is allowed.
EXPECT_TRUE(VerifyIsTestOnlyDeviceAllowed(std::stoi(kTestSystemId_2),
kTestManufacturer_Samsung));
// manufacturer BBB is allowed.
EXPECT_TRUE(IsTestOnlyDeviceAllowedByMake(std::stoi(kTestSystemId_2),
kTestManufacturer_BBB));
// Verifes that device with mixed case succeeds.
EXPECT_TRUE(
VerifyIsTestOnlyDeviceAllowed(std::stoi(kTestSystemId_2), "samSung"));
EXPECT_TRUE(
VerifyIsTestOnlyDeviceAllowed(std::stoi(kTestSystemId_2), "SAMsung"));
EXPECT_TRUE(IsTestOnlyDeviceAllowedByMake(std::stoi(kTestSystemId_2),
kTestManufacturer_BbB));
EXPECT_TRUE(IsTestOnlyDeviceAllowedByMake(std::stoi(kTestSystemId_2),
kTestManufacturer_bbb));
// Verify that device with system_id = kTestSystemId_3 and
// any manufacturer is allowed. This checks that any manufacturer is
// allowed for this system_id.
EXPECT_TRUE(
VerifyIsTestOnlyDeviceAllowed(std::stoi(kTestSystemId_3), "Cisco"));
EXPECT_TRUE(VerifyIsTestOnlyDeviceAllowed(std::stoi(kTestSystemId_3),
"ScientificAtlanta"));
EXPECT_TRUE(IsTestOnlyDeviceAllowedByMake(std::stoi(kTestSystemId_3),
kTestManufacturer_CCC));
EXPECT_TRUE(IsTestOnlyDeviceAllowedByMake(std::stoi(kTestSystemId_3),
kTestManufacturer_DDD));
uint32_t unknown_system_id = 7890;
// Verify that device with system_id = unknown_system_id and
// manufacturer = "Cisco" is not allowed.
EXPECT_FALSE(VerifyIsTestOnlyDeviceAllowed(unknown_system_id, "Cisco"));
// manufacturer CCC is not allowed.
EXPECT_FALSE(
IsTestOnlyDeviceAllowedByMake(unknown_system_id, kTestManufacturer_CCC));
}
TEST_F(DeviceStatusListTest, IsTestOnlyDeviceAllowedByProvider) {
const char kTestProvider_AA[] = "AA";
const char kTestProvider_AAA[] = "AAA";
const char kTestProvider_BBB[] = "BBB";
const char kTestProvider_BbB[] = "BbB";
const char kTestProvider_bbb[] = "bbb";
const char kTestProvider_CCC[] = "CCC";
std::string allowed_device_list =
std::string(kTestSystemId_1) + ":" + std::string(kTestProvider_AA);
allowed_device_list +=
"," + std::string(kTestSystemId_2) + ":" + std::string(kTestProvider_BBB);
allowed_device_list += "," + std::string(kTestSystemId_3) + ":";
allowed_device_list += ", " + std::string(kTestSystemId_1) + ":" +
std::string(kTestProvider_AAA);
device_status_list_.AllowTestOnlyDevicesByProvider(allowed_device_list);
EXPECT_EQ(4, AllowedTestOnlyDevicesByProviderSize());
// Verify that device with system_id = kTestSystemId_1 and
// provider AA is allowed.
EXPECT_TRUE(IsTestOnlyDeviceAllowedByProvider(std::stoi(kTestSystemId_1),
kTestProvider_AA));
// Verify that device with system_id = kTestSystemId_1 and
// provider AAA is allowed.
EXPECT_TRUE(IsTestOnlyDeviceAllowedByProvider(std::stoi(kTestSystemId_1),
kTestProvider_AAA));
// Verify that device with system_id = kTestSystemId_2 and
// provider AAA is not allowed.
// This is because this combination is not 'whitelisted'.
EXPECT_FALSE(IsTestOnlyDeviceAllowedByProvider(std::stoi(kTestSystemId_2),
kTestProvider_AAA));
// Verify that device with system_id = kTestSystemId_2 and
// provider BBB is allowed.
EXPECT_TRUE(IsTestOnlyDeviceAllowedByProvider(std::stoi(kTestSystemId_2),
kTestProvider_BBB));
// Verifes that device with mixed case succeeds.
EXPECT_TRUE(IsTestOnlyDeviceAllowedByProvider(std::stoi(kTestSystemId_2),
kTestProvider_BbB));
EXPECT_TRUE(IsTestOnlyDeviceAllowedByProvider(std::stoi(kTestSystemId_2),
kTestProvider_bbb));
// Verify that device with system_id = kTestSystemId_3 and
// any provider is allowed. This checks that any provider is
// allowed for this system_id.
EXPECT_TRUE(IsTestOnlyDeviceAllowedByProvider(std::stoi(kTestSystemId_3),
kTestProvider_CCC));
EXPECT_TRUE(IsTestOnlyDeviceAllowedByProvider(std::stoi(kTestSystemId_3),
kTestProvider_AAA));
uint32_t unknown_system_id = 7890;
// Verify that device with system_id = unknown_system_id and
// provider CCC is not allowed.
EXPECT_FALSE(
IsTestOnlyDeviceAllowedByProvider(unknown_system_id, kTestProvider_CCC));
}
TEST_F(DeviceStatusListTest, IsDrmDeviceCertificateRevoked) {
@@ -552,6 +711,7 @@ TEST_F(DeviceStatusListTest, DetermineAndDeserializeServiceResponseSuccess) {
SignedDeviceInfo published_devices;
GenerateTrivialValidStatusList(
published_devices.mutable_device_certificate_status_list(),
HashAlgorithmProtoToEnum(published_devices.hash_algorithm()),
published_devices.mutable_signature());
std::string serialized_published_devices;
@@ -561,13 +721,17 @@ TEST_F(DeviceStatusListTest, DetermineAndDeserializeServiceResponseSuccess) {
DeviceCertificateStatusList actual_cert_status_list;
std::string actual_serialized_cert_status_list;
std::string actual_signature;
HashAlgorithm hash_algorithm;
ASSERT_EQ(OkStatus(),
DeviceStatusList::DetermineAndDeserializeServiceResponse(
serialized_published_devices, &actual_cert_status_list,
&actual_serialized_cert_status_list, &actual_signature));
&actual_serialized_cert_status_list, &hash_algorithm,
&actual_signature));
EXPECT_EQ(published_devices.device_certificate_status_list(),
actual_serialized_cert_status_list);
EXPECT_EQ(published_devices.signature(), actual_signature);
EXPECT_EQ(HashAlgorithmProtoToEnum(published_devices.hash_algorithm()),
hash_algorithm);
DeviceCertificateStatusList expected_cert_status_list;
ASSERT_TRUE(expected_cert_status_list.ParseFromString(
@@ -580,9 +744,11 @@ TEST_F(DeviceStatusListTest,
DetermineAndDeserializeServiceResponseLegacySuccess) {
std::string serialized_cert_status_list;
std::string signature;
GenerateTrivialValidStatusList(&serialized_cert_status_list, &signature);
SignedDeviceCertificateStatusList legacy_signed_cert_status_list;
GenerateTrivialValidStatusList(
&serialized_cert_status_list,
HashAlgorithmProtoToEnum(legacy_signed_cert_status_list.hash_algorithm()),
&signature);
*(legacy_signed_cert_status_list.mutable_certificate_status_list()) =
serialized_cert_status_list;
*(legacy_signed_cert_status_list.mutable_signature()) = signature;
@@ -604,12 +770,17 @@ TEST_F(DeviceStatusListTest,
std::string actual_serialized_cert_status_list;
std::string actual_signature;
DeviceCertificateStatusList actual_cert_status_list;
HashAlgorithm hash_algorithm;
ASSERT_EQ(OkStatus(),
DeviceStatusList::DetermineAndDeserializeServiceResponse(
server_response, &actual_cert_status_list,
&actual_serialized_cert_status_list, &actual_signature));
&actual_serialized_cert_status_list, &hash_algorithm,
&actual_signature));
EXPECT_EQ(serialized_cert_status_list, actual_serialized_cert_status_list);
EXPECT_EQ(signature, actual_signature);
EXPECT_EQ(
HashAlgorithmProtoToEnum(legacy_signed_cert_status_list.hash_algorithm()),
hash_algorithm);
DeviceCertificateStatusList expected_cert_status_list;
ASSERT_TRUE(
@@ -622,9 +793,11 @@ TEST_F(DeviceStatusListTest,
DetermineAndDeserializeServiceResponseLegacyWebSafeBase64Success) {
std::string serialized_cert_status_list;
std::string signature;
GenerateTrivialValidStatusList(&serialized_cert_status_list, &signature);
SignedDeviceCertificateStatusList legacy_signed_cert_status_list;
GenerateTrivialValidStatusList(
&serialized_cert_status_list,
HashAlgorithmProtoToEnum(legacy_signed_cert_status_list.hash_algorithm()),
&signature);
*(legacy_signed_cert_status_list.mutable_certificate_status_list()) =
serialized_cert_status_list;
*(legacy_signed_cert_status_list.mutable_signature()) = signature;
@@ -639,14 +812,18 @@ TEST_F(DeviceStatusListTest,
std::string actual_serialized_cert_status_list;
std::string actual_signature;
HashAlgorithm hash_algorithm;
DeviceCertificateStatusList actual_cert_status_list;
ASSERT_EQ(OkStatus(),
DeviceStatusList::DetermineAndDeserializeServiceResponse(
websafe_b64_serialized_signed_cert_status_list,
&actual_cert_status_list, &actual_serialized_cert_status_list,
&actual_signature));
&hash_algorithm, &actual_signature));
EXPECT_EQ(serialized_cert_status_list, actual_serialized_cert_status_list);
EXPECT_EQ(signature, actual_signature);
EXPECT_EQ(
HashAlgorithmProtoToEnum(legacy_signed_cert_status_list.hash_algorithm()),
hash_algorithm);
DeviceCertificateStatusList expected_cert_status_list;
ASSERT_TRUE(
@@ -659,9 +836,11 @@ TEST_F(DeviceStatusListTest,
DetermineAndDeserializeServiceResponseLegacyBase64Success) {
std::string serialized_cert_status_list;
std::string signature;
GenerateTrivialValidStatusList(&serialized_cert_status_list, &signature);
SignedDeviceCertificateStatusList legacy_signed_cert_status_list;
GenerateTrivialValidStatusList(
&serialized_cert_status_list,
HashAlgorithmProtoToEnum(legacy_signed_cert_status_list.hash_algorithm()),
&signature);
*(legacy_signed_cert_status_list.mutable_certificate_status_list()) =
serialized_cert_status_list;
*(legacy_signed_cert_status_list.mutable_signature()) = signature;
@@ -676,14 +855,18 @@ TEST_F(DeviceStatusListTest,
std::string actual_serialized_cert_status_list;
std::string actual_signature;
HashAlgorithm hash_algorithm;
DeviceCertificateStatusList actual_cert_status_list;
ASSERT_EQ(OkStatus(),
DeviceStatusList::DetermineAndDeserializeServiceResponse(
websafe_b64_serialized_signed_cert_status_list,
&actual_cert_status_list, &actual_serialized_cert_status_list,
&actual_signature));
&hash_algorithm, &actual_signature));
EXPECT_EQ(serialized_cert_status_list, actual_serialized_cert_status_list);
EXPECT_EQ(signature, actual_signature);
EXPECT_EQ(
HashAlgorithmProtoToEnum(legacy_signed_cert_status_list.hash_algorithm()),
hash_algorithm);
DeviceCertificateStatusList expected_cert_status_list;
ASSERT_TRUE(
@@ -692,4 +875,44 @@ TEST_F(DeviceStatusListTest,
expected_cert_status_list, actual_cert_status_list));
}
TEST_F(DeviceStatusListTest,
GetDeviceCertificateStatusBySystemIdExpiredDeviceCertificateStatusList) {
MockDeviceStatusList mock_device_status_list;
EXPECT_CALL(mock_device_status_list, GetCurrentTime())
.Times(3)
.WillOnce(Return(kStatusListCreationTime + 100))
.WillOnce(Return(kStatusListCreationTime + 100))
.WillOnce(Return(kStatusListCreationTime + 101));
EXPECT_EQ(OkStatus(), mock_device_status_list.UpdateStatusList(
test_keys_.public_test_key_1_3072_bits(),
serialized_cert_status_list_, kHashAlgorithm,
cert_status_list_signature_, 100));
DeviceCertificateStatus device_certificate_status;
EXPECT_EQ(OkStatus(),
mock_device_status_list.GetDeviceCertificateStatusBySystemId(
kValidCertSystemId, &device_certificate_status));
EXPECT_EQ(EXPIRED_CERTIFICATE_STATUS_LIST,
mock_device_status_list
.GetDeviceCertificateStatusBySystemId(
kValidCertSystemId, &device_certificate_status)
.error_code());
}
TEST_F(DeviceStatusListTest,
GetDeviceCertificateStatusBySystemIdUnknownDevice) {
DeviceCertificateStatus device_certificate_status;
uint32_t unknown_system_id = 2000;
EXPECT_EQ(DRM_DEVICE_CERTIFICATE_UNKNOWN,
device_status_list_
.GetDeviceCertificateStatusBySystemId(
unknown_system_id, &device_certificate_status)
.error_code());
}
TEST_F(DeviceStatusListTest, GetDeviceCertificateStatusBySystemIdOk) {
DeviceCertificateStatus device_certificate_status;
EXPECT_OK(device_status_list_.GetDeviceCertificateStatusBySystemId(
kValidCertSystemId, &device_certificate_status));
}
} // namespace widevine

View File

@@ -18,6 +18,8 @@
#include "absl/synchronization/mutex.h"
#include "common/ec_key.h"
#include "common/error_space.h"
#include "common/hash_algorithm.h"
#include "common/hash_algorithm_util.h"
#include "common/rsa_key.h"
#include "common/sha_util.h"
#include "common/signer_public_key.h"
@@ -281,6 +283,7 @@ class VerifiedCertSignatureCache {
// cache.
Status VerifySignature(const std::string& cert,
const std::string& serial_number,
HashAlgorithm hash_algorithm,
const std::string& signature,
const DrmCertificate& signer) {
{
@@ -314,7 +317,7 @@ class VerifiedCertSignatureCache {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-signer-public-key");
}
if (!signer_public_key->VerifySignature(cert, signature)) {
if (!signer_public_key->VerifySignature(cert, hash_algorithm, signature)) {
return Status(error_space, INVALID_SIGNATURE,
"cache-miss-invalid-signature");
}
@@ -428,8 +431,10 @@ Status DrmRootCertificate::Create(CertificateType cert_type,
return Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-root-public-key");
}
if (!public_key->VerifySignature(signed_root_cert.drm_certificate(),
signed_root_cert.signature())) {
if (!public_key->VerifySignature(
signed_root_cert.drm_certificate(),
HashAlgorithmProtoToEnum(signed_root_cert.hash_algorithm()),
signed_root_cert.signature())) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-root-certificate-signature");
}
@@ -519,6 +524,7 @@ Status DrmRootCertificate::VerifySignatures(
// Always use cache for root-signed certificates.
return signature_cache_->VerifySignature(
signed_cert.drm_certificate(), cert_serial_number,
HashAlgorithmProtoToEnum(signed_cert.hash_algorithm()),
signed_cert.signature(), root_cert_);
}
DrmCertificate signer;
@@ -539,9 +545,10 @@ Status DrmRootCertificate::VerifySignatures(
}
if (use_cache) {
status = signature_cache_->VerifySignature(signed_cert.drm_certificate(),
cert_serial_number,
signed_cert.signature(), signer);
status = signature_cache_->VerifySignature(
signed_cert.drm_certificate(), cert_serial_number,
HashAlgorithmProtoToEnum(signed_cert.hash_algorithm()),
signed_cert.signature(), signer);
if (!status.ok()) {
return status;
}
@@ -552,8 +559,10 @@ Status DrmRootCertificate::VerifySignatures(
return Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-leaf-signer-public-key");
}
if (!signer_public_key->VerifySignature(signed_cert.drm_certificate(),
signed_cert.signature())) {
if (!signer_public_key->VerifySignature(
signed_cert.drm_certificate(),
HashAlgorithmProtoToEnum(signed_cert.hash_algorithm()),
signed_cert.signature())) {
return Status(error_space, INVALID_SIGNATURE,
"cache-miss-invalid-signature");
}

View File

@@ -21,6 +21,8 @@
#include "common/ec_key.h"
#include "common/ec_test_keys.h"
#include "common/error_space.h"
#include "common/hash_algorithm.h"
#include "common/hash_algorithm_util.h"
#include "common/rsa_key.h"
#include "common/rsa_test_keys.h"
#include "common/test_drm_certificates.h"
@@ -101,6 +103,7 @@ class SignerPrivateKey {
public:
virtual ~SignerPrivateKey() {}
virtual bool GenerateSignature(const std::string& message,
HashAlgorithm hash_algorithm,
std::string* signature) const = 0;
virtual DrmCertificate::Algorithm algorithm() const = 0;
static std::unique_ptr<SignerPrivateKey> Create(
@@ -119,8 +122,9 @@ class SignerPrivateKeyImpl : public SignerPrivateKey {
: private_key_(std::move(private_key)), algorithm_(algorithm) {}
~SignerPrivateKeyImpl() override {}
bool GenerateSignature(const std::string& message,
HashAlgorithm hash_algorithm,
std::string* signature) const override {
return private_key_->GenerateSignature(message, signature);
return private_key_->GenerateSignature(message, hash_algorithm, signature);
}
DrmCertificate::Algorithm algorithm() const override { return algorithm_; }
@@ -255,7 +259,9 @@ class DrmRootCertificateTest : public testing::TestWithParam<const char*> {
ASSERT_TRUE(drm_certificates_[kClientKey].SerializeToString(
current_sc->mutable_drm_certificate()));
ASSERT_TRUE(private_keys_[kInterMediateKey]->GenerateSignature(
current_sc->drm_certificate(), current_sc->mutable_signature()));
current_sc->drm_certificate(),
HashAlgorithmProtoToEnum(current_sc->hash_algorithm()),
current_sc->mutable_signature()));
current_sc = current_sc->mutable_signer();
drm_certificates_[kInterMediateKey].set_algorithm(
@@ -263,7 +269,9 @@ class DrmRootCertificateTest : public testing::TestWithParam<const char*> {
ASSERT_TRUE(drm_certificates_[kInterMediateKey].SerializeToString(
current_sc->mutable_drm_certificate()));
ASSERT_TRUE(private_keys_[kDrmRootKey]->GenerateSignature(
current_sc->drm_certificate(), current_sc->mutable_signature()));
current_sc->drm_certificate(),
HashAlgorithmProtoToEnum(current_sc->hash_algorithm()),
current_sc->mutable_signature()));
current_sc = current_sc->mutable_signer();
drm_certificates_[kDrmRootKey].set_algorithm(
@@ -271,7 +279,9 @@ class DrmRootCertificateTest : public testing::TestWithParam<const char*> {
ASSERT_TRUE(drm_certificates_[kDrmRootKey].SerializeToString(
current_sc->mutable_drm_certificate()));
ASSERT_TRUE(private_keys_[kDrmRootKey]->GenerateSignature(
current_sc->drm_certificate(), current_sc->mutable_signature()));
current_sc->drm_certificate(),
HashAlgorithmProtoToEnum(current_sc->hash_algorithm()),
current_sc->mutable_signature()));
}
RsaTestKeys rsa_test_keys_;

View File

@@ -13,7 +13,7 @@
#include <utility>
#include "glog/logging.h"
#include "base/thread_annotations.h"
#include "absl/base/thread_annotations.h"
#include "absl/strings/escaping.h"
#include "absl/synchronization/mutex.h"
#include "util/gtl/map_util.h"

View File

@@ -17,6 +17,7 @@
#include "absl/strings/escaping.h"
#include "common/aes_cbc_util.h"
#include "common/drm_root_certificate.h"
#include "common/hash_algorithm_util.h"
#include "common/rsa_key.h"
#include "common/rsa_test_keys.h"
#include "common/rsa_util.h"
@@ -62,8 +63,10 @@ class DrmServiceCertificateTest : public ::testing::Test {
cert.set_creation_time_seconds(creation_time_seconds);
SignedDrmCertificate signed_cert;
cert.SerializeToString(signed_cert.mutable_drm_certificate());
root_private_key_->GenerateSignature(signed_cert.drm_certificate(),
signed_cert.mutable_signature());
root_private_key_->GenerateSignature(
signed_cert.drm_certificate(),
HashAlgorithmProtoToEnum(signed_cert.hash_algorithm()),
signed_cert.mutable_signature());
std::string serialized_cert;
signed_cert.SerializeToString(&serialized_cert);
return serialized_cert;

View File

@@ -0,0 +1,113 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 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/dual_certificate_client_cert.h"
#include "common/error_space.h"
#include "common/status.h"
#include "protos/public/errors.pb.h"
namespace widevine {
Status DualCertificateClientCert::Initialize(
const DrmRootCertificate* root_certificate,
const std::string& serialized_signing_certificate,
const std::string& serialized_encryption_certificate) {
Status status = signing_certificate_.Initialize(
root_certificate, serialized_signing_certificate);
if (!status.ok()) {
return status;
}
status = encryption_certificate_.Initialize(
root_certificate, serialized_encryption_certificate);
if (!status.ok()) {
return status;
}
if (encryption_certificate_.signer_serial_number() !=
signing_certificate_.signer_serial_number()) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"certificate_signer_mismatch");
}
if ((encryption_certificate_.system_id() !=
signing_certificate_.system_id()) ||
(encryption_certificate_.service_id() !=
signing_certificate_.service_id()) ||
(encryption_certificate_.signer_creation_time_seconds() !=
signing_certificate_.signer_creation_time_seconds()) ||
(encryption_certificate_.signed_by_provisioner() !=
signing_certificate_.signed_by_provisioner())) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid_certificate_pair");
}
return OkStatus();
}
Status DualCertificateClientCert::VerifySignature(
const std::string& message, HashAlgorithm hash_algorithm,
const std::string& signature, ProtocolVersion protocol_version) const {
return signing_certificate_.VerifySignature(message, hash_algorithm,
signature, protocol_version);
}
void DualCertificateClientCert::GenerateSigningKey(
const std::string& message, ProtocolVersion protocol_version) {
encryption_certificate_.GenerateSigningKey(message, protocol_version);
}
const std::string& DualCertificateClientCert::encrypted_key() const {
return encryption_certificate_.encrypted_key();
}
const std::string& DualCertificateClientCert::key() const {
return encryption_certificate_.key();
}
SignedMessage::SessionKeyType DualCertificateClientCert::key_type() const {
return encryption_certificate_.key_type();
}
// TODO(b/155979840): Support revocation check for the encryption certificate.
const std::string& DualCertificateClientCert::serial_number() const {
return signing_certificate_.serial_number();
}
const std::string& DualCertificateClientCert::service_id() const {
return signing_certificate_.service_id();
}
const std::string& DualCertificateClientCert::signing_key() const {
return encryption_certificate_.signing_key();
}
const std::string& DualCertificateClientCert::signer_serial_number() const {
return signing_certificate_.signer_serial_number();
}
uint32_t DualCertificateClientCert::signer_creation_time_seconds() const {
return signing_certificate_.signer_creation_time_seconds();
}
bool DualCertificateClientCert::signed_by_provisioner() const {
return signing_certificate_.signed_by_provisioner();
}
uint32_t DualCertificateClientCert::system_id() const {
return signing_certificate_.system_id();
}
// TODO(b/155979840): Support revocation check for the encryption certificate.
const std::string& DualCertificateClientCert::encrypted_unique_id() const {
return signing_certificate_.encrypted_unique_id();
}
// TODO(b/155979840): Support revocation check for the encryption certificate.
const std::string& DualCertificateClientCert::unique_id_hash() const {
return signing_certificate_.unique_id_hash();
}
} // namespace widevine

View File

@@ -0,0 +1,57 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_DUAL_CERTIFICATE_CLIENT_CERT_H_
#define COMMON_DUAL_CERTIFICATE_CLIENT_CERT_H_
#include "common/certificate_client_cert.h"
namespace widevine {
class DualCertificateClientCert : public ClientCert {
public:
DualCertificateClientCert() = default;
~DualCertificateClientCert() override = default;
DualCertificateClientCert(const DualCertificateClientCert&) = delete;
DualCertificateClientCert& operator=(const DualCertificateClientCert&) =
delete;
Status Initialize(const DrmRootCertificate* root_certificate,
const std::string& serialized_signing_certificate,
const std::string& serialized_encryption_certificate);
Status VerifySignature(const std::string& message,
HashAlgorithm hash_algorithm,
const std::string& signature,
ProtocolVersion protocol_version) const override;
void GenerateSigningKey(const std::string& message,
ProtocolVersion protocol_version) override;
const std::string& encrypted_key() const override;
const std::string& key() const override;
SignedMessage::SessionKeyType key_type() const override;
bool using_dual_certificate() const override { return true; }
const std::string& serial_number() const override;
const std::string& service_id() const override;
const std::string& signing_key() const override;
const std::string& signer_serial_number() const override;
uint32_t signer_creation_time_seconds() const override;
bool signed_by_provisioner() const override;
uint32_t system_id() const override;
widevine::ClientIdentification::TokenType type() const override {
return ClientIdentification::DRM_DEVICE_CERTIFICATE;
}
const std::string& encrypted_unique_id() const override;
const std::string& unique_id_hash() const override;
private:
CertificateClientCert signing_certificate_;
CertificateClientCert encryption_certificate_;
};
} // namespace widevine
#endif // COMMON_DUAL_CERTIFICATE_CLIENT_CERT_H_

View File

@@ -23,6 +23,7 @@
#include "openssl/sha.h"
#include "common/aes_cbc_util.h"
#include "common/ec_util.h"
#include "common/hash_algorithm.h"
#include "common/openssl_util.h"
#include "common/sha_util.h"
@@ -53,6 +54,22 @@ std::string OpenSSLErrorString(uint32_t error) {
return buf;
}
std::string GetMessageDigest(const std::string& message,
widevine::HashAlgorithm hash_algorithm) {
switch (hash_algorithm) {
case widevine::HashAlgorithm::kUnspecified:
case widevine::HashAlgorithm::kSha256:
return widevine::Sha256_Hash(message);
case widevine::HashAlgorithm::kSha1:
LOG(ERROR) << "Unexpected hash algorithm: "
<< static_cast<int>(hash_algorithm);
return "";
}
LOG(FATAL) << "Unexpected hash algorithm: "
<< static_cast<int>(hash_algorithm);
return "";
}
} // namespace
ECPrivateKey::ECPrivateKey(EC_KEY* ec_key) : key_(ec_key) {
@@ -159,6 +176,47 @@ bool ECPrivateKey::GenerateSignature(const std::string& message,
return true;
}
bool ECPrivateKey::GenerateSignature(const std::string& message,
HashAlgorithm hash_algorithm,
std::string* signature) const {
if (message.empty()) {
LOG(ERROR) << "|message| cannot be empty";
return false;
}
if (signature == nullptr) {
LOG(ERROR) << "|signature| cannot be nullptr";
return false;
}
// Hash the message using corresponding hash algorithm.
std::string message_digest = GetMessageDigest(message, hash_algorithm);
if (message_digest.empty()) {
LOG(ERROR) << "Empty message digest";
return false;
}
size_t max_signature_size = ECDSA_size(key());
if (max_signature_size == 0) {
LOG(ERROR) << "key_ does not have a group set";
return false;
}
signature->resize(max_signature_size);
unsigned int bytes_written = 0;
int result = ECDSA_sign(
0 /* unused type */,
reinterpret_cast<const uint8_t*>(message_digest.data()),
message_digest.size(),
reinterpret_cast<uint8_t*>(const_cast<char*>(signature->data())),
&bytes_written, key());
if (result != 1) {
LOG(ERROR) << "Could not calculate signature: "
<< OpenSSLErrorString(ERR_get_error());
return false;
}
signature->resize(bytes_written);
return true;
}
bool ECPrivateKey::MatchesPrivateKey(const ECPrivateKey& private_key) const {
return BN_cmp(EC_KEY_get0_private_key(key()),
EC_KEY_get0_private_key(private_key.key())) == 0;
@@ -254,6 +312,39 @@ bool ECPublicKey::VerifySignature(const std::string& message,
return true;
}
bool ECPublicKey::VerifySignature(const std::string& message,
HashAlgorithm hash_algorithm,
const std::string& signature) const {
if (message.empty()) {
LOG(ERROR) << "|message| cannot be empty";
return false;
}
if (signature.empty()) {
LOG(ERROR) << "|signature| cannot be empty";
return false;
}
// Hash the message using corresponding hash algorithm.
std::string message_digest = GetMessageDigest(message, hash_algorithm);
if (message_digest.empty()) {
LOG(ERROR) << "Empty message digest";
return false;
}
int result = ECDSA_verify(
0 /* unused type */,
reinterpret_cast<const uint8_t*>(message_digest.data()),
message_digest.size(),
reinterpret_cast<uint8_t*>(const_cast<char*>(signature.data())),
signature.size(), key());
if (result != 1) {
LOG(ERROR) << "Could not verify signature: "
<< OpenSSLErrorString(ERR_get_error());
return false;
}
return true;
}
bool ECPublicKey::MatchesPrivateKey(const ECPrivateKey& private_key) const {
return private_key.MatchesPublicKey(*this);
}

View File

@@ -16,7 +16,9 @@
#include <memory>
#include <string>
#include "absl/base/macros.h"
#include "openssl/ec.h"
#include "common/hash_algorithm.h"
#include "common/openssl_util.h"
namespace widevine {
@@ -65,9 +67,24 @@ class ECPrivateKey {
// DER-encoded signature.
// Caller retains ownership of all pointers.
// Returns true on success and false on error.
// TODO(b/155438325): remove this function after the below function is fully
// propagated.
ABSL_DEPRECATED(
"Use the below function with |hash_algorithm| argument instead.")
virtual bool GenerateSignature(const std::string& message,
std::string* signature) const;
// Given a message, calculates a signature using ECDSA with the key_.
// |message| is the message to be signed.
// |hash_algorithm| specifies the hash algorithm.
// |signature| will contain the resulting signature. This will be an ASN.1
// DER-encoded signature.
// Caller retains ownership of all pointers.
// Returns true on success and false on error.
virtual bool GenerateSignature(const std::string& message,
HashAlgorithm hash_algorithm,
std::string* signature) const;
// Returns whether the given private key is the same as key_.
virtual bool MatchesPrivateKey(const ECPrivateKey& private_key) const;
@@ -110,9 +127,23 @@ class ECPublicKey {
// |message| is the message that was signed.
// |signature| is an ASN.1 DER-encoded signature.
// Returns true on success and false on error.
// TODO(b/155438325): remove this function after the below function is fully
// propagated.
ABSL_DEPRECATED(
"Use the below function with |hash_algorithm| argument instead.")
virtual bool VerifySignature(const std::string& message,
const std::string& signature) const;
// Given a message and a signature, verifies that the signature was created
// using the private key associated with key_.
// |message| is the message that was signed.
// |hash_algorithm| specifies the hash algorithm.
// |signature| is an ASN.1 DER-encoded signature.
// Returns true on success and false on error.
virtual bool VerifySignature(const std::string& message,
HashAlgorithm hash_algorithm,
const std::string& signature) const;
// Returns whether the given private key is part of the same key pair as key_.
virtual bool MatchesPrivateKey(const ECPrivateKey& private_key) const;

View File

@@ -111,6 +111,10 @@ class ECKeyTestKeyPairs : public ECKeyTest,
std::unique_ptr<ECPublicKey> public_key_;
};
// Death test naming convention. See below link for details:
// go/gunitadvanced#death-test-naming
using ECKeyTestKeyPairsDeathTest = ECKeyTestKeyPairs;
TEST_P(ECKeyTestKeyPairs, CreateWrongKey) {
EXPECT_EQ(ECPrivateKey::Create(test_public_key_), nullptr);
EXPECT_EQ(ECPublicKey::Create(test_private_key_), nullptr);
@@ -165,6 +169,40 @@ TEST_P(ECKeyTestKeyPairs, SignVerify) {
EXPECT_TRUE(public_key_->VerifySignature(plaintext_message_, signature));
}
TEST_P(ECKeyTestKeyPairs, SignVerifySha1) {
std::string signature;
EXPECT_FALSE(private_key_->GenerateSignature(
plaintext_message_, HashAlgorithm::kSha1, &signature));
EXPECT_FALSE(public_key_->VerifySignature(plaintext_message_,
HashAlgorithm::kSha1, signature));
}
TEST_P(ECKeyTestKeyPairs, SignVerifySha256) {
std::string signature;
ASSERT_TRUE(private_key_->GenerateSignature(
plaintext_message_, HashAlgorithm::kSha256, &signature));
ASSERT_TRUE(public_key_->VerifySignature(plaintext_message_,
HashAlgorithm::kSha256, signature));
}
TEST_P(ECKeyTestKeyPairs, SignVerifyUnspecified) {
std::string signature;
ASSERT_TRUE(private_key_->GenerateSignature(
plaintext_message_, HashAlgorithm::kUnspecified, &signature));
ASSERT_TRUE(public_key_->VerifySignature(
plaintext_message_, HashAlgorithm::kUnspecified, signature));
}
TEST_P(ECKeyTestKeyPairsDeathTest, SignVerifyUnexpected) {
std::string signature;
HashAlgorithm unexpected_hash_algorithm = static_cast<HashAlgorithm>(1234);
EXPECT_DEATH(private_key_->GenerateSignature(
plaintext_message_, unexpected_hash_algorithm, &signature),
"Unexpected hash algorithm: 1234");
EXPECT_FALSE(public_key_->VerifySignature(
plaintext_message_, unexpected_hash_algorithm, signature));
}
TEST_P(ECKeyTestKeyPairs, InvalidSignVerifyParameters) {
std::string signature;
EXPECT_FALSE(private_key_->GenerateSignature("", &signature));
@@ -220,6 +258,9 @@ TEST_P(ECKeyTestKeyPairs, KeyPointEncodingSuccess) {
INSTANTIATE_TEST_SUITE_P(ECKeyTestKeyPairs, ECKeyTestKeyPairs,
::testing::ValuesIn(ECKeyTest::GetTestKeyList()));
INSTANTIATE_TEST_SUITE_P(ECKeyTestKeyPairsDeathTest, ECKeyTestKeyPairsDeathTest,
::testing::ValuesIn(ECKeyTest::GetTestKeyList()));
class ECKeyTestCurveMismatch
: public ECKeyTest,
public ::testing::WithParamInterface<

View File

@@ -200,9 +200,10 @@ TEST(EciesEncryptorTest, EciesEncryptNullKeySource) {
class MockEcKeySource : public ECKeySource {
public:
MockEcKeySource() = default;
MOCK_METHOD3(GetECKey,
bool(ECPrivateKey::EllipticCurve curve, std::string* private_key,
std::string* public_key));
MOCK_METHOD(bool, GetECKey,
(ECPrivateKey::EllipticCurve curve, std::string* private_key,
std::string* public_key),
(override));
};
TEST(EciesEncryptorTest, EciesEncryptKeysourceFail) {

View File

@@ -7,6 +7,7 @@
////////////////////////////////////////////////////////////////////////////////
#include "common/file_util.h"
#include "testing/gunit.h"
#include "absl/strings/str_cat.h"

18
common/hash_algorithm.h Normal file
View File

@@ -0,0 +1,18 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_HASH_ALGORITHM_H_
#define COMMON_HASH_ALGORITHM_H_
namespace widevine {
enum class HashAlgorithm { kUnspecified, kSha1, kSha256 };
} // namespace widevine
#endif // COMMON_HASH_ALGORITHM_H_

View File

@@ -0,0 +1,51 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 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/hash_algorithm_util.h"
#include "glog/logging.h"
#include "protos/public/hash_algorithm.pb.h"
namespace widevine {
HashAlgorithm HashAlgorithmProtoToEnum(
HashAlgorithmProto hash_algorithm_proto) {
switch (hash_algorithm_proto) {
case HASH_ALGORITHM_UNSPECIFIED:
return HashAlgorithm::kUnspecified;
case HASH_ALGORITHM_SHA_1:
return HashAlgorithm::kSha1;
case HASH_ALGORITHM_SHA_256:
return HashAlgorithm::kSha256;
default:
// See below link for using proto3 enum in switch statement:
// http://shortn/_ma9MY7V9wh
if (HashAlgorithmProto_IsValid(hash_algorithm_proto)) {
LOG(ERROR) << "Unsupported value " << hash_algorithm_proto;
} else {
LOG(WARNING) << "Unexpected value " << hash_algorithm_proto;
}
return HashAlgorithm::kUnspecified;
}
}
HashAlgorithmProto HashAlgorithmEnumToProto(HashAlgorithm hash_algorithm) {
switch (hash_algorithm) {
case HashAlgorithm::kUnspecified:
return HASH_ALGORITHM_UNSPECIFIED;
case HashAlgorithm::kSha1:
return HASH_ALGORITHM_SHA_1;
case HashAlgorithm::kSha256:
return HASH_ALGORITHM_SHA_256;
}
LOG(WARNING) << "Unexpected hash algorithm "
<< static_cast<int>(hash_algorithm);
return HASH_ALGORITHM_UNSPECIFIED;
}
} // namespace widevine

View File

@@ -0,0 +1,23 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_HASH_ALGORITHM_UTIL_H_
#define COMMON_HASH_ALGORITHM_UTIL_H_
#include "common/hash_algorithm.h"
#include "protos/public/hash_algorithm.pb.h"
namespace widevine {
HashAlgorithm HashAlgorithmProtoToEnum(HashAlgorithmProto hash_algorithm_proto);
HashAlgorithmProto HashAlgorithmEnumToProto(HashAlgorithm hash_algorithm);
} // namespace widevine
#endif // COMMON_HASH_ALGORITHM_UTIL_H_

View File

@@ -0,0 +1,58 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 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/hash_algorithm_util.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "common/hash_algorithm.h"
namespace widevine {
TEST(HashAlgorithmTest, ProtoToEnumUnspecified) {
EXPECT_EQ(HashAlgorithm::kUnspecified,
HashAlgorithmProtoToEnum(HASH_ALGORITHM_UNSPECIFIED));
}
TEST(HashAlgorithmTest, ProtoToEnumSha1) {
EXPECT_EQ(HashAlgorithm::kSha1,
HashAlgorithmProtoToEnum(HASH_ALGORITHM_SHA_1));
}
TEST(HashAlgorithmTest, ProtoToEnumSha256) {
EXPECT_EQ(HashAlgorithm::kSha256,
HashAlgorithmProtoToEnum(HASH_ALGORITHM_SHA_256));
}
TEST(HashAlgorithmTest, ProtoToEnumUnsupported) {
EXPECT_EQ(HashAlgorithm::kUnspecified,
HashAlgorithmProtoToEnum(static_cast<HashAlgorithmProto>(1234)));
}
TEST(HashAlgorithmTest, EnumToProtoUnspecified) {
EXPECT_EQ(HASH_ALGORITHM_UNSPECIFIED,
HashAlgorithmEnumToProto(HashAlgorithm::kUnspecified));
}
TEST(HashAlgorithmTest, EnumToProtoSha1) {
EXPECT_EQ(HASH_ALGORITHM_SHA_1,
HashAlgorithmEnumToProto(HashAlgorithm::kSha1));
}
TEST(HashAlgorithmTest, EnumToProtoSha256) {
EXPECT_EQ(HASH_ALGORITHM_SHA_256,
HashAlgorithmEnumToProto(HashAlgorithm::kSha256));
}
TEST(HashAlgorithmTest, EnumToProtoUnexpected) {
int some_value = 1234;
EXPECT_EQ(HASH_ALGORITHM_UNSPECIFIED,
HashAlgorithmEnumToProto(static_cast<HashAlgorithm>(some_value)));
}
} // namespace widevine

View File

@@ -33,9 +33,11 @@ Status KeyboxClientCert::Initialize(const std::string& keybox_token) {
return OkStatus();
}
// |hash_algorithm| is needed for function inheritance.
// For KeyBoxClientCert, we always use HMAC-SHA256 in signature verification.
Status KeyboxClientCert::VerifySignature(
const std::string& message, const std::string& signature,
ProtocolVersion protocol_version) const {
const std::string& message, HashAlgorithm hash_algorithm,
const std::string& signature, ProtocolVersion protocol_version) const {
DCHECK(!signing_key_.empty());
using crypto_util::VerifySignatureHmacSha256;
if (!VerifySignatureHmacSha256(

View File

@@ -10,10 +10,12 @@
#define COMMON_KEYBOX_CLIENT_CERT_H_
#include "common/client_cert.h"
#include "common/error_space.h"
#include "common/hash_algorithm.h"
#include "protos/public/errors.pb.h"
namespace widevine {
//
class KeyboxClientCert : public ClientCert {
public:
KeyboxClientCert() {}
@@ -23,6 +25,7 @@ class KeyboxClientCert : public ClientCert {
Status Initialize(const std::string& keybox_token);
Status VerifySignature(const std::string& message,
HashAlgorithm hash_algorithm,
const std::string& signature,
ProtocolVersion protocol_version) const override;
@@ -34,6 +37,7 @@ class KeyboxClientCert : public ClientCert {
SignedMessage::SessionKeyType key_type() const override {
return SignedMessage::WRAPPED_AES_KEY;
}
bool using_dual_certificate() const override { return false; }
const std::string& serial_number() const override { return serial_number_; }
const std::string& service_id() const override { return unimplemented_; }
const std::string& signing_key() const override { return signing_key_; }
@@ -59,6 +63,14 @@ class KeyboxClientCert : public ClientCert {
const std::multimap<uint32_t, std::string>& keymap);
static bool IsSystemIdKnown(const uint32_t system_id);
static uint32_t GetSystemId(const std::string& keybox_bytes);
Status SystemIdUnknownError() const override {
return Status(error_space, UNSUPPORTED_SYSTEM_ID,
"keybox-unsupported-system-id");
}
Status SystemIdRevokedError() const override {
return Status(error_space, DRM_DEVICE_CERTIFICATE_REVOKED,
"keybox-system-id-revoked");
}
private:
std::string unimplemented_;

View File

@@ -10,7 +10,9 @@
#define COMMON_MOCK_RSA_KEY_H_
#include <string>
#include "testing/gmock.h"
#include "common/hash_algorithm.h"
#include "common/rsa_key.h"
namespace widevine {
@@ -20,12 +22,23 @@ class MockRsaPrivateKey : public RsaPrivateKey {
MockRsaPrivateKey() : RsaPrivateKey(RSA_new()) {}
~MockRsaPrivateKey() override {}
MOCK_CONST_METHOD2(Decrypt, bool(const std::string& encrypted_message,
std::string* decrypted_message));
MOCK_CONST_METHOD2(GenerateSignature,
bool(const std::string& message, std::string* signature));
MOCK_CONST_METHOD1(MatchesPrivateKey, bool(const RsaPrivateKey& private_key));
MOCK_CONST_METHOD1(MatchesPublicKey, bool(const RsaPublicKey& public_key));
MOCK_METHOD(bool, Decrypt,
(const std::string& encrypted_message,
std::string* decrypted_message),
(const, override));
// TODO(b/155438325): remove this function after the below function is fully
// propagated.
MOCK_METHOD(bool, GenerateSignature,
(const std::string& message, std::string* signature),
(const, override));
MOCK_METHOD(bool, GenerateSignature,
(const std::string& message, HashAlgorithm hash_algorithm,
std::string* signature),
(const, override));
MOCK_METHOD(bool, MatchesPrivateKey, (const RsaPrivateKey& private_key),
(const, override));
MOCK_METHOD(bool, MatchesPublicKey, (const RsaPublicKey& public_key),
(const, override));
private:
MockRsaPrivateKey(const MockRsaPrivateKey&) = delete;
@@ -37,12 +50,23 @@ class MockRsaPublicKey : public RsaPublicKey {
MockRsaPublicKey() : RsaPublicKey(RSA_new()) {}
~MockRsaPublicKey() override {}
MOCK_CONST_METHOD2(Encrypt, bool(const std::string& clear_message,
std::string* encrypted_message));
MOCK_CONST_METHOD2(VerifySignature, bool(const std::string& message,
const std::string& signature));
MOCK_CONST_METHOD1(MatchesPrivateKey, bool(const RsaPrivateKey& private_key));
MOCK_CONST_METHOD1(MatchesPublicKey, bool(const RsaPublicKey& public_key));
MOCK_METHOD(bool, Encrypt,
(const std::string& clear_message,
std::string* encrypted_message),
(const, override));
// TODO(b/155438325): remove this function after the below function is fully
// propagated.
MOCK_METHOD(bool, VerifySignature,
(const std::string& message, const std::string& signature),
(const, override));
MOCK_METHOD(bool, VerifySignature,
(const std::string& message, HashAlgorithm hash_algorithm,
const std::string& signature),
(const, override));
MOCK_METHOD(bool, MatchesPrivateKey, (const RsaPrivateKey& private_key),
(const, override));
MOCK_METHOD(bool, MatchesPublicKey, (const RsaPublicKey& public_key),
(const, override));
private:
MockRsaPublicKey(const MockRsaPublicKey&) = delete;
@@ -54,16 +78,14 @@ class MockRsaKeyFactory : public RsaKeyFactory {
MockRsaKeyFactory() {}
~MockRsaKeyFactory() override {}
MOCK_CONST_METHOD1(
CreateFromPkcs1PrivateKey,
std::unique_ptr<RsaPrivateKey>(const std::string& private_key));
MOCK_CONST_METHOD2(CreateFromPkcs8PrivateKey,
std::unique_ptr<RsaPrivateKey>(
const std::string& private_key,
const std::string& private_key_passphrase));
MOCK_CONST_METHOD1(
CreateFromPkcs1PublicKey,
std::unique_ptr<RsaPublicKey>(const std::string& public_key));
MOCK_METHOD(std::unique_ptr<RsaPrivateKey>, CreateFromPkcs1PrivateKey,
(const std::string& private_key), (const, override));
MOCK_METHOD(std::unique_ptr<RsaPrivateKey>, CreateFromPkcs8PrivateKey,
(const std::string& private_key,
const std::string& private_key_passphrase),
(const, override));
MOCK_METHOD(std::unique_ptr<RsaPublicKey>, CreateFromPkcs1PublicKey,
(const std::string& public_key), (const, override));
private:
MockRsaKeyFactory(const MockRsaKeyFactory&) = delete;

View File

@@ -0,0 +1,42 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_PLAYREADY_INTERFACE_H_
#define COMMON_PLAYREADY_INTERFACE_H_
#include <string>
#include "util/error_space.h"
#include "protos/public/license_protocol.pb.h"
namespace widevine {
class PlayReadyInterface {
public:
PlayReadyInterface() {}
virtual ~PlayReadyInterface() {}
// Sends to a PlayReady Service running the PlayReady license server on
// Windows .
// Args:
// - |challenge| is a std::string which contains PlayReadyLicenseRequest.
// - |policy| is a std::string which contains the PlayReady Policy Setting.
// - |license| is a std::string of PlayReadyLicenseResponse returned from PlayReady
// Service.
// Returns:
// - status code from downstream components.
virtual util::Status SendToPlayReady(
const std::string& playready_challenge, const std::string& provider,
const std::string& content_id,
const std::list<License::KeyContainer>& keys,
const License::Policy& policy, std::string* playready_license) = 0;
};
} // namespace widevine
#endif // COMMON_PLAYREADY_INTERFACE_H_

View File

@@ -0,0 +1,23 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 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/playready_sdk_impl.h"
#include "absl/status/status.h"
#include "absl/strings/escaping.h"
#include "util/task/codes.pb.h"
namespace widevine {
// TODO(user): fill in SendToPlayReady function.
util::Status PlayReadySdkImpl::SendToPlayReady(
const std::string& playready_challenge, const std::string& provider,
const std::string& content_id, const std::list<License::KeyContainer>& keys,
const License::Policy& policy, std::string* playready_license) {
return OkStatus;
}
} // namespace widevine

View File

@@ -0,0 +1,28 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_PLAYREADY_SDK_IMPL_H_
#define COMMON_PLAYREADY_SDK_IMPL_H_
#include "common/playready_interface.h"
#include "protos/public/license_protocol.pb.h"
namespace widevine {
class PlayReadySdkImpl : public PlayReadyInterface {
public:
PlayReadySdkImpl() : PlayReadyInterface() {}
~PlayReadySdkImpl() override {}
util::Status SendToPlayReady(const std::string& playready_challenge,
const std::string& provider,
const std::string& content_id,
const std::list<License::KeyContainer>& keys,
const License::Policy& policy,
std::string* playready_license) override;
};
} // namespace widevine
#endif // COMMON_PLAYREADY_SDK_IMPL_H_

View File

@@ -16,7 +16,7 @@
#include <memory>
#include <string>
#include "base/thread_annotations.h"
#include "absl/base/thread_annotations.h"
#include "absl/synchronization/mutex.h"
#include "common/status.h"
#include "common/x509_cert.h"

View File

@@ -15,6 +15,7 @@
#include <memory>
#include "glog/logging.h"
#include "absl/strings/escaping.h"
#include "absl/strings/str_cat.h"
#include "common/crypto_util.h"
#include "common/ec_key.h"
@@ -77,11 +78,7 @@ Status RootOfTrustIdGenerator::Generate(uint32_t system_id,
std::string RootOfTrustIdGenerator::GenerateUniqueIdHash(
const std::string& unique_id) const {
if (unique_id.empty()) {
LOG(WARNING) << "unique_id should not be empty.";
return "";
}
return Sha256_Hash(absl::StrCat(unique_id, wv_shared_salt_));
return widevine::GenerateUniqueIdHash(unique_id, wv_shared_salt_);
}
Status RootOfTrustIdDecryptor::DecryptUniqueId(
@@ -104,4 +101,30 @@ Status RootOfTrustIdDecryptor::DecryptUniqueId(
return OkStatus();
}
Status RootOfTrustIdDecryptor::VerifyAndExtractAllValues(
uint32_t system_id, const RootOfTrustId& root_of_trust_id,
std::string* device_unique_id, std::string* device_unique_id_hash) const {
CHECK(device_unique_id != nullptr) << "device_unique_id was null.";
CHECK(device_unique_id_hash != nullptr) << "device_unique_id_hash was null.";
Status status = DecryptUniqueId(
system_id, root_of_trust_id.encrypted_unique_id(), device_unique_id);
if (!status.ok()) {
return status;
}
*device_unique_id_hash =
widevine::GenerateUniqueIdHash(*device_unique_id, wv_shared_salt_);
std::string revocation_hash =
GenerateRotIdHash(root_of_trust_id.encrypted_unique_id(), system_id,
*device_unique_id_hash);
// This should not happen unless there's a bug in the way we issue root of
// trust ids.
if (revocation_hash != root_of_trust_id.unique_id_hash()) {
return Status(error::INVALID_ARGUMENT,
"The generated revocation hash did not match the one in the "
"root_of_trust_id");
}
return OkStatus();
}
} // namespace widevine

View File

@@ -38,7 +38,7 @@ class RootOfTrustIdGenerator {
// values. The unique id hash values identify revoked devices and are
// published in the DCSL and consumed by the License SDK.
RootOfTrustIdGenerator(std::unique_ptr<EciesEncryptor> ecies_encryptor,
std::string wv_shared_salt)
const std::string& wv_shared_salt)
: ecies_encryptor_(std::move(ecies_encryptor)),
wv_shared_salt_(std::move(wv_shared_salt)) {}
@@ -73,8 +73,10 @@ class RootOfTrustIdGenerator {
class RootOfTrustIdDecryptor {
public:
explicit RootOfTrustIdDecryptor(
std::unique_ptr<EciesDecryptor> ecies_decryptor)
: ecies_decryptor_(std::move(ecies_decryptor)) {}
std::unique_ptr<EciesDecryptor> ecies_decryptor,
const std::string& wv_shared_salt)
: ecies_decryptor_(std::move(ecies_decryptor)),
wv_shared_salt_(wv_shared_salt) {}
// Decrypts the |rot_encrypted_id| using the |system_id| as part of the
// context. |unique_id| contains the decrypted value on success.
@@ -83,8 +85,18 @@ class RootOfTrustIdDecryptor {
Status DecryptUniqueId(uint32_t system_id, const std::string& rot_encrypted_id,
std::string* unique_id) const;
// Decrypts the encrypted id within the |root_of_trust_id|, extacting the
// |device_unique_id|, and generating the |device_unique_id_hash|. It then
// generates the rot id revocation hash and verifies that it matches the
// unique_id_hash from the root_of_trust_id.
Status VerifyAndExtractAllValues(uint32_t system_id,
const RootOfTrustId& root_of_trust_id,
std::string* device_unique_id,
std::string* device_unique_id_hash) const;
private:
std::unique_ptr<EciesDecryptor> ecies_decryptor_;
std::string wv_shared_salt_;
};
} // namespace widevine

View File

@@ -80,8 +80,9 @@ class MockEciesEncryptor : public EciesEncryptor {
ECPublicKey::Create(test_keys.public_test_key_1_secp256r1());
return new MockEciesEncryptor(std::move(ec_key));
}
MOCK_CONST_METHOD3(Encrypt, bool(const std::string&, const std::string&,
std::string*));
MOCK_METHOD(bool, Encrypt,
(const std::string&, const std::string&, std::string*),
(const, override));
private:
explicit MockEciesEncryptor(std::unique_ptr<ECPublicKey> ec_key)
@@ -92,7 +93,7 @@ class MockEciesEncryptor : public EciesEncryptor {
TEST_F(RootOfTrustIdGeneratorTest, GenerateIdSuccess) {
RootOfTrustIdGenerator generator(CreateEncryptor(), kTestSharedSalt);
RootOfTrustIdDecryptor decryptor(CreateDecryptor());
RootOfTrustIdDecryptor decryptor(CreateDecryptor(), kTestSharedSalt);
// Generate the root of trust id.
RootOfTrustId root_of_trust_id;
@@ -117,7 +118,7 @@ TEST_F(RootOfTrustIdGeneratorTest, GenerateIdSuccess) {
TEST_F(RootOfTrustIdGeneratorTest, GenerateIdUniqueSuccess) {
RootOfTrustIdGenerator generator(CreateEncryptor(), kTestSharedSalt);
RootOfTrustIdDecryptor decryptor(CreateDecryptor());
RootOfTrustIdDecryptor decryptor(CreateDecryptor(), kTestSharedSalt);
std::string rot_encrypted_id;
std::string rot_id_hash;
@@ -208,7 +209,7 @@ TEST_F(RootOfTrustIdGeneratorTest, GenerateIdNullRotIdFail) {
TEST_F(RootOfTrustIdGeneratorTest, DecryptorSystemIdMismatchFails) {
RootOfTrustIdGenerator generator(CreateEncryptor(), kTestSharedSalt);
RootOfTrustIdDecryptor decryptor(CreateDecryptor());
RootOfTrustIdDecryptor decryptor(CreateDecryptor(), kTestSharedSalt);
// Generate the root of trust id.
RootOfTrustId root_of_trust_id;
@@ -228,7 +229,7 @@ TEST_F(RootOfTrustIdGeneratorTest, DecryptorSystemIdMismatchFails) {
}
TEST_F(RootOfTrustIdGeneratorTest, DecryptorBlankUniqueId) {
RootOfTrustIdDecryptor decryptor(CreateDecryptor());
RootOfTrustIdDecryptor decryptor(CreateDecryptor(), kTestSharedSalt);
// Attempt to decrypt empty encrypted id.
std::string decrypted_unique_id;
@@ -239,7 +240,7 @@ TEST_F(RootOfTrustIdGeneratorTest, DecryptorBlankUniqueId) {
TEST_F(RootOfTrustIdGeneratorTest, DecryptorSystemIdNullDecryptedIdFails) {
RootOfTrustIdGenerator generator(CreateEncryptor(), kTestSharedSalt);
RootOfTrustIdDecryptor decryptor(CreateDecryptor());
RootOfTrustIdDecryptor decryptor(CreateDecryptor(), kTestSharedSalt);
// Generate the root of trust id.
RootOfTrustId root_of_trust_id;
@@ -256,4 +257,48 @@ TEST_F(RootOfTrustIdGeneratorTest, DecryptorSystemIdNullDecryptedIdFails) {
"unique_id");
}
TEST_F(RootOfTrustIdGeneratorTest, VerifyAndExtractAllValuesSuccess) {
RootOfTrustIdGenerator generator(CreateEncryptor(), kTestSharedSalt);
RootOfTrustIdDecryptor decryptor(CreateDecryptor(), kTestSharedSalt);
// Generate the root of trust id.
RootOfTrustId root_of_trust_id;
ASSERT_OK(
generator.Generate(kTestSystemId, kTestUniqueId, &root_of_trust_id));
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(
expected_root_of_trust_id_, root_of_trust_id));
// Verify decrypted unique id.
std::string decrypted_unique_id;
std::string decrypted_unique_id_hash;
EXPECT_OK(decryptor.VerifyAndExtractAllValues(kTestSystemId, root_of_trust_id,
&decrypted_unique_id,
&decrypted_unique_id_hash));
EXPECT_EQ(kTestUniqueId, decrypted_unique_id);
EXPECT_EQ(generator.GenerateUniqueIdHash(kTestUniqueId),
decrypted_unique_id_hash);
}
TEST_F(RootOfTrustIdGeneratorTest, VerifyAndExtractAllValuesSystemIdMismatch) {
RootOfTrustIdGenerator generator(CreateEncryptor(), kTestSharedSalt);
RootOfTrustIdDecryptor decryptor(CreateDecryptor(), kTestSharedSalt);
// Generate the root of trust id.
RootOfTrustId root_of_trust_id;
ASSERT_OK(
generator.Generate(kTestSystemId, kTestUniqueId, &root_of_trust_id));
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(
expected_root_of_trust_id_, root_of_trust_id));
// Verify decrypted unique id.
std::string decrypted_unique_id;
std::string decrypted_unique_id_hash;
EXPECT_EQ(error::INTERNAL,
decryptor
.VerifyAndExtractAllValues(kTestSystemId + 1, root_of_trust_id,
&decrypted_unique_id,
&decrypted_unique_id_hash)
.error_code());
}
} // namespace widevine

View File

@@ -29,4 +29,17 @@ std::string GenerateRotIdHash(const std::string& salt, uint32_t system_id,
return Sha256_Hash(absl::StrCat(salt, system_id, unique_id_hash));
}
std::string GenerateUniqueIdHash(const std::string& unique_id,
const std::string& salt) {
if (unique_id.empty()) {
LOG(WARNING) << "unique_id should not be empty.";
return "";
}
if (salt.empty()) {
LOG(WARNING) << "salt should not be empty.";
return "";
}
return widevine::Sha256_Hash(absl::StrCat(unique_id, salt));
}
} // namespace widevine

View File

@@ -21,6 +21,14 @@
namespace widevine {
// Helper function that generates the unique id hash from the |unique_id| and
// the |salt|. |salt| is an internal secret.
//
// Returns the hash value on success.
// If |salt| or |unique_id| are empty, this will return an empty string.
std::string GenerateUniqueIdHash(const std::string& unique_id,
const std::string& salt);
// Helper function that generates the hash for the ROT id from the
// |unique_id_hash|, the |system_id| and the |salt|. |salt| is typically an
// encrypted unique id. Since we use an ephemeral eliptic curve key as part of

View File

@@ -19,9 +19,15 @@ namespace {
constexpr char kFakeEncryptedId[] = "fake encrypted id";
constexpr char kFakeUniqueIdHash[] = "fake unique_id hash";
constexpr char kFakeUniqueId[] = "fake unique_id";
constexpr char kFakeSecretSalt[] = "fake secret salt";
// This is the ROT ID Hash generated from the fake values.
constexpr char kRotIdHashHex[] =
"0a757dde0f1080b60f34bf8e46af573ce987b5ed1c831b44952e2feed5243a95";
// This is the unique id hash generated from the fake unique id value.
constexpr char kUniqueIdHashHex[] =
"da20922e84b48e52223496f44b07632a4db19d488cd71cf813de300b9d244e06";
constexpr uint32_t kFakeSystemId = 1234;
constexpr uint32_t kOtherFakeSystemId = 9876;
@@ -63,4 +69,17 @@ TEST(RotIdUtilTest, GenerateRotIdHashSuccess) {
GenerateRotIdHash(kFakeEncryptedId, kFakeSystemId, kFakeUniqueIdHash));
}
// This test really only ensures the stability of the GenerateUniqueIdHash
// implementation. If the hash ever changes, then it will introduce problems
// into the ecosystem.
TEST(RotIdUtilTest, GenerateUniqueIdHashSuccess) {
ASSERT_EQ(absl::HexStringToBytes(kUniqueIdHashHex),
GenerateUniqueIdHash(kFakeUniqueId, kFakeSecretSalt));
}
TEST(RotIdUtilTest, GenerateUniqueIdHashEmptyValues) {
ASSERT_EQ("", GenerateUniqueIdHash(kFakeUniqueId, ""));
ASSERT_EQ("", GenerateUniqueIdHash("", kFakeSecretSalt));
}
} // namespace widevine

View File

@@ -13,7 +13,7 @@
//
// RSA signature details:
// Algorithm: RSASSA-PSS
// Hash algorithm: SHA1
// Hash algorithm: |hash_algorithm|
// Mask generation function: mgf1SHA1
// Salt length: 20 bytes
// Trailer field: 0xbc
@@ -21,7 +21,7 @@
// RSA encryption details:
// Algorithm: RSA-OAEP
// Mask generation function: mgf1SHA1
// Label (encoding paramter): empty std::string
// Label (encoding parameter): empty std::string
#include "common/rsa_key.h"
@@ -31,6 +31,7 @@
#include "openssl/evp.h"
#include "openssl/rsa.h"
#include "openssl/sha.h"
#include "common/hash_algorithm.h"
#include "common/rsa_util.h"
#include "common/sha_util.h"
@@ -51,6 +52,21 @@ std::string OpenSSLErrorString(uint32_t error) {
return buf;
}
std::string GetMessageDigest(const std::string& message,
widevine::HashAlgorithm hash_algorithm) {
switch (hash_algorithm) {
// The default hash algorithm of RSA signature is SHA1.
case widevine::HashAlgorithm::kUnspecified:
case widevine::HashAlgorithm::kSha1:
return widevine::Sha1_Hash(message);
case widevine::HashAlgorithm::kSha256:
return widevine::Sha256_Hash(message);
}
LOG(FATAL) << "Unexpected hash algorithm: "
<< static_cast<int>(hash_algorithm);
return "";
}
} // namespace
namespace widevine {
@@ -137,6 +153,47 @@ bool RsaPrivateKey::GenerateSignature(const std::string& message,
return true;
}
bool RsaPrivateKey::GenerateSignature(const std::string& message,
HashAlgorithm hash_algorithm,
std::string* signature) const {
DCHECK(signature);
if (message.empty()) {
LOG(ERROR) << "Message to be signed is empty";
return false;
}
// Hash the message using corresponding hash algorithm.
std::string message_digest = GetMessageDigest(message, hash_algorithm);
if (message_digest.empty()) {
LOG(ERROR) << "Empty message digest";
return false;
}
// Add PSS padding.
size_t rsa_size = RSA_size(key_);
std::string padded_digest(rsa_size, 0);
if (!RSA_padding_add_PKCS1_PSS_mgf1(
key_, reinterpret_cast<unsigned char*>(&padded_digest[0]),
reinterpret_cast<unsigned char*>(&message_digest[0]), EVP_sha1(),
EVP_sha1(), kPssSaltLength)) {
LOG(ERROR) << "RSA padding failure: "
<< OpenSSLErrorString(ERR_get_error());
return false;
}
// Encrypt PSS padded digest.
signature->assign(rsa_size, 0);
if (RSA_private_encrypt(padded_digest.size(),
reinterpret_cast<unsigned char*>(&padded_digest[0]),
reinterpret_cast<unsigned char*>(&(*signature)[0]),
key_, RSA_NO_PADDING) !=
static_cast<int>(signature->size())) {
LOG(ERROR) << "RSA private encrypt failure: "
<< OpenSSLErrorString(ERR_get_error());
return false;
}
return true;
}
bool RsaPrivateKey::GenerateSignatureSha256Pkcs7(const std::string& message,
std::string* signature) const {
DCHECK(signature);
@@ -253,6 +310,52 @@ bool RsaPublicKey::VerifySignature(const std::string& message,
return true;
}
bool RsaPublicKey::VerifySignature(const std::string& message,
HashAlgorithm hash_algorithm,
const std::string& signature) const {
if (message.empty()) {
LOG(ERROR) << "Signed message is empty";
return false;
}
size_t rsa_size = RSA_size(key_);
if (signature.size() != rsa_size) {
LOG(ERROR) << "Message signature is of the wrong size (expected "
<< rsa_size << ", actual " << signature.size() << ")";
return false;
}
// Decrypt the signature.
std::string padded_digest(signature.size(), 0);
if (RSA_public_decrypt(
signature.size(),
const_cast<unsigned char*>(
reinterpret_cast<const unsigned char*>(signature.data())),
reinterpret_cast<unsigned char*>(&padded_digest[0]), key_,
RSA_NO_PADDING) != static_cast<int>(rsa_size)) {
LOG(ERROR) << "RSA public decrypt failure: "
<< OpenSSLErrorString(ERR_get_error());
return false;
}
// Hash the message using SHA1 using corresponding hash algorithm.
std::string message_digest = GetMessageDigest(message, hash_algorithm);
if (message_digest.empty()) {
LOG(ERROR) << "Empty message digest";
return false;
}
// Verify PSS padding.
if (RSA_verify_PKCS1_PSS_mgf1(
key_, reinterpret_cast<unsigned char*>(&message_digest[0]),
EVP_sha1(), EVP_sha1(),
reinterpret_cast<unsigned char*>(&padded_digest[0]),
kPssSaltLength) == 0) {
LOG(ERROR) << "RSA Verify PSS padding failure: "
<< OpenSSLErrorString(ERR_get_error());
return false;
}
return true;
}
bool RsaPublicKey::VerifySignatureSha256Pkcs7(
const std::string& message, const std::string& signature) const {
if (message.empty()) {

View File

@@ -18,7 +18,9 @@
#include <string>
#include <cstdint>
#include "absl/base/macros.h"
#include "openssl/rsa.h"
#include "common/hash_algorithm.h"
namespace widevine {
@@ -41,9 +43,20 @@ class RsaPrivateKey {
// Generate RSSASSA-PSS signature. Caller retains ownership of all parameters.
// Returns true if successful, false otherwise.
// TODO(b/155438325): remove this function after the below function is fully
// propagated.
ABSL_DEPRECATED(
"Use the below function with |hash_algorithm| argument instead.")
virtual bool GenerateSignature(const std::string& message,
std::string* signature) const;
// Generate RSSASSA-PSS signature. Caller retains ownership of all parameters.
// |hash_algorithm| indicates the hash algorithm used. Returns true if
// successful, false otherwise.
virtual bool GenerateSignature(const std::string& message,
HashAlgorithm hash_algorithm,
std::string* signature) const;
// Generate SHA256 digest, PKCS#7 padded signature. Caller retains ownership
// of all parameters. Returns true if successful, false otherwise.
virtual bool GenerateSignatureSha256Pkcs7(const std::string& message,
@@ -98,9 +111,20 @@ class RsaPublicKey {
// Verify RSSASSA-PSS signature. Caller retains ownership of all parameters.
// Returns true if validation succeeds, false otherwise.
// TODO(b/155438325): remove this function after the below function is fully
// propagated.
ABSL_DEPRECATED(
"Use the below function with |hash_algorithm| argument instead.")
virtual bool VerifySignature(const std::string& message,
const std::string& signature) const;
// Verify RSSASSA-PSS signature. Caller retains ownership of all parameters.
// |hash_algorithm| indicates the hash algorithm used. Returns true if
// validation succeeds, false otherwise.
virtual bool VerifySignature(const std::string& message,
HashAlgorithm hash_algorithm,
const std::string& signature) const;
// Verify a signature. This method takes two parameters: |message| which is a
// std::string containing the data which was signed, and |signature| which is a
// std::string containing the message SHA256 digest signature with PKCS#7

View File

@@ -10,10 +10,11 @@
// Description:
// Unit test for rsa_key RSA encryption and signing.
#include "common/rsa_key.h"
#include <memory>
#include "testing/gunit.h"
#include "common/rsa_key.h"
#include "common/rsa_test_keys.h"
#include "common/rsa_util.h"
@@ -46,8 +47,7 @@ TEST_F(RsaKeyTest, CopyConstructor) {
std::unique_ptr<RsaPrivateKey> private_key_copy(
new RsaPrivateKey(*private_key));
std::unique_ptr<RsaPublicKey> public_key_copy(
new RsaPublicKey(*public_key));
std::unique_ptr<RsaPublicKey> public_key_copy(new RsaPublicKey(*public_key));
EXPECT_TRUE(public_key_copy->MatchesPublicKey(*public_key));
EXPECT_TRUE(public_key_copy->MatchesPrivateKey(*private_key));

View File

@@ -11,8 +11,12 @@
#include <vector>
#include "glog/logging.h"
#include "google/protobuf/text_format.h"
#include "common/client_id_util.h"
#include "common/device_status_list.h"
#include "protos/public/client_identification.pb.h"
#include "protos/public/device_certificate_status.pb.h"
#include "protos/public/device_common.pb.h"
#include "protos/public/provisioned_device_info.pb.h"
#include "protos/public/security_profile.pb.h"
@@ -23,98 +27,44 @@ using ClientCapabilities = ClientIdentification::ClientCapabilities;
SecurityProfileList::SecurityProfileList(const std::string& profile_namespace)
: profile_namespace_(profile_namespace) {}
int SecurityProfileList::Init() { return AddDefaultProfiles(); }
int SecurityProfileList::Init() { return 0; }
int SecurityProfileList::AddDefaultProfiles() {
const uint32_t oemcrypto_8 = 8;
const uint32_t oemcrypto_12 = 12;
const bool make_model_not_verified = false;
SecurityProfile profile;
PopulateProfile(SecurityProfile::SECURITY_PROFILE_LEVEL_1, "WVSP1",
ClientCapabilities::HDCP_NONE,
ClientCapabilities::ANALOG_OUTPUT_UNKNOWN, oemcrypto_8,
make_model_not_verified, ProvisionedDeviceInfo::LEVEL_3,
kResourceTierLow, &profile);
InsertProfile(profile);
PopulateProfile(SecurityProfile::SECURITY_PROFILE_LEVEL_2, "WVSP2",
ClientCapabilities::HDCP_NONE,
ClientCapabilities::ANALOG_OUTPUT_SUPPORTS_CGMS_A,
oemcrypto_12, make_model_not_verified,
ProvisionedDeviceInfo::LEVEL_2, kResourceTierLow, &profile);
InsertProfile(profile);
PopulateProfile(SecurityProfile::SECURITY_PROFILE_LEVEL_3, "WVSP3",
ClientCapabilities::HDCP_V1,
ClientCapabilities::ANALOG_OUTPUT_SUPPORTS_CGMS_A,
oemcrypto_12, make_model_not_verified,
ProvisionedDeviceInfo::LEVEL_1, kResourceTierMed, &profile);
InsertProfile(profile);
PopulateProfile(SecurityProfile::SECURITY_PROFILE_LEVEL_4, "WVSP4",
ClientCapabilities::HDCP_V2_2,
ClientCapabilities::ANALOG_OUTPUT_SUPPORTS_CGMS_A,
oemcrypto_12, make_model_not_verified,
ProvisionedDeviceInfo::LEVEL_1, kResourceTierHigh, &profile);
InsertProfile(profile);
absl::ReaderMutexLock lock(&mutex_);
return security_profiles_.size();
}
SecurityProfile::Level SecurityProfileList::GetBestProfileLevel(
const ClientIdentification& client_id,
const ProvisionedDeviceInfo& device_info,
SecurityProfile::DrmInfo* drm_info) const {
// Iterate through each SP starting from the strictest first.
absl::ReaderMutexLock lock(&mutex_);
// Profile list is assumed to be sorted.
for (auto& profile : security_profiles_) {
if (!IsProfileAllowed(profile, client_id, device_info)) {
continue;
}
if (drm_info != nullptr) {
GetDrmInfo(client_id, device_info, drm_info);
}
return profile.level();
}
return SecurityProfile::SECURITY_PROFILE_LEVEL_UNDEFINED;
}
int SecurityProfileList::GetAllowedProfilesFromList(
int SecurityProfileList::GetQualifiedProfilesFromSpecifiedProfiles(
const std::vector<std::string>& profiles_to_check,
const ClientIdentification& client_id,
const ProvisionedDeviceInfo& device_info,
std::vector<std::string>* profiles_to_allow) const {
if (profiles_to_allow == nullptr) {
std::vector<std::string>* qualified_profiles) const {
if (qualified_profiles == nullptr) {
return 0;
}
qualified_profiles->clear();
absl::ReaderMutexLock lock(&mutex_);
for (auto& profile_name : profiles_to_check) {
SecurityProfile profile;
if (GetProfileByName(profile_name, &profile)) {
if (IsProfileAllowed(profile, client_id, device_info)) {
profiles_to_allow->push_back(profile.name());
if (DoesProfileQualify(profile, client_id, device_info)) {
qualified_profiles->push_back(profile.name());
}
}
}
return profiles_to_allow->size();
return qualified_profiles->size();
}
int SecurityProfileList::GetAllowedProfiles(
int SecurityProfileList::GetQualifiedProfiles(
const ClientIdentification& client_id,
const ProvisionedDeviceInfo& device_info,
std::vector<std::string>* profiles_to_allow) const {
if (profiles_to_allow == nullptr) {
std::vector<std::string>* qualified_profiles) const {
if (qualified_profiles == nullptr) {
return 0;
}
qualified_profiles->clear();
absl::ReaderMutexLock lock(&mutex_);
for (auto& profile : security_profiles_) {
if (IsProfileAllowed(profile, client_id, device_info)) {
profiles_to_allow->push_back(profile.name());
if (DoesProfileQualify(profile, client_id, device_info)) {
qualified_profiles->push_back(profile.name());
}
}
return profiles_to_allow->size();
return qualified_profiles->size();
}
bool SecurityProfileList::GetDrmInfo(const ClientIdentification& client_id,
@@ -127,62 +77,65 @@ bool SecurityProfileList::GetDrmInfo(const ClientIdentification& client_id,
client_id.client_capabilities().max_hdcp_version());
drm_info->mutable_output()->set_analog_output_capabilities(
client_id.client_capabilities().analog_output_capabilities());
drm_info->mutable_security()->set_oemcrypto_version(
drm_info->mutable_security()->set_oemcrypto_api_version(
client_id.client_capabilities().oem_crypto_api_version());
drm_info->mutable_security()->set_resource_rating_tier(
client_id.client_capabilities().resource_rating_tier());
drm_info->mutable_security()->set_security_level(
device_info.security_level());
drm_info->mutable_security()->set_request_model_info_status(false);
drm_info->mutable_request_model_info()->set_manufacturer(
GetClientInfo(client_id, kModDrmMake));
drm_info->mutable_request_model_info()->set_model_name(
GetClientInfo(client_id, kModDrmModel));
drm_info->set_system_id(device_info.system_id());
return true;
}
bool SecurityProfileList::PopulateProfile(
const SecurityProfile::Level profile_level, const std::string& profile_name,
const ClientCapabilities::HdcpVersion min_hdcp_version,
const ClientCapabilities::AnalogOutputCapabilities
analog_output_capabilities,
const uint32_t min_oemcrypto_version, const bool make_model_verified,
const ProvisionedDeviceInfo::WvSecurityLevel security_level,
const uint32_t resource_rating_tier,
SecurityProfile* profile_to_create) const {
if (profile_to_create == nullptr) {
return false;
}
profile_to_create->set_level(profile_level);
profile_to_create->set_name(profile_name);
profile_to_create->mutable_min_output_requirements()->set_hdcp_version(
min_hdcp_version);
profile_to_create->mutable_min_output_requirements()
->set_analog_output_capabilities(analog_output_capabilities);
profile_to_create->mutable_min_security_requirements()->set_oemcrypto_version(
min_oemcrypto_version);
profile_to_create->mutable_min_security_requirements()->set_security_level(
security_level);
profile_to_create->mutable_min_security_requirements()
->set_resource_rating_tier(resource_rating_tier);
profile_to_create->mutable_min_security_requirements()
->set_request_model_info_status(make_model_verified);
return true;
}
bool SecurityProfileList::GetProfileByLevel(
SecurityProfile::Level level, SecurityProfile* security_profile) const {
absl::ReaderMutexLock lock(&mutex_);
for (auto& profile : security_profiles_) {
if (profile.level() == level) {
if (security_profile != nullptr) {
*security_profile = profile;
}
return true;
drm_info->mutable_request_model_info()->set_status(
DeviceModel::MODEL_STATUS_UNVERIFIED);
for (const auto& model_info : device_info.model_info()) {
if (model_info.manufacturer() ==
drm_info->request_model_info().manufacturer() &&
model_info.model_name() ==
drm_info->request_model_info().model_name()) {
drm_info->mutable_request_model_info()->set_status(model_info.status());
drm_info->mutable_request_model_info()->set_model_year(
model_info.model_year());
break;
}
}
return false;
drm_info->set_system_id(device_info.system_id());
SecurityProfile::ClientInfo* client_info = drm_info->mutable_client_info();
client_info->set_device_name(GetClientInfo(client_id, kModDrmDeviceName));
SecurityProfile::ClientInfo::ProductInfo* product_info =
client_info->mutable_product_info();
product_info->set_product_name(GetClientInfo(client_id, kModDrmProductName));
product_info->set_build_info(GetClientInfo(client_id, kModDrmBuildInfo));
product_info->set_oem_crypto_security_patch_level(
GetClientInfo(client_id, kModDrmOemCryptoSecurityPatchLevel));
// TODO(user): Figure out how to get device platform pushed into SPL API.
DeviceCertificateStatus device_certificate_status;
SecurityProfile::DeviceState device_model_state =
SecurityProfile::DEVICE_STATE_UNKNOWN;
Status status =
DeviceStatusList::Instance()->GetDeviceCertificateStatusBySystemId(
device_info.system_id(), &device_certificate_status);
if (status.ok() && device_certificate_status.has_status()) {
switch (device_certificate_status.status()) {
case DeviceCertificateStatus::STATUS_IN_TESTING:
device_model_state = SecurityProfile::IN_TESTING;
break;
case DeviceCertificateStatus::STATUS_RELEASED:
device_model_state = SecurityProfile::RELEASED;
break;
case DeviceCertificateStatus::STATUS_TEST_ONLY:
device_model_state = SecurityProfile::TEST_ONLY;
break;
case DeviceCertificateStatus::STATUS_REVOKED:
device_model_state = SecurityProfile::REVOKED;
break;
default:
break;
}
}
drm_info->set_device_model_state(device_model_state);
return true;
}
bool SecurityProfileList::GetProfileByName(
@@ -202,49 +155,91 @@ bool SecurityProfileList::GetProfileByName(
bool SecurityProfileList::InsertProfile(
const SecurityProfile& profile_to_insert) {
// Check if profile already exist.
if (GetProfileByLevel(profile_to_insert.level(), nullptr)) {
return false;
}
if (GetProfileByName(profile_to_insert.name(), nullptr)) {
LOG(ERROR) << "Unable to insert profile: " << profile_to_insert.name()
<< ". Name already exist.";
return false;
}
if (profile_to_insert.min_security_requirements().security_level() ==
ProvisionedDeviceInfo::LEVEL_UNSPECIFIED) {
LOG(ERROR) << "Unable to insert profile: " << profile_to_insert.name()
<< ". Security level not specified.";
return false;
}
absl::WriterMutexLock lock(&mutex_);
security_profiles_.push_back(profile_to_insert);
sort(security_profiles_.begin(), security_profiles_.end(),
CompareProfileLevel);
return true;
}
bool SecurityProfileList::CompareProfileLevel(const SecurityProfile& p1,
const SecurityProfile& p2) {
// Profiles are sorted from highest to lowest (strictest) level.
return (p1.level() > p2.level());
int SecurityProfileList::NumProfiles() const {
absl::ReaderMutexLock lock(&mutex_);
return security_profiles_.size();
}
bool SecurityProfileList::IsProfileAllowed(
void SecurityProfileList::ClearAllProfiles() {
absl::WriterMutexLock lock(&mutex_);
security_profiles_.clear();
}
bool SecurityProfileList::DoesProfileQualify(
const SecurityProfile& profile, const ClientIdentification& client_id,
const ProvisionedDeviceInfo& device_info) const {
if (profile.min_security_requirements().security_level() <
device_info.security_level()) {
VLOG(1) << "Profile does not qualify <" << profile.name()
<< "> security level: "
<< profile.min_security_requirements().security_level()
<< ", device: " << device_info.security_level();
return false;
}
if (profile.min_security_requirements().oemcrypto_version() >
if (profile.min_security_requirements().oemcrypto_api_version() >
client_id.client_capabilities().oem_crypto_api_version()) {
VLOG(1) << "Profile does not qualify <" << profile.name()
<< "> oemcrypto version: "
<< profile.min_security_requirements().oemcrypto_api_version()
<< ", device: "
<< client_id.client_capabilities().oem_crypto_api_version();
return false;
}
if (profile.min_output_requirements().hdcp_version() >
client_id.client_capabilities().max_hdcp_version()) {
VLOG(1) << "profile does not qualify <" << profile.name()
<< "> hdcp_version: "
<< profile.min_output_requirements().hdcp_version() << ", device: "
<< client_id.client_capabilities().max_hdcp_version();
return false;
}
if (profile.min_output_requirements().analog_output_capabilities() >
client_id.client_capabilities().analog_output_capabilities()) {
VLOG(1) << "Profile idoes not qualify <" << profile.name()
<< "> analog output: "
<< profile.min_output_requirements().analog_output_capabilities()
<< ", device: "
<< client_id.client_capabilities().analog_output_capabilities();
return false;
}
if (profile.min_security_requirements().resource_rating_tier() >
client_id.client_capabilities().resource_rating_tier()) {
VLOG(1) << "Profile does not qualify <" << profile.name()
<< "> resource rating tier: "
<< profile.min_security_requirements().resource_rating_tier()
<< ", device: "
<< client_id.client_capabilities().resource_rating_tier();
return false;
}
return true;
}
void SecurityProfileList::GetProfileNames(
std::vector<std::string>* profile_names) const {
if (profile_names == nullptr) {
return;
}
absl::ReaderMutexLock lock(&mutex_);
for (auto& profile : security_profiles_) {
profile_names->push_back(profile.name());
}
}
} // namespace widevine

View File

@@ -7,25 +7,22 @@
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Container of Widevine security profiles. Security profiles indicate the
// level of security of a device based on the device's output protections,
// version of OEMCrypto and security level.
// Container of device security profiles. Security profiles indicate rules
// to allow using the profile. The rules are based on DRM capabilities of a
// device.
#ifndef COMMON_SECURITY_PROFILE_LIST_H_
#define COMMON_SECURITY_PROFILE_LIST_H_
#include "absl/synchronization/mutex.h"
#include "protos/public/client_identification.pb.h"
#include "protos/public/device_security_profile_data.pb.h"
#include "protos/public/provisioned_device_info.pb.h"
#include "protos/public/security_profile.pb.h"
namespace widevine {
using ClientCapabilities = ClientIdentification::ClientCapabilities;
const uint32_t kResourceTierLow = 1;
const uint32_t kResourceTierMed = 2;
const uint32_t kResourceTierHigh = 3;
// The SecurityProfileList will hold all security profiles. During license
// acquisition, information from the client and information from the server are
// combined to deternmine the device's security profile level.
@@ -33,57 +30,31 @@ const uint32_t kResourceTierHigh = 3;
class SecurityProfileList {
public:
explicit SecurityProfileList(const std::string& profile_namespace);
~SecurityProfileList() {}
virtual ~SecurityProfileList() {}
// Initialize the security profile list. The list is initially empty, this
// function will populate the list with default profiles. The size of the
// list is returned.
int Init();
// Initialize the security profile list. The size of the profile list is
// returned.
virtual int Init();
// Add the specified profile to the existing list of profiles. Returns true
// if successfully inserted, false if unable to insert.
bool InsertProfile(const SecurityProfile& profile_to_insert);
// Populate |profile_to_create| with the specified output protections and
// security parameters. All input parameters are used hence should be set.
bool PopulateProfile(
const SecurityProfile::Level profile_level,
const std::string& profile_name,
const ClientCapabilities::HdcpVersion min_hdcp_version,
const ClientCapabilities::AnalogOutputCapabilities
analog_output_capabilities,
const uint32_t min_oemcrypto_version, const bool make_model_verified,
const ProvisionedDeviceInfo::WvSecurityLevel security_level,
const uint32_t resource_rating_tier,
SecurityProfile* profile_to_create) const;
// Return the highest security level based on the device capabilities.
// If |drm_info| is not null, |drm_info| is populated with the device data.
SecurityProfile::Level GetBestProfileLevel(
const ClientIdentification& client_id,
const ProvisionedDeviceInfo& device_info,
SecurityProfile::DrmInfo* drm_info) const;
// Populates |profiles_to_allow| with a list of profiles that meet the
// requirements for the this device. The number of profiles is returned.
int GetAllowedProfiles(const ClientIdentification& client_id,
const ProvisionedDeviceInfo& device_info,
std::vector<std::string>* profiles_to_allow) const;
// Populates |profiles_allow| with a list of profiles from the specified
// |profiles_to_check| list that meet the requirements for the this device.
// The number of profiles is returned.
int GetAllowedProfilesFromList(
virtual int GetQualifiedProfilesFromSpecifiedProfiles(
const std::vector<std::string>& profiles_to_check,
const ClientIdentification& client_id,
const ProvisionedDeviceInfo& device_info,
std::vector<std::string>* profiles_to_allow) const;
std::vector<std::string>* qualified_profiles) const;
// Return true if a profile exist matching the specified |level|.
// |security_profile| is owned by the caller and is populated if a profile
// exist.
bool GetProfileByLevel(SecurityProfile::Level level,
SecurityProfile* security_profile) const;
// Populates |profiles_to_allow| with a list of profiles that meet the
// requirements for the this device. The number of profiles is returned.
virtual int GetQualifiedProfiles(
const ClientIdentification& client_id,
const ProvisionedDeviceInfo& device_info,
std::vector<std::string>* qualified_profiles) const;
// Return true if a profile exist matching the specified |name|.
// |security_profile| is owned by the caller and is populated if a profile
@@ -97,17 +68,20 @@ class SecurityProfileList {
const ProvisionedDeviceInfo& device_info,
SecurityProfile::DrmInfo* drm_info) const;
// Return the number of profiles in the list.
int NumProfiles() const;
// Return a list of profile names.
virtual void GetProfileNames(std::vector<std::string>* profile_names) const;
protected:
void ClearAllProfiles();
private:
// Initialize the list with Widevine default profiles. The size of the
// profile list after the additions is returned.
int AddDefaultProfiles();
bool DoesProfileQualify(const SecurityProfile& profile,
const ClientIdentification& client_id,
const ProvisionedDeviceInfo& device_info) const;
static bool CompareProfileLevel(const SecurityProfile& p1,
const SecurityProfile& p2);
bool IsProfileAllowed(const SecurityProfile& profile,
const ClientIdentification& client_id,
const ProvisionedDeviceInfo& device_info) const;
mutable absl::Mutex mutex_;
// Security profiles

View File

@@ -13,6 +13,7 @@
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "absl/memory/memory.h"
#include "common/client_id_util.h"
#include "protos/public/device_common.pb.h"
#include "protos/public/security_profile.pb.h"
@@ -23,7 +24,16 @@ const char kMakeName[] = "company_name";
const char kMakeValue[] = "Google";
const char kModelName[] = "model_name";
const char kModelValue[] = "model1";
const char kDeviceNameValue[] = "TestDeviceName";
const char kProductNameValue[] = "TestProductName";
const char kBuildInfoValue[] = "TestBuildInfo";
const char kOemCryptoSecurityPatchLevelValue[] =
"TestOemCryptoSecurityPatchLevel";
const char kDefaultContentOwnerName[] = "Widevine";
const uint32_t kSystemId = 1234;
const uint32_t kResourceTierLow = 1;
const uint32_t kResourceTierMed = 2;
const uint32_t kResourceTierHigh = 3;
class SecurityProfileListTest : public ::testing::Test {
public:
@@ -32,75 +42,71 @@ class SecurityProfileListTest : public ::testing::Test {
void SetUp() override {
const uint32_t oemcrypto_12 = 12;
const bool make_model_not_verified = false;
const ClientIdentification::ClientCapabilities::HdcpVersion hdcp_version =
ClientCapabilities::HDCP_V2_2;
test_profile_1_.set_level(SecurityProfile::SECURITY_PROFILE_LEVEL_1);
test_profile_1_.mutable_min_output_requirements()->set_hdcp_version(
hdcp_version);
test_profile_1_.mutable_min_output_requirements()
->set_analog_output_capabilities(
ClientCapabilities::ANALOG_OUTPUT_SUPPORTS_CGMS_A);
test_profile_1_.mutable_min_security_requirements()->set_oemcrypto_version(
oemcrypto_12);
test_profile_1_.mutable_min_security_requirements()->set_security_level(
ProvisionedDeviceInfo::LEVEL_1);
test_profile_1_.mutable_min_security_requirements()
->set_resource_rating_tier(kResourceTierHigh);
test_profile_1_.mutable_min_security_requirements()
->set_request_model_info_status(make_model_not_verified);
std::string profile_namespace = "widevine_test";
SecurityProfile profile;
std::string profile_namespace = "widevine";
profile_list_ = absl::make_unique<SecurityProfileList>(profile_namespace);
ClientIdentification_NameValue *nv = client_id_.add_client_info();
nv->set_name(kMakeName);
nv->set_value(kMakeValue);
nv = client_id_.add_client_info();
nv->set_name(kModelName);
nv->set_value(kModelValue);
AddClientInfo(&client_id_, kMakeName, kMakeValue);
AddClientInfo(&client_id_, kModelName, kModelValue);
AddClientInfo(&client_id_, kModDrmDeviceName, kDeviceNameValue);
AddClientInfo(&client_id_, kModDrmProductName, kProductNameValue);
AddClientInfo(&client_id_, kModDrmBuildInfo, kBuildInfoValue);
AddClientInfo(&client_id_, kModDrmOemCryptoSecurityPatchLevel,
kOemCryptoSecurityPatchLevelValue);
client_id_.mutable_client_capabilities()->set_oem_crypto_api_version(
oemcrypto_12);
client_id_.mutable_client_capabilities()->set_max_hdcp_version(
hdcp_version);
ClientCapabilities::HDCP_V2_2);
client_id_.mutable_client_capabilities()->set_resource_rating_tier(
kResourceTierHigh);
device_info_.set_security_level(ProvisionedDeviceInfo::LEVEL_1);
device_info_.set_system_id(kSystemId);
}
SecurityProfile test_profile_1_;
std::unique_ptr<SecurityProfileList> profile_list_;
ClientIdentification client_id_;
ProvisionedDeviceInfo device_info_;
};
TEST_F(SecurityProfileListTest, InsertProfile) {
// This test will not initialize the SecurityProfileList, hence it's empty.
// Insert test profile 1 into the list.
EXPECT_TRUE(profile_list_->InsertProfile(test_profile_1_));
// Should not allow insertion of an already existing level.
EXPECT_FALSE(profile_list_->InsertProfile(test_profile_1_));
SecurityProfile profile;
// Should not allow insertion of an already existing name.
// Make sure the level is not the same as already inserted level_1.
profile.set_level(SecurityProfile::SECURITY_PROFILE_LEVEL_2);
profile.set_name(test_profile_1_.name());
EXPECT_FALSE(profile_list_->InsertProfile(test_profile_1_));
ASSERT_TRUE(profile_list_->GetProfileByLevel(
SecurityProfile::SECURITY_PROFILE_LEVEL_1, &profile));
EXPECT_TRUE(
google::protobuf::util::MessageDifferencer::Equals(test_profile_1_, profile));
// Insert test profile1 into the list.
SecurityProfileList profile_list("widevine-test");
SecurityProfile profile1;
profile1.set_name("profile1");
profile1.mutable_min_security_requirements()->set_security_level(
ProvisionedDeviceInfo::LEVEL_3);
EXPECT_TRUE(profile_list.InsertProfile(profile1));
// Verify the list still has one profile.
EXPECT_EQ(1, profile_list.NumProfiles());
// Should not allow insert if existing profile has the same name.
SecurityProfile profile2;
profile2.set_name(profile1.name());
profile2.mutable_min_security_requirements()->set_security_level(
ProvisionedDeviceInfo::LEVEL_3);
EXPECT_FALSE(profile_list.InsertProfile(profile2));
// Verify the list still has one profile.
EXPECT_EQ(1, profile_list.NumProfiles());
// Should allow insert since this profile has a different name.
profile2.set_name("profile2");
EXPECT_TRUE(profile_list.InsertProfile(profile2));
EXPECT_EQ(2, profile_list.NumProfiles());
}
TEST_F(SecurityProfileListTest, GetDrmInfo) {
SecurityProfile::DrmInfo drm_info;
DeviceModel* device_model = device_info_.add_model_info();
device_model->set_manufacturer(GetClientInfo(client_id_, kModDrmMake));
device_model->set_model_name(GetClientInfo(client_id_, kModDrmModel));
device_model->set_status(DeviceModel::MODEL_STATUS_VERIFIED);
const uint32_t model_launch_year = 2015;
device_model->set_model_year(model_launch_year);
ASSERT_TRUE(profile_list_->GetDrmInfo(client_id_, device_info_, &drm_info));
EXPECT_EQ(client_id_.client_capabilities().max_hdcp_version(),
drm_info.output().hdcp_version());
EXPECT_EQ(client_id_.client_capabilities().analog_output_capabilities(),
drm_info.output().analog_output_capabilities());
EXPECT_EQ(client_id_.client_capabilities().oem_crypto_api_version(),
drm_info.security().oemcrypto_version());
drm_info.security().oemcrypto_api_version());
EXPECT_EQ(client_id_.client_capabilities().resource_rating_tier(),
drm_info.security().resource_rating_tier());
@@ -108,104 +114,92 @@ TEST_F(SecurityProfileListTest, GetDrmInfo) {
drm_info.security().security_level());
EXPECT_EQ(device_info_.system_id(), drm_info.system_id());
// make_mode status is currently hard-coded to false.
EXPECT_EQ(false, drm_info.security().request_model_info_status());
EXPECT_EQ(kMakeValue, drm_info.request_model_info().manufacturer());
EXPECT_EQ(kModelValue, drm_info.request_model_info().model_name());
EXPECT_EQ(DeviceModel::MODEL_STATUS_VERIFIED,
drm_info.request_model_info().status());
EXPECT_EQ(model_launch_year, drm_info.request_model_info().model_year());
EXPECT_EQ(kDeviceNameValue, drm_info.client_info().device_name());
EXPECT_EQ(kProductNameValue,
drm_info.client_info().product_info().product_name());
EXPECT_EQ(kBuildInfoValue,
drm_info.client_info().product_info().build_info());
EXPECT_EQ(
kOemCryptoSecurityPatchLevelValue,
drm_info.client_info().product_info().oem_crypto_security_patch_level());
}
TEST_F(SecurityProfileListTest, ProfileLevels) {
SecurityProfile::DrmInfo drm_info;
profile_list_->Init();
TEST_F(SecurityProfileListTest, QualifiedProfiles) {
SecurityProfile profile1;
profile1.set_name("profile1");
profile1.mutable_min_security_requirements()->set_security_level(
ProvisionedDeviceInfo::LEVEL_3);
profile1.mutable_min_output_requirements()->set_hdcp_version(
ClientCapabilities::HDCP_V1);
profile_list_->InsertProfile(profile1);
client_id_.mutable_client_capabilities()->set_max_hdcp_version(
ClientCapabilities::HDCP_NONE);
client_id_.mutable_client_capabilities()->set_analog_output_capabilities(
ClientCapabilities::ANALOG_OUTPUT_UNKNOWN);
client_id_.mutable_client_capabilities()->set_oem_crypto_api_version(7);
client_id_.mutable_client_capabilities()->set_resource_rating_tier(
kResourceTierLow);
device_info_.set_security_level(ProvisionedDeviceInfo::LEVEL_3);
SecurityProfile profile2;
profile2.set_name("profile2");
profile2.mutable_min_security_requirements()->set_security_level(
ProvisionedDeviceInfo::LEVEL_1);
profile2.mutable_min_output_requirements()->set_hdcp_version(
ClientCapabilities::HDCP_V2);
profile_list_->InsertProfile(profile2);
// Lowest profile level requires OEMCrypto version 8.
ASSERT_EQ(
SecurityProfile::SECURITY_PROFILE_LEVEL_UNDEFINED,
profile_list_->GetBestProfileLevel(client_id_, device_info_, &drm_info));
// Both profiles should qualify based on client_info and device_info from the
// Setup function.
std::vector<std::string> qualified_profiles;
EXPECT_EQ(2, profile_list_->GetQualifiedProfiles(client_id_, device_info_,
&qualified_profiles));
EXPECT_NE(qualified_profiles.end(),
std::find(qualified_profiles.begin(), qualified_profiles.end(),
profile1.name()));
EXPECT_NE(qualified_profiles.end(),
std::find(qualified_profiles.begin(), qualified_profiles.end(),
profile2.name()));
// Move up to profile 1
client_id_.mutable_client_capabilities()->set_oem_crypto_api_version(8);
ASSERT_EQ(
SecurityProfile::SECURITY_PROFILE_LEVEL_1,
profile_list_->GetBestProfileLevel(client_id_, device_info_, &drm_info));
// Move up to profile 2
client_id_.mutable_client_capabilities()->set_analog_output_capabilities(
ClientCapabilities::ANALOG_OUTPUT_SUPPORTS_CGMS_A);
client_id_.mutable_client_capabilities()->set_oem_crypto_api_version(12);
device_info_.set_security_level(ProvisionedDeviceInfo::LEVEL_2);
ASSERT_EQ(
SecurityProfile::SECURITY_PROFILE_LEVEL_2,
profile_list_->GetBestProfileLevel(client_id_, device_info_, &drm_info));
// Move up to profile 3
// Reduce the DRM capabilities of the device so profile2 will not qualify.
client_id_.mutable_client_capabilities()->set_max_hdcp_version(
ClientCapabilities::HDCP_V1);
device_info_.set_security_level(ProvisionedDeviceInfo::LEVEL_1);
client_id_.mutable_client_capabilities()->set_resource_rating_tier(
kResourceTierMed);
ASSERT_EQ(
SecurityProfile::SECURITY_PROFILE_LEVEL_3,
profile_list_->GetBestProfileLevel(client_id_, device_info_, &drm_info));
// Move up to profile 4
client_id_.mutable_client_capabilities()->set_max_hdcp_version(
ClientCapabilities::HDCP_V2_2);
client_id_.mutable_client_capabilities()->set_resource_rating_tier(
kResourceTierHigh);
ASSERT_EQ(
SecurityProfile::SECURITY_PROFILE_LEVEL_4,
profile_list_->GetBestProfileLevel(client_id_, device_info_, &drm_info));
ASSERT_EQ(1, profile_list_->GetQualifiedProfiles(client_id_, device_info_,
&qualified_profiles));
EXPECT_NE(qualified_profiles.end(),
std::find(qualified_profiles.begin(), qualified_profiles.end(),
profile1.name()));
}
TEST_F(SecurityProfileListTest, FindProfile) {
// This test will not initialize the SecurityProfileList, hence it's empty.
// Insert test profile 1 into the list.
SecurityProfileList profile_list("widevine-test");
SecurityProfile profile1;
profile1.set_level(SecurityProfile::SECURITY_PROFILE_LEVEL_1);
profile1.set_name("profile1");
profile1.mutable_min_security_requirements()->set_security_level(
ProvisionedDeviceInfo::LEVEL_3);
EXPECT_EQ(kDefaultContentOwnerName, profile1.owner());
SecurityProfile profile2;
profile2.set_level(SecurityProfile::SECURITY_PROFILE_LEVEL_2);
profile2.set_name("profile2");
SecurityProfile profile3;
profile3.set_level(SecurityProfile::SECURITY_PROFILE_LEVEL_3);
profile3.set_name("profile3");
// Insert profiles 1 & 2, but not 3..
EXPECT_TRUE(profile_list_->InsertProfile(profile1));
EXPECT_TRUE(profile_list_->InsertProfile(profile2));
// Find the profile by its level.
SecurityProfile profile;
EXPECT_TRUE(profile_list_->GetProfileByLevel(profile1.level(), &profile));
EXPECT_EQ(profile1.name(), profile.name());
EXPECT_EQ(profile1.level(), profile.level());
EXPECT_TRUE(profile_list_->GetProfileByLevel(profile2.level(), &profile));
EXPECT_EQ(profile2.name(), profile.name());
EXPECT_EQ(profile2.level(), profile.level());
EXPECT_FALSE(profile_list_->GetProfileByName(profile3.name(), nullptr));
profile2.mutable_min_security_requirements()->set_security_level(
ProvisionedDeviceInfo::LEVEL_3);
// Override the default owner name.
profile2.set_owner("owner2");
// Insert profiles 1 & 2.
EXPECT_TRUE(profile_list.InsertProfile(profile1));
EXPECT_TRUE(profile_list.InsertProfile(profile2));
EXPECT_EQ(2, profile_list.NumProfiles());
// Find the profile by its name.
EXPECT_TRUE(profile_list_->GetProfileByName(profile1.name(), &profile));
SecurityProfile profile;
EXPECT_TRUE(profile_list.GetProfileByName(profile1.name(), &profile));
EXPECT_EQ(profile1.name(), profile.name());
EXPECT_EQ(profile1.level(), profile.level());
EXPECT_EQ(profile1.owner(), profile.owner());
EXPECT_TRUE(profile_list_->GetProfileByName(profile2.name(), &profile));
EXPECT_TRUE(profile_list.GetProfileByName(profile2.name(), &profile));
EXPECT_EQ(profile2.name(), profile.name());
EXPECT_EQ(profile2.level(), profile.level());
EXPECT_EQ(profile2.owner(), profile.owner());
EXPECT_FALSE(profile_list_->GetProfileByName(profile3.name(), nullptr));
EXPECT_FALSE(
profile_list.GetProfileByName("you-should-not-find-me", &profile));
}
} // namespace security_profile

View File

@@ -37,7 +37,8 @@ std::string Sha512_Hash(const std::string& message) {
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.
// - Allocate a UUID to use as a "name space identifier" for all UUIDs
// generated from names in that name space.

View File

@@ -7,6 +7,7 @@
////////////////////////////////////////////////////////////////////////////////
#include "common/sha_util.h"
#include "testing/gunit.h"
#include "absl/strings/escaping.h"

View File

@@ -39,6 +39,7 @@ Status GenerateAesSignature(const std::string& message,
Status GenerateRsaSignature(const std::string& message,
const std::string& private_key,
HashAlgorithm hash_algorithm,
std::string* signature) {
if (signature == nullptr) {
return Status(error::INVALID_ARGUMENT, "signature is nullptr");
@@ -49,7 +50,7 @@ Status GenerateRsaSignature(const std::string& message,
return Status(error::INTERNAL, "Failed to construct a RsaPrivateKey");
}
std::string sig;
if (!rsa_private_key->GenerateSignature(message, &sig)) {
if (!rsa_private_key->GenerateSignature(message, hash_algorithm, &sig)) {
return Status(error::INTERNAL, "Failed to generate a RSA signature");
}
if (sig.empty()) {

View File

@@ -11,6 +11,7 @@
#include <string>
#include "common/hash_algorithm.h"
#include "common/status.h"
namespace widevine {
@@ -23,11 +24,13 @@ Status GenerateAesSignature(const std::string& message,
const std::string& aes_key,
const std::string& aes_iv, std::string* signature);
// Generates a RSA signature of |message| using |private_key|.
// Signature is returned via |sigature| if generation was successful.
// Returns a Status that carries the details of error if generation failed.
// Generates a RSA signature of |message| using |private_key| and
// |hash_algorithm|. Signature is returned via |sigature| if generation was
// successful. Returns a Status that carries the details of error if generation
// failed.
Status GenerateRsaSignature(const std::string& message,
const std::string& private_key,
HashAlgorithm hash_algorithm,
std::string* signature);
} // namespace signature_util

View File

@@ -25,9 +25,10 @@ class SignerPublicKeyImpl : public SignerPublicKey {
SignerPublicKeyImpl(const SignerPublicKeyImpl&) = delete;
SignerPublicKeyImpl& operator=(const SignerPublicKeyImpl&) = delete;
bool VerifySignature(const std::string& message,
bool VerifySignature(const std::string& message, HashAlgorithm hash_algorithm,
const std::string& signature) const override {
if (!signer_public_key_->VerifySignature(message, signature)) {
if (!signer_public_key_->VerifySignature(message, hash_algorithm,
signature)) {
return false;
}
return true;

View File

@@ -11,6 +11,7 @@
#include <string>
#include "common/hash_algorithm.h"
#include "protos/public/drm_certificate.pb.h"
namespace widevine {
@@ -24,8 +25,9 @@ class SignerPublicKey {
SignerPublicKey(const SignerPublicKey&) = delete;
SignerPublicKey& operator=(const SignerPublicKey&) = delete;
// Verify message using |signer_public_key_|.
// Verify message using |signer_public_key_| and |hash_algorithm|.
virtual bool VerifySignature(const std::string& message,
HashAlgorithm hash_algorithm,
const std::string& signature) const = 0;
// A factory method to create a SignerPublicKey. The |algorithm| is used to

View File

@@ -13,6 +13,7 @@
#include "testing/gunit.h"
#include "common/ec_key.h"
#include "common/ec_test_keys.h"
#include "common/hash_algorithm.h"
#include "common/rsa_key.h"
#include "common/rsa_test_keys.h"
#include "protos/public/drm_certificate.pb.h"
@@ -20,6 +21,7 @@
namespace widevine {
static const char kMessage[] = "The rain in Spain falls mainly in the blank?";
const HashAlgorithm kHashAlgorithm = HashAlgorithm::kSha256;
class SignerPublicKeyTest : public ::testing::Test {
public:
@@ -32,12 +34,13 @@ TEST_F(SignerPublicKeyTest, RSA) {
RsaPrivateKey::Create(rsa_test_keys_.private_test_key_1_3072_bits()));
std::string signature;
ASSERT_TRUE(private_key->GenerateSignature(kMessage, &signature));
ASSERT_TRUE(
private_key->GenerateSignature(kMessage, kHashAlgorithm, &signature));
std::unique_ptr<SignerPublicKey> public_key = SignerPublicKey::Create(
rsa_test_keys_.public_test_key_1_3072_bits(), DrmCertificate::RSA);
ASSERT_NE(public_key, nullptr);
EXPECT_TRUE(public_key->VerifySignature(kMessage, signature));
EXPECT_TRUE(public_key->VerifySignature(kMessage, kHashAlgorithm, signature));
}
TEST_F(SignerPublicKeyTest, ECC) {
@@ -45,13 +48,14 @@ TEST_F(SignerPublicKeyTest, ECC) {
ECPrivateKey::Create(ec_test_keys_.private_test_key_1_secp521r1());
std::string signature;
ASSERT_TRUE(private_key->GenerateSignature(kMessage, &signature));
ASSERT_TRUE(
private_key->GenerateSignature(kMessage, kHashAlgorithm, &signature));
std::unique_ptr<SignerPublicKey> public_key =
SignerPublicKey::Create(ec_test_keys_.public_test_key_1_secp521r1(),
DrmCertificate::ECC_SECP521R1);
ASSERT_NE(public_key, nullptr);
EXPECT_TRUE(public_key->VerifySignature(kMessage, signature));
EXPECT_TRUE(public_key->VerifySignature(kMessage, kHashAlgorithm, signature));
}
TEST_F(SignerPublicKeyTest, IncorrectAlgorithm) {

View File

@@ -7,6 +7,7 @@
////////////////////////////////////////////////////////////////////////////////
#include "common/signing_key_util.h"
#include "testing/gunit.h"
#include "absl/strings/escaping.h"
#include "common/crypto_util.h"

View File

@@ -7,6 +7,7 @@
////////////////////////////////////////////////////////////////////////////////
#include "common/string_util.h"
#include "testing/gmock.h"
#include "testing/gunit.h"

View File

@@ -9,6 +9,7 @@
#include "common/test_utils.h"
#include <stddef.h>
#include <memory>
#include "glog/logging.h"

View File

@@ -22,7 +22,7 @@ namespace widevine {
// and PKCS#1 1.5 padding. |pem_private_key| is a PEM-encoded private RSA key,
// |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
// all paramters.
// all parameters.
Status GenerateRsaSignatureSha256Pkcs1(const std::string& pem_private_key,
const std::string& message,
std::string* signature);

View File

@@ -13,6 +13,7 @@
#define COMMON_VERIFIED_MEDIA_PIPELINE_H_
#include <string>
#include "common/status.h"
#include "protos/public/license_protocol.pb.h"

View File

@@ -13,12 +13,14 @@
#include "common/vmp_checker.h"
#include <stddef.h>
#include <vector>
#include <cstdint>
#include "glog/logging.h"
#include "common/certificate_type.h"
#include "common/error_space.h"
#include "common/hash_algorithm_util.h"
#include "common/rsa_key.h"
#include "common/x509_cert.h"
#include "protos/public/errors.pb.h"
@@ -334,7 +336,9 @@ Status VmpChecker::VerifyVmpData(const std::string& vmp_data, Result* result) {
std::unique_ptr<RsaPublicKey> key(cert->GetRsaPublicKey());
std::string message(binary_info.binary_hash());
message += binary_info.flags() & 0xff;
if (!key->VerifySignature(message, binary_info.signature())) {
if (!key->VerifySignature(
message, HashAlgorithmProtoToEnum(binary_info.hash_algorithm()),
binary_info.signature())) {
LOG(INFO) << "Code signature verification failed for file \""
<< binary_info.file_name() << "\".";
*result = kTampered;

View File

@@ -6,14 +6,16 @@
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "common/vmp_checker.h"
#include <memory>
#include "glog/logging.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "absl/strings/escaping.h"
#include "common/hash_algorithm_util.h"
#include "common/rsa_key.h"
#include "common/vmp_checker.h"
#include "protos/public/errors.pb.h"
#include "protos/public/verified_media_pipeline.pb.h"
@@ -184,7 +186,9 @@ class VmpCheckerTest : public ::testing::Test {
std::string message(binary_hash);
message += flags & 0xff;
std::string signature;
ASSERT_TRUE(signing_key_->GenerateSignature(message, &signature));
ASSERT_TRUE(signing_key_->GenerateSignature(
message, HashAlgorithmProtoToEnum(new_binary->hash_algorithm()),
&signature));
new_binary->set_signature(signature);
}

View File

@@ -6,11 +6,12 @@
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "common/wvm_test_keys.h"
#include <vector>
#include "absl/strings/escaping.h"
#include "absl/strings/string_view.h"
#include "common/wvm_test_keys.h"
#include "common/wvm_token_handler.h"
namespace widevine {

View File

@@ -7,22 +7,23 @@
////////////////////////////////////////////////////////////////////////////////
#include "common/wvm_token_handler.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "absl/strings/escaping.h"
#include "absl/strings/string_view.h"
#include "common/wvm_test_keys.h"
using widevine::wvm_test_keys::kTestSystemId;
using widevine::wvm_test_keys::kTestSystemId3Des;
using widevine::wvm_test_keys::kTestPreprovKeyHex;
using widevine::wvm_test_keys::GetPreprovKeyVector;
using widevine::wvm_test_keys::kTestDeviceKey1Hex;
using widevine::wvm_test_keys::kTestDeviceKey2Hex;
using widevine::wvm_test_keys::kTestDeviceKey3DesHex;
using widevine::wvm_test_keys::kTestPreprovKeyHex;
using widevine::wvm_test_keys::kTestSystemId;
using widevine::wvm_test_keys::kTestSystemId3Des;
using widevine::wvm_test_keys::kTestToken1Hex;
using widevine::wvm_test_keys::kTestToken2Hex;
using widevine::wvm_test_keys::kTestToken3DesHex;
using widevine::wvm_test_keys::GetPreprovKeyVector;
namespace widevine {

View File

@@ -13,12 +13,13 @@
#define COMMON_X509_CERT_H_
#include <stddef.h>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "base/thread_annotations.h"
#include "absl/base/thread_annotations.h"
#include "absl/synchronization/mutex.h"
#include "openssl/pem.h"
#include "openssl/x509.h"

View File

@@ -6,13 +6,14 @@
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "common/x509_cert.h"
#include <memory>
#include "testing/gunit.h"
#include "absl/strings/escaping.h"
#include "common/rsa_key.h"
#include "common/test_utils.h"
#include "common/x509_cert.h"
namespace widevine {
const char kTestRootCaDerCert[] =
@@ -352,7 +353,6 @@ const char kTestDevCodeSigningCert[] =
const char kDevCertFlagOid[] = "1.3.6.1.4.1.11129.4.1.2";
const bool kTestDevCodeSigningCertFlagValue = true;
TEST(X509CertTest, LoadCert) {
X509Cert test_cert;
EXPECT_EQ(OkStatus(),