Files
media_cas_packager_sdk_source/common/drm_service_certificate.cc
2020-07-24 18:17:12 -07:00

317 lines
12 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.
////////////////////////////////////////////////////////////////////////////////
#include "common/drm_service_certificate.h"
#include <map>
#include <memory>
#include <utility>
#include "glog/logging.h"
#include "absl/base/thread_annotations.h"
#include "absl/strings/escaping.h"
#include "absl/synchronization/mutex.h"
#include "util/gtl/map_util.h"
#include "common/aes_cbc_util.h"
#include "common/certificate_type.h"
#include "common/drm_root_certificate.h"
#include "common/error_space.h"
#include "common/rsa_util.h"
#include "protos/public/client_identification.pb.h"
#include "protos/public/drm_certificate.pb.h"
#include "protos/public/errors.pb.h"
#include "protos/public/signed_drm_certificate.pb.h"
namespace widevine {
namespace {
// Class used to hold global service certificate map.
class DrmServiceCertificateMap {
public:
DrmServiceCertificateMap();
~DrmServiceCertificateMap();
DrmServiceCertificateMap(const DrmServiceCertificateMap&) = delete;
DrmServiceCertificateMap& operator=(const DrmServiceCertificateMap&) = delete;
void Reset();
void AddCert(std::unique_ptr<DrmServiceCertificate> new_cert);
void ClearDefaultDrmServiceCertificate();
const DrmServiceCertificate* GetDefaultCert();
const DrmServiceCertificate* GetCertBySerialNumber(
const std::string& serial_number);
const DrmServiceCertificate* GetCertByProvider(
const std::string& provider_id);
static DrmServiceCertificateMap* GetInstance();
private:
absl::Mutex mutex_;
// Certificate serial number to certificate map.
std::map<std::string, std::unique_ptr<DrmServiceCertificate>> map_
ABSL_GUARDED_BY(mutex_);
DrmServiceCertificate* default_cert_ ABSL_GUARDED_BY(mutex_);
};
DrmServiceCertificateMap::DrmServiceCertificateMap() : default_cert_(nullptr) {}
DrmServiceCertificateMap::~DrmServiceCertificateMap() { Reset(); }
void DrmServiceCertificateMap::Reset() {
absl::WriterMutexLock lock(&mutex_);
map_.clear();
default_cert_ = nullptr;
}
void DrmServiceCertificateMap::AddCert(
std::unique_ptr<DrmServiceCertificate> new_cert) {
absl::WriterMutexLock lock(&mutex_);
std::unique_ptr<DrmServiceCertificate>* previous_cert =
gtl::FindOrNull(map_, new_cert->serial_number());
if (previous_cert != nullptr) {
if (default_cert_ == previous_cert->get()) {
default_cert_ = nullptr;
}
}
if (default_cert_ == nullptr) {
default_cert_ = new_cert.get();
}
const std::string& serial_number = new_cert->serial_number();
map_[serial_number] = std::move(new_cert);
}
void DrmServiceCertificateMap::ClearDefaultDrmServiceCertificate() {
absl::WriterMutexLock lock(&mutex_);
default_cert_ = nullptr;
}
const DrmServiceCertificate* DrmServiceCertificateMap::GetDefaultCert() {
absl::ReaderMutexLock lock(&mutex_);
return default_cert_;
}
const DrmServiceCertificate* DrmServiceCertificateMap::GetCertBySerialNumber(
const std::string& serial_number) {
absl::ReaderMutexLock lock(&mutex_);
return map_[serial_number].get();
}
const DrmServiceCertificate* DrmServiceCertificateMap::GetCertByProvider(
const std::string& provider_id) {
absl::ReaderMutexLock lock(&mutex_);
DrmServiceCertificate* provider_drm_cert = nullptr;
for (const auto& drm_cert : map_) {
if (drm_cert.second->provider_id() == provider_id) {
if (provider_drm_cert == nullptr) {
provider_drm_cert = drm_cert.second.get();
} else if (drm_cert.second->creation_time_seconds() >
provider_drm_cert->creation_time_seconds()) {
// Use the newest cert.
provider_drm_cert = drm_cert.second.get();
}
}
}
return provider_drm_cert;
}
DrmServiceCertificateMap* DrmServiceCertificateMap::GetInstance() {
static auto* const kInstance = new DrmServiceCertificateMap();
return kInstance;
}
} // namespace
Status DrmServiceCertificate::AddDrmServiceCertificate(
const DrmRootCertificate* root_drm_cert,
const std::string& service_certificate,
const std::string& service_private_key,
const std::string& service_private_key_passphrase) {
DrmCertificate drm_cert;
Status status =
root_drm_cert->VerifyCertificate(service_certificate, nullptr, &drm_cert);
if (!status.ok()) {
return status;
}
if (drm_cert.type() != DrmCertificate::SERVICE) {
return Status(error_space, INVALID_SERVICE_CERTIFICATE,
"not-service-certificate");
}
if (drm_cert.provider_id().empty()) {
return Status(error_space, INVALID_SERVICE_CERTIFICATE,
"missing-certificate-service-id");
}
std::unique_ptr<RsaPublicKey> public_key(
RsaPublicKey::Create(drm_cert.public_key()));
if (!public_key) {
return Status(error_space, INVALID_SERVICE_CERTIFICATE,
"invalid-certificate-public-key");
}
std::string pkcs1_key;
if (!rsa_util::EncryptedPrivateKeyInfoToRsaPrivateKey(
service_private_key, service_private_key_passphrase, &pkcs1_key)) {
return Status(error_space, INVALID_SERVICE_PRIVATE_KEY,
"key-decryption-failed");
}
std::unique_ptr<RsaPrivateKey> private_key(RsaPrivateKey::Create(pkcs1_key));
if (private_key == nullptr) {
return Status(error_space, INVALID_SERVICE_PRIVATE_KEY,
"invalid-private-key");
}
std::unique_ptr<DrmServiceCertificate> new_cert(new DrmServiceCertificate(
service_certificate, drm_cert.provider_id(), drm_cert.serial_number(),
drm_cert.creation_time_seconds(), std::move(public_key),
std::move(private_key)));
DrmServiceCertificateMap::GetInstance()->AddCert(std::move(new_cert));
return OkStatus();
}
const DrmServiceCertificate*
DrmServiceCertificate::GetDefaultDrmServiceCertificate() {
return DrmServiceCertificateMap::GetInstance()->GetDefaultCert();
}
const DrmServiceCertificate*
DrmServiceCertificate::GetDefaultDrmServiceCertificateOrDie() {
const DrmServiceCertificate* default_cert =
DrmServiceCertificateMap::GetInstance()->GetDefaultCert();
CHECK(default_cert) << "Service Certificate not set!";
return default_cert;
}
const DrmServiceCertificate*
DrmServiceCertificate::GetDrmServiceCertificateBySerialNumber(
const std::string& serial_number) {
return DrmServiceCertificateMap::GetInstance()->GetCertBySerialNumber(
serial_number);
}
const DrmServiceCertificate*
DrmServiceCertificate::GetDrmServiceCertificateByProvider(
const std::string& provider) {
return DrmServiceCertificateMap::GetInstance()->GetCertByProvider(provider);
}
Status DrmServiceCertificate::SetDefaultDrmServiceCertificate(
const DrmRootCertificate* root_drm_cert,
const std::string& service_certificate,
const std::string& service_private_key,
const std::string& service_private_key_passphrase) {
DrmServiceCertificateMap::GetInstance()->ClearDefaultDrmServiceCertificate();
return AddDrmServiceCertificate(root_drm_cert, service_certificate,
service_private_key,
service_private_key_passphrase);
}
Status DrmServiceCertificate::DecryptClientIdentification(
const EncryptedClientIdentification& encrypted_client_id,
ClientIdentification* client_id) {
DCHECK(client_id);
if (encrypted_client_id.service_certificate_serial_number().empty()) {
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-service-certificate-serial-number");
}
if (encrypted_client_id.provider_id().empty()) {
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-service-id");
}
if (encrypted_client_id.encrypted_client_id().empty()) {
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-encrypted-client-id");
}
if (encrypted_client_id.encrypted_client_id_iv().empty()) {
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-encrypted-client-id-iv");
}
if (encrypted_client_id.encrypted_privacy_key().empty()) {
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-encrypted-privacy-key");
}
std::string privacy_key;
std::string provider_id;
const DrmServiceCertificate* cert = GetDrmServiceCertificateBySerialNumber(
encrypted_client_id.service_certificate_serial_number());
if (!cert) {
return Status(
error_space, SERVICE_CERTIFICATE_NOT_FOUND,
"service-certificate-not-found (SN " +
absl::BytesToHexString(
encrypted_client_id.service_certificate_serial_number()) +
")");
}
if (!cert->private_key()->Decrypt(encrypted_client_id.encrypted_privacy_key(),
&privacy_key)) {
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"privacy-key-decryption-failed");
}
if (cert->provider_id() != encrypted_client_id.provider_id()) {
return Status(error_space, SERVICE_CERTIFICATE_NOT_FOUND,
std::string("provider-id-mismatch (") + cert->provider_id() +
" / " + encrypted_client_id.provider_id() + ")");
}
std::string serialized_client_id(crypto_util::DecryptAesCbc(
privacy_key, encrypted_client_id.encrypted_client_id_iv(),
encrypted_client_id.encrypted_client_id()));
if (serialized_client_id.empty()) {
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"client-id-decryption-failed");
}
if (!client_id->ParseFromString(serialized_client_id)) {
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"client-id-parse-failed");
}
return OkStatus();
}
void DrmServiceCertificate::ResetServiceCertificates() {
DrmServiceCertificateMap::GetInstance()->Reset();
}
Status DrmServiceCertificate::ValidateDrmServiceCertificate() {
const DrmServiceCertificate* service_certificate =
GetDefaultDrmServiceCertificate();
if (!service_certificate) {
return Status(error_space, SERVICE_CERTIFICATE_NOT_FOUND,
"drm service certificate is not found.");
}
SignedDrmCertificate signed_cert;
if (!signed_cert.ParseFromString(service_certificate->certificate())) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"signed drm service certificate is failed to parse.");
}
DrmCertificate drm_cert;
if (!drm_cert.ParseFromString(signed_cert.drm_certificate())) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"Drm service certificate is failed to parse.");
}
if (!drm_cert.has_creation_time_seconds()) {
return Status(error_space, INVALID_SERVICE_CERTIFICATE,
"missing certificate creation time");
}
// TODO(user): Check creation_time_seconds field in DrmCertificate and also
// export the absl/time dependency through moe.
return OkStatus();
}
DrmServiceCertificate::DrmServiceCertificate(
const std::string& service_certificate, const std::string& provider_id,
const std::string& serial_number, const uint32_t creation_time_seconds,
std::unique_ptr<RsaPublicKey> public_key,
std::unique_ptr<RsaPrivateKey> private_key)
: certificate_(service_certificate),
provider_id_(provider_id),
serial_number_(serial_number),
creation_time_seconds_(creation_time_seconds),
public_key_(std::move(public_key)),
private_key_(std::move(private_key)) {}
} // namespace widevine