Export media_cas_packager_sdk
This commit is contained in:
369
common/drm_service_certificate_test.cc
Normal file
369
common/drm_service_certificate_test.cc
Normal file
@@ -0,0 +1,369 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2013 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/drm_service_certificate.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "glog/logging.h"
|
||||
#include "google/protobuf/util/message_differencer.h"
|
||||
#include "testing/gmock.h"
|
||||
#include "testing/gunit.h"
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "common/aes_cbc_util.h"
|
||||
#include "common/rsa_key.h"
|
||||
#include "common/rsa_test_keys.h"
|
||||
#include "common/rsa_util.h"
|
||||
#include "common/test_certificates.h"
|
||||
#include "protos/public/client_identification.pb.h"
|
||||
#include "protos/public/drm_certificate.pb.h"
|
||||
#include "protos/public/errors.pb.h" // IWYU pragma: keep
|
||||
#include "protos/public/license_server_sdk.pb.h"
|
||||
#include "protos/public/signed_drm_certificate.pb.h"
|
||||
|
||||
namespace widevine {
|
||||
|
||||
const char kPrivacyKey[] = "f7538b38acc78ec68c732ac665c55c65";
|
||||
const char kIv[] = "09e9cda133ff5140bd2793173a04b5a3";
|
||||
const char kPassphrase[] = "passphrase";
|
||||
|
||||
class DrmServiceCertificateTest : public ::testing::Test {
|
||||
public:
|
||||
DrmServiceCertificateTest()
|
||||
: privacy_key_(absl::HexStringToBytes(kPrivacyKey)),
|
||||
iv_(absl::HexStringToBytes(kIv)),
|
||||
root_private_key_(
|
||||
RsaPrivateKey::Create(test_keys_.private_test_key_1_3072_bits())) {
|
||||
CHECK(root_private_key_ != nullptr);
|
||||
client_id_.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE);
|
||||
client_id_.set_token(test_certs_.test_user_device_certificate());
|
||||
}
|
||||
|
||||
void SetUp() override { DrmServiceCertificate::ResetServiceCertificates(); }
|
||||
|
||||
protected:
|
||||
std::string GenerateDrmServiceCertificate(const std::string& serial_number,
|
||||
const std::string& provider_id,
|
||||
uint32_t creation_time_seconds,
|
||||
const std::string& public_key) {
|
||||
DrmCertificate cert;
|
||||
cert.set_type(DrmCertificate::SERVICE);
|
||||
cert.set_serial_number(serial_number);
|
||||
cert.set_provider_id(provider_id);
|
||||
cert.set_public_key(public_key);
|
||||
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());
|
||||
std::string serialized_cert;
|
||||
signed_cert.SerializeToString(&serialized_cert);
|
||||
return serialized_cert;
|
||||
}
|
||||
|
||||
util::Status SetDefaultDrmServiceCertificate(const std::string& serial_number,
|
||||
const std::string& provider_id,
|
||||
uint32_t creation_time_seconds) {
|
||||
std::string signed_cert(GenerateDrmServiceCertificate(
|
||||
serial_number, provider_id, creation_time_seconds,
|
||||
test_keys_.public_test_key_2_2048_bits()));
|
||||
std::string encrypted_private_key;
|
||||
if (!rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo(
|
||||
test_keys_.private_test_key_2_2048_bits(), kPassphrase,
|
||||
&encrypted_private_key)) {
|
||||
return util::Status(util::error::INTERNAL, "");
|
||||
}
|
||||
return DrmServiceCertificate::SetDefaultDrmServiceCertificate(
|
||||
test_keys_.public_test_key_1_3072_bits(), signed_cert,
|
||||
encrypted_private_key, kPassphrase);
|
||||
}
|
||||
|
||||
util::Status AddDrmServiceCertificate(const std::string& serial_number,
|
||||
const std::string& provider_id,
|
||||
uint32_t creation_time_seconds) {
|
||||
std::string signed_cert(GenerateDrmServiceCertificate(
|
||||
serial_number, provider_id, creation_time_seconds,
|
||||
test_keys_.public_test_key_2_2048_bits()));
|
||||
std::string encrypted_private_key;
|
||||
if (!rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo(
|
||||
test_keys_.private_test_key_2_2048_bits(), kPassphrase,
|
||||
&encrypted_private_key)) {
|
||||
return util::Status(util::error::INTERNAL, "");
|
||||
}
|
||||
return DrmServiceCertificate::AddDrmServiceCertificate(
|
||||
test_keys_.public_test_key_1_3072_bits(), signed_cert,
|
||||
encrypted_private_key, kPassphrase);
|
||||
}
|
||||
|
||||
void EncryptClientIdentification(
|
||||
const std::string& serial_number, const std::string& provider_id,
|
||||
const std::string& public_key,
|
||||
EncryptedClientIdentification* encrypted_client_id) {
|
||||
CHECK(encrypted_client_id);
|
||||
encrypted_client_id->set_provider_id(provider_id);
|
||||
encrypted_client_id->set_service_certificate_serial_number(serial_number);
|
||||
std::string serial_client_id;
|
||||
client_id_.SerializeToString(&serial_client_id);
|
||||
encrypted_client_id->set_encrypted_client_id(
|
||||
crypto_util::EncryptAesCbc(privacy_key_, iv_, serial_client_id));
|
||||
encrypted_client_id->set_encrypted_client_id_iv(iv_);
|
||||
std::unique_ptr<RsaPublicKey> rsa_key(RsaPublicKey::Create(public_key));
|
||||
ASSERT_TRUE(rsa_key.get());
|
||||
rsa_key->Encrypt(privacy_key_,
|
||||
encrypted_client_id->mutable_encrypted_privacy_key());
|
||||
}
|
||||
|
||||
RsaTestKeys test_keys_;
|
||||
TestCertificates test_certs_;
|
||||
std::string privacy_key_;
|
||||
std::string iv_;
|
||||
std::unique_ptr<RsaPrivateKey> root_private_key_;
|
||||
ClientIdentification client_id_;
|
||||
};
|
||||
|
||||
TEST_F(DrmServiceCertificateTest, BasicClientIdDecrypt) {
|
||||
std::string serial_number("serial_number");
|
||||
std::string provider_id("someservice.com");
|
||||
uint32_t creation_time_seconds(1234);
|
||||
|
||||
EXPECT_OK(AddDrmServiceCertificate(serial_number, provider_id,
|
||||
creation_time_seconds));
|
||||
EncryptedClientIdentification encrypted_client_id;
|
||||
EncryptClientIdentification(serial_number, provider_id,
|
||||
test_keys_.public_test_key_2_2048_bits(),
|
||||
&encrypted_client_id);
|
||||
ClientIdentification decrypted_client_id;
|
||||
EXPECT_EQ(util::OkStatus(),
|
||||
DrmServiceCertificate::DecryptClientIdentification(
|
||||
encrypted_client_id, &decrypted_client_id));
|
||||
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_,
|
||||
decrypted_client_id));
|
||||
}
|
||||
|
||||
TEST_F(DrmServiceCertificateTest, NoDefaultDrmServiceCertificate) {
|
||||
ASSERT_EQ(nullptr, DrmServiceCertificate::GetDefaultDrmServiceCertificate());
|
||||
const auto& get_default_sc_or_die = []() {
|
||||
DrmServiceCertificate::GetDefaultDrmServiceCertificateOrDie();
|
||||
};
|
||||
EXPECT_DEATH(get_default_sc_or_die(), "Service Certificate not set!");
|
||||
}
|
||||
|
||||
TEST_F(DrmServiceCertificateTest, MultipleDrmServiceCertificates) {
|
||||
std::string serial_number1("serial_number1");
|
||||
std::string provider_id1("someservice.com");
|
||||
uint32_t creation_time_seconds1(1234);
|
||||
std::string serial_number2("serial_number2");
|
||||
uint32_t creation_time_seconds2(1234);
|
||||
std::string bogus_serial_number("bogus-serial-number2");
|
||||
|
||||
EXPECT_EQ(nullptr, DrmServiceCertificate::GetDefaultDrmServiceCertificate());
|
||||
|
||||
EXPECT_OK(AddDrmServiceCertificate(serial_number1, provider_id1,
|
||||
creation_time_seconds1));
|
||||
|
||||
// Expect this to pass because the serial number is allowed to change as long
|
||||
// as the service Id is the same as before.
|
||||
EXPECT_OK(AddDrmServiceCertificate(serial_number2, provider_id1,
|
||||
creation_time_seconds2));
|
||||
|
||||
EncryptedClientIdentification encrypted_client_id;
|
||||
EncryptClientIdentification(serial_number1, provider_id1,
|
||||
test_keys_.public_test_key_2_2048_bits(),
|
||||
&encrypted_client_id);
|
||||
ClientIdentification decrypted_client_id;
|
||||
EXPECT_OK(DrmServiceCertificate::DecryptClientIdentification(
|
||||
encrypted_client_id, &decrypted_client_id));
|
||||
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_,
|
||||
decrypted_client_id));
|
||||
|
||||
EncryptClientIdentification(serial_number2, provider_id1,
|
||||
test_keys_.public_test_key_2_2048_bits(),
|
||||
&encrypted_client_id);
|
||||
EXPECT_OK(DrmServiceCertificate::DecryptClientIdentification(
|
||||
encrypted_client_id, &decrypted_client_id));
|
||||
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_,
|
||||
decrypted_client_id));
|
||||
|
||||
EncryptClientIdentification(bogus_serial_number, provider_id1,
|
||||
test_keys_.public_test_key_2_2048_bits(),
|
||||
&encrypted_client_id);
|
||||
EXPECT_EQ(SERVICE_CERTIFICATE_NOT_FOUND,
|
||||
DrmServiceCertificate::DecryptClientIdentification(
|
||||
encrypted_client_id, &decrypted_client_id)
|
||||
.error_code());
|
||||
}
|
||||
|
||||
TEST_F(DrmServiceCertificateTest, MultipleCertsPerService) {
|
||||
std::string serial_number1("serial_number1");
|
||||
std::string serial_number2("serial_number2");
|
||||
std::string serial_number3("serial_number3");
|
||||
std::string provider_id("someservice.com");
|
||||
uint32_t creation_time_seconds(1234);
|
||||
|
||||
EXPECT_OK(AddDrmServiceCertificate(serial_number1, provider_id,
|
||||
creation_time_seconds));
|
||||
EXPECT_OK(AddDrmServiceCertificate(serial_number2, provider_id,
|
||||
creation_time_seconds + 1));
|
||||
EXPECT_OK(AddDrmServiceCertificate(serial_number3, provider_id,
|
||||
creation_time_seconds - 1));
|
||||
|
||||
EncryptedClientIdentification encrypted_client_id;
|
||||
EncryptClientIdentification(serial_number1, provider_id,
|
||||
test_keys_.public_test_key_2_2048_bits(),
|
||||
&encrypted_client_id);
|
||||
ClientIdentification decrypted_client_id;
|
||||
EXPECT_EQ(util::OkStatus(),
|
||||
DrmServiceCertificate::DecryptClientIdentification(
|
||||
encrypted_client_id, &decrypted_client_id));
|
||||
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_,
|
||||
decrypted_client_id));
|
||||
|
||||
EncryptClientIdentification(serial_number2, provider_id,
|
||||
test_keys_.public_test_key_2_2048_bits(),
|
||||
&encrypted_client_id);
|
||||
EXPECT_EQ(util::OkStatus(),
|
||||
DrmServiceCertificate::DecryptClientIdentification(
|
||||
encrypted_client_id, &decrypted_client_id));
|
||||
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_,
|
||||
decrypted_client_id));
|
||||
|
||||
EncryptClientIdentification(serial_number3, provider_id,
|
||||
test_keys_.public_test_key_2_2048_bits(),
|
||||
&encrypted_client_id);
|
||||
EXPECT_EQ(util::OkStatus(),
|
||||
DrmServiceCertificate::DecryptClientIdentification(
|
||||
encrypted_client_id, &decrypted_client_id));
|
||||
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_,
|
||||
decrypted_client_id));
|
||||
|
||||
const DrmServiceCertificate* default_cert(
|
||||
DrmServiceCertificate::GetDefaultDrmServiceCertificate());
|
||||
ASSERT_TRUE(default_cert);
|
||||
SignedDrmCertificate signed_cert;
|
||||
ASSERT_TRUE(signed_cert.ParseFromString(default_cert->certificate()));
|
||||
DrmCertificate drm_cert;
|
||||
ASSERT_TRUE(drm_cert.ParseFromString(signed_cert.drm_certificate()));
|
||||
EXPECT_EQ(serial_number1, drm_cert.serial_number());
|
||||
|
||||
EXPECT_OK(SetDefaultDrmServiceCertificate(serial_number2, provider_id,
|
||||
creation_time_seconds));
|
||||
default_cert = DrmServiceCertificate::GetDefaultDrmServiceCertificate();
|
||||
ASSERT_TRUE(default_cert);
|
||||
ASSERT_TRUE(signed_cert.ParseFromString(default_cert->certificate()));
|
||||
ASSERT_TRUE(drm_cert.ParseFromString(signed_cert.drm_certificate()));
|
||||
EXPECT_EQ(serial_number2, drm_cert.serial_number());
|
||||
}
|
||||
|
||||
TEST_F(DrmServiceCertificateTest, DrmServiceCertificateNotFound) {
|
||||
std::string serial_number("serial_number");
|
||||
std::string provider_id("someservice.com");
|
||||
uint32_t creation_time_seconds(1234);
|
||||
|
||||
EXPECT_OK(AddDrmServiceCertificate(serial_number, provider_id,
|
||||
creation_time_seconds));
|
||||
EncryptedClientIdentification encrypted_client_id;
|
||||
EncryptClientIdentification("invalid_serial_number", provider_id,
|
||||
test_keys_.public_test_key_2_2048_bits(),
|
||||
&encrypted_client_id);
|
||||
ClientIdentification decrypted_client_id;
|
||||
EXPECT_EQ(SERVICE_CERTIFICATE_NOT_FOUND,
|
||||
DrmServiceCertificate::DecryptClientIdentification(
|
||||
encrypted_client_id, &decrypted_client_id)
|
||||
.error_code());
|
||||
}
|
||||
|
||||
TEST_F(DrmServiceCertificateTest, InvalidEncryptedClientIdentification) {
|
||||
std::string serial_number("serial_number");
|
||||
std::string provider_id("someservice.com");
|
||||
uint32_t creation_time_seconds(1234);
|
||||
|
||||
ASSERT_OK(AddDrmServiceCertificate(serial_number, provider_id,
|
||||
creation_time_seconds));
|
||||
EncryptedClientIdentification encrypted_client_id;
|
||||
EncryptClientIdentification(serial_number, provider_id,
|
||||
test_keys_.public_test_key_2_2048_bits(),
|
||||
&encrypted_client_id);
|
||||
ClientIdentification decrypted_client_id;
|
||||
ASSERT_EQ(util::OkStatus(),
|
||||
DrmServiceCertificate::DecryptClientIdentification(
|
||||
encrypted_client_id, &decrypted_client_id));
|
||||
ASSERT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_,
|
||||
decrypted_client_id));
|
||||
|
||||
EncryptedClientIdentification invalid;
|
||||
invalid = encrypted_client_id;
|
||||
invalid.clear_encrypted_privacy_key();
|
||||
EXPECT_EQ(
|
||||
"Errors::INVALID_ENCRYPTED_CLIENT_IDENTIFICATION: "
|
||||
"missing-encrypted-privacy-key",
|
||||
DrmServiceCertificate::DecryptClientIdentification(invalid,
|
||||
&decrypted_client_id)
|
||||
.ToString());
|
||||
|
||||
invalid = encrypted_client_id;
|
||||
++(*invalid.mutable_encrypted_client_id_iv())[4];
|
||||
EXPECT_NE(util::OkStatus(),
|
||||
DrmServiceCertificate::DecryptClientIdentification(
|
||||
invalid, &decrypted_client_id));
|
||||
|
||||
invalid.clear_encrypted_client_id_iv();
|
||||
EXPECT_EQ(
|
||||
"Errors::INVALID_ENCRYPTED_CLIENT_IDENTIFICATION: "
|
||||
"missing-encrypted-client-id-iv",
|
||||
DrmServiceCertificate::DecryptClientIdentification(invalid,
|
||||
&decrypted_client_id)
|
||||
.ToString());
|
||||
|
||||
invalid = encrypted_client_id;
|
||||
++(*invalid.mutable_encrypted_client_id())[0];
|
||||
EXPECT_NE(util::OkStatus(),
|
||||
DrmServiceCertificate::DecryptClientIdentification(
|
||||
invalid, &decrypted_client_id));
|
||||
|
||||
invalid.clear_encrypted_client_id();
|
||||
EXPECT_EQ(
|
||||
"Errors::INVALID_ENCRYPTED_CLIENT_IDENTIFICATION: "
|
||||
"missing-encrypted-client-id",
|
||||
DrmServiceCertificate::DecryptClientIdentification(invalid,
|
||||
&decrypted_client_id)
|
||||
.ToString());
|
||||
}
|
||||
|
||||
TEST_F(DrmServiceCertificateTest, PrivateKeyDecryptError) {
|
||||
std::string serial_number("serial_number");
|
||||
std::string provider_id("someservice.com");
|
||||
uint32_t creation_time_seconds(1234);
|
||||
|
||||
ASSERT_OK(AddDrmServiceCertificate(serial_number, provider_id,
|
||||
creation_time_seconds));
|
||||
EncryptedClientIdentification encrypted_client_id;
|
||||
EncryptClientIdentification(serial_number, provider_id,
|
||||
test_keys_.public_test_key_2_2048_bits(),
|
||||
&encrypted_client_id);
|
||||
ClientIdentification decrypted_client_id;
|
||||
ASSERT_EQ(util::OkStatus(),
|
||||
DrmServiceCertificate::DecryptClientIdentification(
|
||||
encrypted_client_id, &decrypted_client_id));
|
||||
ASSERT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_,
|
||||
decrypted_client_id));
|
||||
|
||||
EncryptedClientIdentification corrupted;
|
||||
corrupted = encrypted_client_id;
|
||||
++(*corrupted.mutable_encrypted_privacy_key())[20];
|
||||
EXPECT_EQ(
|
||||
"Errors::INVALID_ENCRYPTED_CLIENT_IDENTIFICATION: "
|
||||
"privacy-key-decryption-failed",
|
||||
DrmServiceCertificate::DecryptClientIdentification(corrupted,
|
||||
&decrypted_client_id)
|
||||
.ToString());
|
||||
}
|
||||
|
||||
// TODO(user): Add more unit tests for various fail cases (bad keys having
|
||||
// to do with bad keys and bad certs).
|
||||
|
||||
} // namespace widevine
|
||||
Reference in New Issue
Block a user