[ Merge of http://go/wvgerrit/171310 ] Offline license not found errors are identified by CdmResponseEnum 347 (KEYSET_ID_NOT_FOUND_4). No addition file system information is shared. Checks for file existance use the stat command. The stat call can return error codes from errno.h when the command fails. These are now converted into sub error codes and returned along with the offline license file not found error. This also includes a change to log stat errors other than ENOENT (no such file or directory) as a warning rather than verbose. Bug: 276225520 Test: file_store_unittest, file_utils_unittest, GtsMediaTestCases Change-Id: Ic09d036549582cd65783b49fa96ffefc4bf562c7
397 lines
17 KiB
C++
397 lines
17 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 "disallow_copy_and_assign.h"
|
|
#include "okp_info.h"
|
|
#include "platform.h"
|
|
#include "wv_cdm_types.h"
|
|
|
|
#if defined(UNIT_TEST)
|
|
# include <gtest/gtest_prod.h>
|
|
#endif
|
|
|
|
namespace wvutil {
|
|
class FileSystem;
|
|
}
|
|
|
|
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;
|
|
};
|
|
|
|
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(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,
|
|
const 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_;
|
|
|
|
CORE_DISALLOW_COPY_AND_ASSIGN(DeviceFiles);
|
|
};
|
|
|
|
} // namespace wvcdm
|
|
|
|
#endif // WVCDM_CORE_DEVICE_FILES_H_
|