396 lines
18 KiB
C++
396 lines
18 KiB
C++
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
|
|
// source code may only be used and distributed under the Widevine License
|
|
// Agreement.
|
|
#ifndef WVCDM_CORE_DEVICE_FILES_H_
|
|
#define WVCDM_CORE_DEVICE_FILES_H_
|
|
|
|
#include <mutex>
|
|
#include <set>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "crypto_wrapped_key.h"
|
|
#include "device_files.pb.h"
|
|
#include "okp_info.h"
|
|
#include "platform.h"
|
|
#include "wv_cdm_types.h"
|
|
#include "wv_class_utils.h"
|
|
|
|
#if defined(UNIT_TEST)
|
|
# include <gtest/gtest_prod.h>
|
|
#endif
|
|
|
|
namespace wvutil {
|
|
class FileSystem;
|
|
} // namespace wvutil
|
|
|
|
namespace wvcdm {
|
|
|
|
class DeviceFiles {
|
|
public:
|
|
typedef enum {
|
|
kCertificateValid,
|
|
kCertificateExpired,
|
|
kCertificateNotFound,
|
|
kCertificateInvalid,
|
|
kCannotHandle,
|
|
} CertificateState;
|
|
|
|
// |kCertificateDefault| includes an expiration time set by the provisioning
|
|
// service. This will replace any legacy certificates, if a forced
|
|
// reprovisioning happens at the client or by the license service.
|
|
// ATSC certificates are unaffected and have an unlimited lifetime.
|
|
typedef enum {
|
|
kCertificateDefault,
|
|
kCertificateLegacy,
|
|
kCertificateAtsc,
|
|
} CertificateType;
|
|
|
|
// All error response codes start with 5000 to avoid overlap with other error
|
|
// spaces.
|
|
enum ResponseType {
|
|
kNoError = NO_ERROR,
|
|
kResponseTypeBase = 5000,
|
|
kObjectNotInitialized = kResponseTypeBase + 1,
|
|
kParameterNull = kResponseTypeBase + 2,
|
|
kBasePathUnavailable = kResponseTypeBase + 3,
|
|
kFileNotFound = kResponseTypeBase + 4,
|
|
kFileOpenFailed = kResponseTypeBase + 5,
|
|
kFileWriteError = kResponseTypeBase + 6,
|
|
kFileReadError = kResponseTypeBase + 7,
|
|
kInvalidFileSize = kResponseTypeBase + 8,
|
|
kHashComputationFailed = kResponseTypeBase + 9,
|
|
kFileHashMismatch = kResponseTypeBase + 10,
|
|
kFileParseError1 = kResponseTypeBase + 11,
|
|
kFileParseError2 = kResponseTypeBase + 12,
|
|
kUnknownLicenseState = kResponseTypeBase + 13,
|
|
kIncorrectFileType = kResponseTypeBase + 14,
|
|
kIncorrectFileVersion = kResponseTypeBase + 15,
|
|
kLicenseNotPresent = kResponseTypeBase + 16,
|
|
kFileNotFoundEAcces = kResponseTypeBase + 17,
|
|
kFileNotFoundEFault = kResponseTypeBase + 18,
|
|
kFileNotFoundELoop = kResponseTypeBase + 19,
|
|
kFileNotFoundENameTooLong = kResponseTypeBase + 20,
|
|
kFileNotFoundENoEnt = kResponseTypeBase + 21,
|
|
kFileNotFoundENoMem = kResponseTypeBase + 22,
|
|
kFileNotFoundENotDir = kResponseTypeBase + 23,
|
|
kFileNotFoundEOverflow = kResponseTypeBase + 24,
|
|
kFileNotFoundOther = kResponseTypeBase + 25,
|
|
};
|
|
|
|
// Converts the different enum types to a human readable C-string for
|
|
// logging.
|
|
static const char* CertificateStateToString(CertificateState state);
|
|
static const char* CertificateTypeToString(CertificateType type);
|
|
static const char* ResponseTypeToString(ResponseType type);
|
|
static ResponseType ErrnoToResponseType(int errno_value);
|
|
|
|
// CdmLicenseData represents all of the data that is stored in CDM
|
|
// license file. License data is uniquely keyed using |key_set_id|.
|
|
struct CdmLicenseData {
|
|
std::string key_set_id;
|
|
CdmOfflineLicenseState state;
|
|
CdmInitData pssh_data;
|
|
// License request / response.
|
|
CdmKeyMessage license_request;
|
|
CdmKeyResponse license;
|
|
// License renewal request / response.
|
|
CdmKeyMessage license_renewal_request;
|
|
CdmKeyResponse license_renewal;
|
|
// License release.
|
|
std::string release_server_url;
|
|
// License times.
|
|
int64_t playback_start_time;
|
|
int64_t last_playback_time;
|
|
int64_t grace_period_end_time;
|
|
// App parameters.
|
|
CdmAppParameterMap app_parameters;
|
|
// Usage entry and index.
|
|
UsageEntry usage_entry;
|
|
UsageEntryIndex usage_entry_index;
|
|
std::string drm_certificate;
|
|
CryptoWrappedKey wrapped_private_key;
|
|
// Exported license data
|
|
std::string exported_license_data;
|
|
};
|
|
|
|
struct CdmUsageData {
|
|
std::string provider_session_token;
|
|
CdmKeyMessage license_request;
|
|
CdmKeyResponse license;
|
|
std::string key_set_id;
|
|
UsageEntry usage_entry;
|
|
UsageEntryIndex usage_entry_index;
|
|
std::string drm_certificate;
|
|
CryptoWrappedKey wrapped_private_key;
|
|
};
|
|
|
|
DeviceFiles() = delete;
|
|
WVCDM_DISALLOW_COPY_AND_MOVE(DeviceFiles);
|
|
DeviceFiles(wvutil::FileSystem*);
|
|
virtual ~DeviceFiles();
|
|
|
|
virtual bool Init(CdmSecurityLevel security_level);
|
|
virtual bool Reset(CdmSecurityLevel security_level) {
|
|
return Init(security_level);
|
|
}
|
|
|
|
// ATSC certificates are installed by the ATSC service. They can be read
|
|
// and used but not written or removed.
|
|
virtual bool StoreCertificate(const std::string& certificate,
|
|
const CryptoWrappedKey& private_key);
|
|
virtual CertificateState RetrieveCertificate(bool atsc_mode_enabled,
|
|
std::string* certificate,
|
|
CryptoWrappedKey* private_key,
|
|
std::string* serial_number,
|
|
uint32_t* system_id);
|
|
// Returns true if a DRM certificate is available.
|
|
virtual bool HasCertificate(bool atsc_mode_enabled);
|
|
// Retrieves the legacy DRM certificate without performing expiry
|
|
// related validation. Use this only when restoring/releasing
|
|
// licenses/usage entries
|
|
virtual bool RetrieveLegacyCertificate(std::string* certificate,
|
|
CryptoWrappedKey* private_key,
|
|
std::string* serial_number,
|
|
uint32_t* system_id);
|
|
virtual bool RemoveCertificate();
|
|
|
|
virtual bool StoreOemCertificate(const std::string& certificate,
|
|
const CryptoWrappedKey& private_key);
|
|
virtual DeviceFiles::CertificateState RetrieveOemCertificate(
|
|
std::string* certificate, CryptoWrappedKey* wrapped_private_key);
|
|
virtual bool HasOemCertificate();
|
|
virtual bool RemoveOemCertificate();
|
|
|
|
virtual bool StoreLicense(const CdmLicenseData& license_data,
|
|
ResponseType* result);
|
|
|
|
virtual bool RetrieveLicense(const std::string& key_set_id,
|
|
CdmLicenseData* license_data,
|
|
ResponseType* result);
|
|
virtual ResponseType StoreAtscLicense(
|
|
const CdmKeySetId& key_set_id,
|
|
const std::string& serialized_license_data);
|
|
|
|
virtual bool DeleteLicense(const std::string& key_set_id);
|
|
virtual bool ListLicenses(std::vector<std::string>* key_set_ids);
|
|
virtual bool DeleteAllFiles();
|
|
virtual bool DeleteAllLicenses();
|
|
virtual bool LicenseExists(const std::string& key_set_id);
|
|
virtual bool ReserveLicenseId(const std::string& key_set_id);
|
|
virtual bool UnreserveLicenseId(const std::string& key_set_id);
|
|
|
|
// Use this method to create a |usage_info_file_name| from an |app_id|
|
|
static std::string GetUsageInfoFileName(const std::string& app_id);
|
|
|
|
// The UsageInfo methods have been revised to use |usage_info_file_name|
|
|
// rather than |app_id| as a parameter. Use the helper method above to
|
|
// translate.
|
|
// OEMCrypto API 13 introduced big usage tables which required
|
|
// migration from usage tables stored by the TEE to usage table
|
|
// header+usage entries stored in unsecured persistent storage. The upgrade
|
|
// required creation of reverse lookup tables (CdmUsageEntryInfo).
|
|
// |app_id| however was hashed and unextractable, and necessitated the
|
|
// switch to |usage_info_file_name|
|
|
virtual bool StoreUsageInfo(
|
|
const std::string& provider_session_token,
|
|
const CdmKeyMessage& key_request, const CdmKeyResponse& key_response,
|
|
const std::string& usage_info_file_name, const std::string& key_set_id,
|
|
const UsageEntry& usage_entry, UsageEntryIndex usage_entry_index,
|
|
const std::string& drm_certificate, const CryptoWrappedKey& wrapped_key);
|
|
|
|
// Retrieve usage identifying information stored on the file system.
|
|
// The caller needs to specify at least one of |ksids| or
|
|
// |provider_session_tokens|
|
|
virtual bool ListUsageIds(const std::string& app_id,
|
|
std::vector<std::string>* ksids,
|
|
std::vector<std::string>* provider_session_tokens);
|
|
|
|
// Get the provider session token for the given key_set_id.
|
|
virtual bool GetProviderSessionToken(const std::string& app_id,
|
|
const std::string& key_set_id,
|
|
std::string* provider_session_token);
|
|
|
|
virtual bool DeleteUsageInfo(const std::string& usage_info_file_name,
|
|
const CdmKeySetId& key_set_id);
|
|
|
|
// Deletes a set of provider sessions from the specified usage info.
|
|
// Sessions removed are based on the provided |key_set_ids|. If
|
|
// there are no remaining sessions associated with the usage info
|
|
// then the file will be deleted; otherwise, the remaining sessions
|
|
// are written back to the usage info file.
|
|
//
|
|
// Args:
|
|
// usage_info_file_name: name of the file containing the usage info
|
|
// message. This name should _not_ be the complete path, just
|
|
// the file name.
|
|
// key_set_ids: The list of key set IDs to be removed from the
|
|
// usage info. Note that any key set ids that are not present
|
|
// in the usage info are silently ignored.
|
|
// Returns:
|
|
// `true` if the file existed, and operations were completed as
|
|
// expected. `false` if the file does not exist or if there is an
|
|
// issue writing the result back to file.
|
|
virtual bool DeleteMultipleUsageInfoByKeySetIds(
|
|
const std::string& usage_info_file_name,
|
|
const std::vector<std::string>& key_set_ids);
|
|
|
|
// Delete usage information from the file system. Puts a list of all the
|
|
// psts that were deleted from the file into |provider_session_tokens|.
|
|
virtual bool DeleteAllUsageInfoForApp(
|
|
const std::string& usage_info_file_name,
|
|
std::vector<std::string>* provider_session_tokens);
|
|
|
|
virtual bool DeleteAllUsageInfo();
|
|
|
|
// Retrieve the usage info entry specified by |provider_session_token|.
|
|
// Returns false if the entry could not be found.
|
|
virtual bool RetrieveUsageInfo(const std::string& usage_info_file_name,
|
|
const std::string& provider_session_token,
|
|
CdmKeyMessage* license_request,
|
|
CdmKeyResponse* license_response,
|
|
UsageEntry* usage_entry,
|
|
UsageEntryIndex* usage_entry_index,
|
|
std::string* drm_certificate,
|
|
CryptoWrappedKey* wrapped_key);
|
|
// Retrieve the usage info entry specified by |key_set_id|.
|
|
// Returns false if the entry could not be found.
|
|
virtual bool RetrieveUsageInfoByKeySetId(
|
|
const std::string& usage_info_file_name, const std::string& key_set_id,
|
|
std::string* provider_session_token, CdmKeyMessage* license_request,
|
|
CdmKeyResponse* license_response, UsageEntry* usage_entry,
|
|
UsageEntryIndex* usage_entry_index, std::string* drm_certificate,
|
|
CryptoWrappedKey* wrapped_key);
|
|
|
|
// These APIs support upgrading from usage tables to usage tabler header +
|
|
// entries introduced in OEMCrypto V13.
|
|
|
|
virtual bool ListUsageInfoFiles(std::vector<std::string>* usage_file_names);
|
|
virtual bool RetrieveUsageInfo(const std::string& usage_info_file_name,
|
|
std::vector<CdmUsageData>* usage_data);
|
|
virtual bool RetrieveUsageInfo(const std::string& usage_info_file_name,
|
|
const std::string& provider_session_token,
|
|
CdmUsageData* usage_data);
|
|
// This method overwrites rather than appends data to the usage file
|
|
virtual bool StoreUsageInfo(const std::string& usage_info_file_name,
|
|
const std::vector<CdmUsageData>& usage_data);
|
|
virtual bool UpdateUsageInfo(const std::string& usage_info_file_name,
|
|
const CdmUsageData& usage_data);
|
|
|
|
virtual bool StoreHlsAttributes(const std::string& key_set_id,
|
|
CdmHlsMethod method,
|
|
const std::vector<uint8_t>& media_segment_iv);
|
|
virtual bool RetrieveHlsAttributes(const std::string& key_set_id,
|
|
CdmHlsMethod* method,
|
|
std::vector<uint8_t>* media_segment_iv);
|
|
virtual bool DeleteHlsAttributes(const std::string& key_set_id);
|
|
|
|
virtual bool StoreUsageTableInfo(
|
|
const UsageTableHeader& usage_table_header,
|
|
const std::vector<CdmUsageEntryInfo>& usage_entry_info_list);
|
|
|
|
// When retrieving usage table information from the file system; any
|
|
// table that has yet to be updated for the LRU attributes will be
|
|
// indicated by |lru_upgrade|.
|
|
virtual bool RetrieveUsageTableInfo(
|
|
UsageTableHeader* usage_table_header,
|
|
std::vector<CdmUsageEntryInfo>* usage_entry_info_list, bool* lru_upgrade);
|
|
|
|
virtual bool DeleteUsageTableInfo();
|
|
|
|
// OTA Keybox Provisioning (OKP) information.
|
|
virtual bool StoreOkpInfo(const okp::SystemFallbackInfo& info);
|
|
virtual bool RetrieveOkpInfo(okp::SystemFallbackInfo* info);
|
|
virtual bool DeleteOkpInfo();
|
|
|
|
private:
|
|
// This method will retrieve the certificate and perform expiry validation
|
|
// appropriate for a given certificate type
|
|
CertificateState RetrieveCertificate(CertificateType certificate_type,
|
|
std::string* certificate,
|
|
CryptoWrappedKey* private_key,
|
|
std::string* serial_number,
|
|
uint32_t* system_id);
|
|
bool HasCertificate(CertificateType certificate_type);
|
|
|
|
// Helpers that wrap the File interface and automatically handle hashing, as
|
|
// well as adding the device files base path to the file name.
|
|
ResponseType StoreFileWithHash(const std::string& name,
|
|
const std::string& serialized_file);
|
|
ResponseType StoreFileRaw(const std::string& name,
|
|
const std::string& serialized_file);
|
|
ResponseType RetrieveHashedFile(const std::string& name,
|
|
video_widevine_client::sdk::File* file);
|
|
bool FileExists(const std::string& name);
|
|
bool ListFiles(std::vector<std::string>* names);
|
|
bool RemoveFile(const std::string& name);
|
|
ssize_t GetFileSize(const std::string& name);
|
|
|
|
static bool GetCertificateFileName(CertificateType certificate_type,
|
|
std::string* certificate_file_name);
|
|
static bool GetOemCertificateFileName(std::string* certificate_file_name);
|
|
|
|
static std::string GetHlsAttributesFileNameExtension();
|
|
static std::string GetLicenseFileNameExtension();
|
|
static std::string GetUsageTableFileName();
|
|
static std::string GetOkpInfoFileName();
|
|
static std::string GetFileNameSafeHash(const std::string& input);
|
|
|
|
#if defined(UNIT_TEST)
|
|
FRIEND_TEST(DeviceFilesSecurityLevelTest, RequestedSecurityLevel);
|
|
FRIEND_TEST(DeviceCertificateTest, ReadCertificate);
|
|
FRIEND_TEST(DeviceFilesStoreTest, StoreLicense);
|
|
FRIEND_TEST(DeviceFilesHlsAttributesTest, Delete);
|
|
FRIEND_TEST(DeviceFilesHlsAttributesTest, Read);
|
|
FRIEND_TEST(DeviceFilesHlsAttributesTest, Store);
|
|
FRIEND_TEST(DeviceFilesTest, AppParametersBackwardCompatibility);
|
|
FRIEND_TEST(DeviceFilesTest, DeleteLicense);
|
|
FRIEND_TEST(DeviceFilesTest, HasCertificateAtsc);
|
|
FRIEND_TEST(DeviceFilesTest, HasCertificateDefault);
|
|
FRIEND_TEST(DeviceFilesTest, HasCertificateLegacy);
|
|
FRIEND_TEST(DeviceFilesTest, HasCertificateNone);
|
|
FRIEND_TEST(DeviceFilesTest, ReserveLicenseIdsDoesNotUseFileSystem);
|
|
FRIEND_TEST(DeviceFilesTest, RetrieveAtscCertificate);
|
|
FRIEND_TEST(DeviceFilesTest, RetrieveAtscCertificateNotFound);
|
|
FRIEND_TEST(DeviceFilesTest, RetrieveCertificateWithoutKeyType);
|
|
FRIEND_TEST(DeviceFilesTest, RetrieveDefaultCertificate);
|
|
FRIEND_TEST(DeviceFilesTest, RetrieveDefaultCertificateNeverExpires);
|
|
FRIEND_TEST(DeviceFilesTest,
|
|
RetrieveLegacyCertificateWithClientExpirationTime);
|
|
FRIEND_TEST(DeviceFilesTest, RetrieveLegacyCertificateWithoutExpirationTime);
|
|
FRIEND_TEST(DeviceFilesTest, RetrieveLicenses);
|
|
FRIEND_TEST(DeviceFilesTest, StoreCertificateInvalidParams);
|
|
FRIEND_TEST(DeviceFilesTest, StoreLicenses);
|
|
FRIEND_TEST(DeviceFilesTest, UpdateLicenseState);
|
|
FRIEND_TEST(DeviceFilesTest, OkpInfo_FileDoesNotExist);
|
|
FRIEND_TEST(DeviceFilesTest, OkpInfo_DeleteFile);
|
|
FRIEND_TEST(DeviceFilesTest, OkpInfo_StoreAndRetrieve);
|
|
FRIEND_TEST(DeviceFilesUsageInfoTest, Delete);
|
|
FRIEND_TEST(DeviceFilesUsageInfoTest, DeleteAll);
|
|
FRIEND_TEST(DeviceFilesUsageInfoTest, Read);
|
|
FRIEND_TEST(DeviceFilesUsageInfoTest, Store);
|
|
FRIEND_TEST(DeviceFilesUsageTableTest, Read);
|
|
FRIEND_TEST(DeviceFilesUsageTableTest, Store);
|
|
FRIEND_TEST(DeviceFilesUsageTableTest, ReadWithoutLruData);
|
|
FRIEND_TEST(RetrieveDefaultCertificateTest, ErrorScenarios);
|
|
FRIEND_TEST(RetrieveLegacyCertificateTest, ErrorScenarios);
|
|
FRIEND_TEST(StoreCertificateTest, DefaultAndLegacy);
|
|
FRIEND_TEST(WvCdmRequestLicenseTest, UnprovisionTest);
|
|
FRIEND_TEST(WvCdmRequestLicenseTest, ForceL3Test);
|
|
FRIEND_TEST(WvCdmRequestLicenseTest, UsageInfoRetryTest);
|
|
FRIEND_TEST(WvCdmRequestLicenseTest, UsageReleaseAllTest);
|
|
FRIEND_TEST(WvCdmUsageInfoTest, UsageInfo);
|
|
FRIEND_TEST(WvCdmUsageTest, WithClientId);
|
|
FRIEND_TEST(WvCdmExtendedDurationTest, UsageOverflowTest);
|
|
#endif
|
|
|
|
static std::set<std::string> reserved_license_ids_;
|
|
static std::mutex reserved_license_ids_mutex_;
|
|
|
|
wvutil::FileSystem* file_system_;
|
|
CdmSecurityLevel security_level_;
|
|
bool initialized_;
|
|
}; // class DeviceFiles
|
|
} // namespace wvcdm
|
|
#endif // WVCDM_CORE_DEVICE_FILES_H_
|