// 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 #include #include #include #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 #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; }; 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* 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* ksids, std::vector* 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& 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* 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* usage_file_names); virtual bool RetrieveUsageInfo(const std::string& usage_info_file_name, std::vector* 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& 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& media_segment_iv); virtual bool RetrieveHlsAttributes(const std::string& key_set_id, CdmHlsMethod* method, std::vector* media_segment_iv); virtual bool DeleteHlsAttributes(const std::string& key_set_id); virtual bool StoreUsageTableInfo( const UsageTableHeader& usage_table_header, const std::vector& 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* 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* 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 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_