------------- Add libcurl to media_cas_packager_sdk. libcurl will later be used by a key fetcher to retrieve entitlement key from License Server using a HTTP request. ------------- Add a function named parsehelper to parse DCSL from the key smith response. ------------- Move wv_cas_key_fetcher to media_cas_packager_sdk so partners can use it request entitlement keys from License Server. ------------- Add pkcs7 write method to x509_cert.cc ------------- Update boringssl_repo to latest in master-with-bazel ------------- Add a TsPacket class to media_cas_packager_sdk to allow the construction of a ECM TS packet in the SDK. ------------- Move InsertEcm() from our internal CAS directory to the media_cas_packager_sdk, to be used to build a ECM TS packet by the SDK. ------------- Add METADATA in common folder ------------- Refactoring of certificate verification into DrmRootCertificate. ------------- Extend the default duration of leaf certificates. ------------- Fix moe_test ------------- Add a new method to WvCasEcm to allow partner to create a TS packet carrying the generated ECM. ------------- Change from SHA1 to SHA256 for Cast certificates ------------- Update crypto mode enumeration to match WV ECM document ------------- Fix the way we set the validity dates ------------- Move exported_root/util/status to common/ to prepare for util::Status migration Also added constructor/operator to copy from/to util::Status. ------------- Add GenerateDCSLrequest function to certificate_util.h. ------------- Fix build break ------------- Allow 'table_id' (in the section header) be specified by caller of SDK method WvCasEcm::GenerateTsPacket(). ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=224535399
265 lines
10 KiB
C++
265 lines
10 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
// 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.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Description:
|
|
// Unit tests for drm_root_certificate.cc
|
|
|
|
#include "common/drm_root_certificate.h"
|
|
|
|
#include <memory>
|
|
|
|
#include "google/protobuf/util/message_differencer.h"
|
|
#include "testing/gmock.h"
|
|
#include "testing/gunit.h"
|
|
#include "common/error_space.h"
|
|
#include "common/rsa_key.h"
|
|
#include "common/rsa_test_keys.h"
|
|
#include "common/test_drm_certificates.h"
|
|
#include "protos/public/drm_certificate.pb.h"
|
|
#include "protos/public/errors.pb.h"
|
|
#include "protos/public/signed_drm_certificate.pb.h"
|
|
|
|
using google::protobuf::util::MessageDifferencer;
|
|
|
|
namespace widevine {
|
|
|
|
TEST(DrmRootCertificateCreateTest, TestCertificate) {
|
|
const std::string kTestCertificateHash(
|
|
"49f917b1bdfed78002a58e799a58e940"
|
|
"1fffaaed9d8d80752782b066757e2c8c");
|
|
std::unique_ptr<DrmRootCertificate> root_cert;
|
|
ASSERT_EQ(util::OkStatus(), DrmRootCertificate::CreateByType(
|
|
kCertificateTypeTesting, &root_cert));
|
|
ASSERT_TRUE(root_cert != nullptr);
|
|
EXPECT_EQ(kTestCertificateHash, root_cert->GetDigest());
|
|
}
|
|
|
|
TEST(DrmRootCertificateCreateTest, DevCertificate) {
|
|
const std::string kDevelopmentCertificateHash(
|
|
"0e25ee95476a770f30b98ac5ef778b3f"
|
|
"137b66c29385b84f547a361b4724b17d");
|
|
std::unique_ptr<DrmRootCertificate> root_cert;
|
|
ASSERT_EQ(util::OkStatus(), DrmRootCertificate::CreateByType(
|
|
kCertificateTypeDevelopment, &root_cert));
|
|
ASSERT_TRUE(root_cert != nullptr);
|
|
EXPECT_EQ(kDevelopmentCertificateHash, root_cert->GetDigest());
|
|
}
|
|
|
|
TEST(DrmRootCertificateCreateTest, ProdCertificate) {
|
|
const std::string kProductionCertificateHash(
|
|
"d62fdabc9286648a81f7d3bedaf2f5a5"
|
|
"27bbad39bc38da034ba98a21569adb9b");
|
|
std::unique_ptr<DrmRootCertificate> root_cert;
|
|
ASSERT_EQ(util::OkStatus(), DrmRootCertificate::CreateByType(
|
|
kCertificateTypeProduction, &root_cert));
|
|
ASSERT_TRUE(root_cert != nullptr);
|
|
EXPECT_EQ(kProductionCertificateHash, root_cert->GetDigest());
|
|
}
|
|
|
|
TEST(DrmRootCertificateTestCertificatesTest, Success) {
|
|
TestDrmCertificates test_certs;
|
|
std::unique_ptr<DrmRootCertificate> root_cert;
|
|
ASSERT_TRUE(
|
|
DrmRootCertificate::CreateByType(kCertificateTypeTesting, &root_cert)
|
|
.ok());
|
|
EXPECT_TRUE(root_cert
|
|
->VerifyCertificate(test_certs.test_root_certificate(),
|
|
nullptr, nullptr)
|
|
.ok());
|
|
EXPECT_TRUE(
|
|
root_cert
|
|
->VerifyCertificate(test_certs.test_intermediate_certificate(),
|
|
nullptr, nullptr)
|
|
.ok());
|
|
EXPECT_TRUE(root_cert
|
|
->VerifyCertificate(test_certs.test_user_device_certificate(),
|
|
nullptr, nullptr)
|
|
.ok());
|
|
EXPECT_TRUE(root_cert
|
|
->VerifyCertificate(test_certs.test_service_certificate(),
|
|
nullptr, nullptr)
|
|
.ok());
|
|
}
|
|
|
|
class DrmRootCertificateTest : public testing::Test {
|
|
protected:
|
|
DrmRootCertificateTest() {
|
|
private_keys_.emplace_back(
|
|
RsaPrivateKey::Create(test_keys_.private_test_key_1_3072_bits()));
|
|
private_keys_.emplace_back(
|
|
RsaPrivateKey::Create(test_keys_.private_test_key_2_2048_bits()));
|
|
private_keys_.emplace_back(
|
|
RsaPrivateKey::Create(test_keys_.private_test_key_3_2048_bits()));
|
|
}
|
|
|
|
void SetUp() override {
|
|
drm_certificates_[0].set_serial_number("level 0");
|
|
drm_certificates_[0].set_creation_time_seconds(0);
|
|
drm_certificates_[0].set_public_key(
|
|
test_keys_.public_test_key_1_3072_bits());
|
|
drm_certificates_[1].set_serial_number("level 1");
|
|
drm_certificates_[1].set_creation_time_seconds(1);
|
|
drm_certificates_[1].set_public_key(
|
|
test_keys_.public_test_key_2_2048_bits());
|
|
drm_certificates_[2].set_serial_number("level 2");
|
|
drm_certificates_[2].set_creation_time_seconds(2);
|
|
drm_certificates_[2].set_public_key(
|
|
test_keys_.public_test_key_3_2048_bits());
|
|
|
|
ASSERT_EQ(util::OkStatus(), DrmRootCertificate::CreateByType(
|
|
kCertificateTypeTesting, &root_cert_));
|
|
}
|
|
|
|
void GenerateSignedDrmCertificate() {
|
|
SignedDrmCertificate* current_sc(&signed_drm_certificate_);
|
|
ASSERT_TRUE(drm_certificates_[2].SerializeToString(
|
|
current_sc->mutable_drm_certificate()));
|
|
ASSERT_TRUE(private_keys_[1]->GenerateSignature(
|
|
current_sc->drm_certificate(), current_sc->mutable_signature()));
|
|
|
|
current_sc = current_sc->mutable_signer();
|
|
ASSERT_TRUE(drm_certificates_[1].SerializeToString(
|
|
current_sc->mutable_drm_certificate()));
|
|
ASSERT_TRUE(private_keys_[0]->GenerateSignature(
|
|
current_sc->drm_certificate(), current_sc->mutable_signature()));
|
|
|
|
current_sc = current_sc->mutable_signer();
|
|
ASSERT_TRUE(drm_certificates_[0].SerializeToString(
|
|
current_sc->mutable_drm_certificate()));
|
|
ASSERT_TRUE(private_keys_[0]->GenerateSignature(
|
|
current_sc->drm_certificate(), current_sc->mutable_signature()));
|
|
}
|
|
|
|
RsaTestKeys test_keys_;
|
|
std::vector<std::unique_ptr<RsaPrivateKey>> private_keys_;
|
|
SignedDrmCertificate signed_drm_certificate_;
|
|
DrmCertificate drm_certificates_[3];
|
|
std::unique_ptr<DrmRootCertificate> root_cert_;
|
|
};
|
|
|
|
TEST_F(DrmRootCertificateTest, SuccessNoOutput) {
|
|
GenerateSignedDrmCertificate();
|
|
ASSERT_EQ(util::OkStatus(),
|
|
root_cert_->VerifyCertificate(
|
|
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
|
}
|
|
|
|
TEST_F(DrmRootCertificateTest, SuccessWithOutput) {
|
|
GenerateSignedDrmCertificate();
|
|
SignedDrmCertificate out_signed_cert;
|
|
DrmCertificate out_cert;
|
|
ASSERT_EQ(util::OkStatus(), root_cert_->VerifyCertificate(
|
|
signed_drm_certificate_.SerializeAsString(),
|
|
&out_signed_cert, &out_cert));
|
|
EXPECT_TRUE(
|
|
MessageDifferencer::Equals(out_signed_cert, signed_drm_certificate_));
|
|
EXPECT_TRUE(MessageDifferencer::Equals(out_cert, drm_certificates_[2]));
|
|
}
|
|
|
|
TEST_F(DrmRootCertificateTest, InvalidSignedDrmCertificate) {
|
|
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
|
"invalid-signed-drm-certificate"),
|
|
root_cert_->VerifyCertificate("pure garbage", nullptr, nullptr));
|
|
}
|
|
|
|
TEST_F(DrmRootCertificateTest, InvalidSignerCertificate) {
|
|
GenerateSignedDrmCertificate();
|
|
signed_drm_certificate_.mutable_signer()->set_drm_certificate("more garbage");
|
|
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
|
"invalid-signer-certificate"),
|
|
root_cert_->VerifyCertificate(
|
|
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
|
}
|
|
|
|
TEST_F(DrmRootCertificateTest, MissingDrmCertificate) {
|
|
GenerateSignedDrmCertificate();
|
|
signed_drm_certificate_.clear_drm_certificate();
|
|
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
|
"invalid-drm-certificate"),
|
|
root_cert_->VerifyCertificate(
|
|
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
|
}
|
|
|
|
TEST_F(DrmRootCertificateTest, InvalidDrmCertificate) {
|
|
GenerateSignedDrmCertificate();
|
|
signed_drm_certificate_.set_drm_certificate("junk");
|
|
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
|
"invalid-drm-certificate"),
|
|
root_cert_->VerifyCertificate(
|
|
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
|
}
|
|
|
|
TEST_F(DrmRootCertificateTest, InvalidPublicKey) {
|
|
drm_certificates_[0].set_public_key("rubbish");
|
|
GenerateSignedDrmCertificate();
|
|
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
|
"invalid-signer-public-key"),
|
|
root_cert_->VerifyCertificate(
|
|
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
|
}
|
|
|
|
TEST_F(DrmRootCertificateTest, MissingPublicKey) {
|
|
drm_certificates_[2].clear_public_key();
|
|
GenerateSignedDrmCertificate();
|
|
EXPECT_EQ(
|
|
util::Status(error_space, INVALID_DRM_CERTIFICATE, "missing-public-key"),
|
|
root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(),
|
|
nullptr, nullptr));
|
|
}
|
|
|
|
TEST_F(DrmRootCertificateTest, MissingCreationTime) {
|
|
drm_certificates_[2].clear_creation_time_seconds();
|
|
GenerateSignedDrmCertificate();
|
|
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
|
"missing-creation-time"),
|
|
root_cert_->VerifyCertificate(
|
|
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
|
}
|
|
|
|
TEST_F(DrmRootCertificateTest, MissingSerialNumber) {
|
|
drm_certificates_[2].set_serial_number("");
|
|
GenerateSignedDrmCertificate();
|
|
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
|
|
"missing-serial-number"),
|
|
root_cert_->VerifyCertificate(
|
|
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
|
}
|
|
|
|
TEST_F(DrmRootCertificateTest, InvalidSignatureWithNoCache) {
|
|
GenerateSignedDrmCertificate();
|
|
signed_drm_certificate_.mutable_signer()->set_signature(
|
|
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
|
|
EXPECT_EQ(util::Status(error_space, INVALID_SIGNATURE,
|
|
"cache-miss-invalid-signature"),
|
|
root_cert_->VerifyCertificate(
|
|
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
|
}
|
|
|
|
TEST_F(DrmRootCertificateTest, InvalidSignatureWithCache) {
|
|
GenerateSignedDrmCertificate();
|
|
// Verify and cache.
|
|
ASSERT_EQ(util::OkStatus(),
|
|
root_cert_->VerifyCertificate(
|
|
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
|
|
|
// Verify success using cache.
|
|
ASSERT_EQ(util::OkStatus(),
|
|
root_cert_->VerifyCertificate(
|
|
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
|
|
|
|
// Verify failure using cache.
|
|
signed_drm_certificate_.mutable_signer()->set_signature(
|
|
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
|
|
EXPECT_EQ(
|
|
util::Status(error_space, INVALID_SIGNATURE, "cached-signature-mismatch"),
|
|
root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(),
|
|
nullptr, nullptr));
|
|
}
|
|
|
|
} // namespace widevine
|