//////////////////////////////////////////////////////////////////////////////// // 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 #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