131 lines
4.4 KiB
C++
131 lines
4.4 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
// Copyright 2019 Google LLC.
|
|
//
|
|
// This software is licensed under the terms defined in the Widevine Master
|
|
// License Agreement. For a copy of this agreement, please contact
|
|
// widevine-licensing@google.com.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Description:
|
|
// Classes for generating and decrypting the root of trust id which is
|
|
// included in generated DRM Certificates.
|
|
|
|
#include "common/rot_id_generator.h"
|
|
|
|
#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"
|
|
#include "common/rot_id_util.h"
|
|
#include "common/sha_util.h"
|
|
#include "common/status.h"
|
|
#include "protos/public/drm_certificate.pb.h"
|
|
|
|
namespace {
|
|
|
|
constexpr char kRotIdLabel[] = "ROOT_OF_TRUST_ID ENCRYPTION LABEL";
|
|
constexpr int32_t kKeyId = 0;
|
|
|
|
std::string GenerateContext(uint32_t system_id) {
|
|
return absl::StrCat(kRotIdLabel, system_id);
|
|
}
|
|
|
|
} // anonymous namespace
|
|
|
|
namespace widevine {
|
|
|
|
Status RootOfTrustIdGenerator::Generate(uint32_t system_id,
|
|
const std::string& unique_id,
|
|
RootOfTrustId* root_of_trust_id) const {
|
|
CHECK(root_of_trust_id != nullptr) << "root_of_trust_id was null.";
|
|
|
|
if (system_id == 0) {
|
|
return Status(error::INVALID_ARGUMENT, "system id should not be 0.");
|
|
}
|
|
if (unique_id.empty()) {
|
|
return Status(error::INVALID_ARGUMENT,
|
|
"The unique id should not be empty.");
|
|
}
|
|
|
|
root_of_trust_id->set_version(
|
|
widevine::RootOfTrustId::ROOT_OF_TRUST_ID_VERSION_1);
|
|
root_of_trust_id->set_key_id(kKeyId);
|
|
if (!ecies_encryptor_->Encrypt(
|
|
unique_id, GenerateContext(system_id),
|
|
root_of_trust_id->mutable_encrypted_unique_id())) {
|
|
root_of_trust_id->Clear();
|
|
return Status(error::INTERNAL, "Encrypt failed.");
|
|
}
|
|
|
|
std::string unique_id_hash = GenerateUniqueIdHash(unique_id);
|
|
if (unique_id_hash.empty()) {
|
|
root_of_trust_id->Clear();
|
|
return Status(error::INTERNAL, "Could not generate unique id hash.");
|
|
}
|
|
|
|
root_of_trust_id->set_unique_id_hash(GenerateRotIdHash(
|
|
root_of_trust_id->encrypted_unique_id(), system_id, unique_id_hash));
|
|
if (root_of_trust_id->unique_id_hash().empty()) {
|
|
root_of_trust_id->Clear();
|
|
return Status(error::INTERNAL, "Failed to generate revoked id hash.");
|
|
}
|
|
|
|
return OkStatus();
|
|
}
|
|
|
|
std::string RootOfTrustIdGenerator::GenerateUniqueIdHash(
|
|
const std::string& unique_id) const {
|
|
return widevine::GenerateUniqueIdHash(unique_id, wv_shared_salt_);
|
|
}
|
|
|
|
Status RootOfTrustIdDecryptor::DecryptUniqueId(
|
|
uint32_t system_id, const std::string& rot_encrypted_id,
|
|
std::string* unique_id) const {
|
|
CHECK(unique_id != nullptr) << "unique_id was null.";
|
|
if (system_id == 0) {
|
|
return Status(error::INVALID_ARGUMENT, "system id should not be 0.");
|
|
}
|
|
if (rot_encrypted_id.empty()) {
|
|
return Status(error::INVALID_ARGUMENT,
|
|
"The rot_encrypted_id should not be empty.");
|
|
}
|
|
|
|
if (!ecies_decryptor_->Decrypt(rot_encrypted_id, GenerateContext(system_id),
|
|
unique_id)) {
|
|
return Status(error::INTERNAL, "Failed to decrypt rot_encrypted_id");
|
|
}
|
|
|
|
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
|