From 0ee5214b929abe663dfe4fbd94b1b2092896bd30 Mon Sep 17 00:00:00 2001 From: Srujan Gaddam Date: Mon, 12 Nov 2018 14:19:56 -0800 Subject: [PATCH] Add rollback-prevention time methods to ref Merge from master branch of Widevine repo of http://go/wvgerrit/66077 Merge from oemcrypto-v15 branch of Widevine repo of http://go/wvgerrit/64562 Bug: b/78357351 b/62058202 addressed issues with the Level 3 OEMCrypto in guarding against rollback. This change does something similar for the ref, so that OEMCrypto vendors have rollback-prevention code they can refer to. Test: linux/ce cdm unit tests Test: tested as part of http://go/ag/5501993 Change-Id: I76128c5def2615ecbdbe94e3af1fec4a025be8c1 --- .../ref/src/oemcrypto_engine_ref.cpp | 101 ++++++++++++++++++ .../oemcrypto/ref/src/oemcrypto_engine_ref.h | 4 + .../ref/src/oemcrypto_old_usage_table_ref.cpp | 15 ++- .../ref/src/oemcrypto_old_usage_table_ref.h | 10 +- .../oemcrypto/ref/src/oemcrypto_session.cpp | 4 +- .../ref/src/oemcrypto_usage_table_ref.cpp | 13 ++- .../ref/src/oemcrypto_usage_table_ref.h | 2 + 7 files changed, 135 insertions(+), 14 deletions(-) diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.cpp b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.cpp index 5606883a..85487581 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.cpp +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.cpp @@ -14,12 +14,14 @@ #include #include +#include #include #include "keys.h" #include "log.h" #include "oemcrypto_key_ref.h" #include "oemcrypto_rsa_key_shared.h" +#include "string_conversions.h" namespace wvoec_ref { @@ -85,6 +87,105 @@ SessionContext* CryptoEngine::FindSession(SessionId sid) { return NULL; } +time_t CryptoEngine::OnlineTime() { + // Use the monotonic clock for times that don't have to be stable across + // device boots. + timespec current_time; + int gettime_result = clock_gettime(CLOCK_MONOTONIC, ¤t_time); + if (gettime_result == 0) { + return current_time.tv_sec; + } else { + // Can't use monotonic clock, use roll back time. + return RollbackCorrectedOfflineTime(); + } +} + +time_t CryptoEngine::RollbackCorrectedOfflineTime() { + struct TimeInfo { + // The max time recorded through this function call. + time_t previous_time; + // If the wall time is rollbacked to before the previous_time, this member + // is updated to reflect the offset. + time_t rollback_offset; + // Pad the struct so that TimeInfo is a multiple of 16. + uint8_t padding[16 - (2 * sizeof(time_t)) % 16]; + }; + + std::vector encrypted_buffer(sizeof(TimeInfo)); + std::vector clear_buffer(sizeof(TimeInfo)); + TimeInfo time_info; + memset(&time_info, 0, sizeof(time_info)); + // Use the device key for encrypt/decrypt. + const std::vector& key = DeviceRootKey(); + + wvcdm::File* file; + std::string path; + // Note: this path is OK for a real implementation, but using security level 1 + // would be better. + // TODO(fredgc, jfore): Address how this property is presented to the ref. + // For now, the path is empty. + /*if (!wvcdm::Properties::GetDeviceFilesBasePath(wvcdm::kSecurityLevelL3, + &path)) { + LOGE("RollbackCorrectedOfflineTime: Unable to get base path"); + }*/ + std::string filename = path + "StoredUsageTime.dat"; + + wvcdm::FileSystem* file_system = file_system_.get(); + if (file_system->Exists(filename)) { + // Load time info from previous call to this function. + file = file_system->Open(filename, wvcdm::FileSystem::kReadOnly); + if (!file) { + LOGE("RollbackCorrectedOfflineTime: File open failed: %s", + filename.c_str()); + return time(NULL); + } + file->Read(reinterpret_cast(&encrypted_buffer[0]), sizeof(TimeInfo)); + file->Close(); + // Decrypt the encrypted TimeInfo buffer. + AES_KEY aes_key; + AES_set_decrypt_key(&key[0], 128, &aes_key); + std::vector iv(wvoec::KEY_IV_SIZE, 0); + AES_cbc_encrypt(&encrypted_buffer[0], &clear_buffer[0], sizeof(TimeInfo), + &aes_key, iv.data(), AES_DECRYPT); + memcpy(&time_info, &clear_buffer[0], sizeof(TimeInfo)); + } + + time_t current_time; + // Add any time offsets in the past to the current time. + current_time = time(NULL) + time_info.rollback_offset; + if (time_info.previous_time > current_time) { + // Time has been rolled back. + // Update the rollback offset. + time_info.rollback_offset += time_info.previous_time - current_time; + // Keep current time at previous recorded time. + current_time = time_info.previous_time; + } + // The new previous_time will either stay the same or move forward. + time_info.previous_time = current_time; + + // Copy updated data and encrypt the buffer. + memcpy(&clear_buffer[0], &time_info, sizeof(TimeInfo)); + AES_KEY aes_key; + AES_set_encrypt_key(&key[0], 128, &aes_key); + std::vector iv(wvoec::KEY_IV_SIZE, 0); + AES_cbc_encrypt(&clear_buffer[0], &encrypted_buffer[0], sizeof(TimeInfo), + &aes_key, iv.data(), AES_ENCRYPT); + + // Write the encrypted buffer to disk. + file = file_system->Open( + filename, wvcdm::FileSystem::kCreate | wvcdm::FileSystem::kTruncate); + if (!file) { + LOGE("RollbackCorrectedOfflineTime: File open failed: %s", + filename.c_str()); + return time(NULL); + } + file->Write(reinterpret_cast(&encrypted_buffer[0]), sizeof(TimeInfo)); + file->Close(); + + // Return time with offset. + return current_time; +} + OEMCrypto_HDCP_Capability CryptoEngine::config_current_hdcp_capability() { return config_local_display_only() ? HDCP_NO_DIGITAL_OUTPUT : HDCP_V1; } diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.h b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.h index 352bb890..e6e0fd7a 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.h +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.h @@ -87,6 +87,10 @@ class CryptoEngine { return kMaxSupportedOEMCryptoSessions; } + time_t OnlineTime(); + + time_t RollbackCorrectedOfflineTime(); + // Returns the HDCP version currently in use. virtual OEMCrypto_HDCP_Capability config_current_hdcp_capability(); diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_old_usage_table_ref.cpp b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_old_usage_table_ref.cpp index 2c19ef1b..93438ebd 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_old_usage_table_ref.cpp +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_old_usage_table_ref.cpp @@ -31,16 +31,21 @@ namespace wvoec_ref { -OldUsageTableEntry::OldUsageTableEntry(const std::vector &pst_hash) +OldUsageTableEntry::OldUsageTableEntry(OldUsageTable *old_usage_table, + const std::vector &pst_hash) : pst_hash_(pst_hash), - time_of_license_received_(time(NULL)), + old_usage_table_(old_usage_table), + time_of_license_received_( + old_usage_table_->ce_->RollbackCorrectedOfflineTime()), time_of_first_decrypt_(0), time_of_last_decrypt_(0), status_(kUnused) {} OldUsageTableEntry::~OldUsageTableEntry() {} -OldUsageTableEntry::OldUsageTableEntry(const OldStoredUsageEntry *buffer) { +OldUsageTableEntry::OldUsageTableEntry(OldUsageTable *old_usage_table, + const OldStoredUsageEntry *buffer) + : old_usage_table_(old_usage_table) { pst_hash_.assign(buffer->pst_hash, buffer->pst_hash + SHA256_DIGEST_LENGTH); time_of_license_received_ = buffer->time_of_license_received; time_of_first_decrypt_ = buffer->time_of_first_decrypt; @@ -157,7 +162,7 @@ OldUsageTable::OldUsageTable(CryptoEngine *ce) { // entries. for (uint64_t i = 0; i < stored_table->count; i++) { OldUsageTableEntry *entry = - new OldUsageTableEntry(&stored_table->entries[i].entry); + new OldUsageTableEntry(this, &stored_table->entries[i].entry); table_[entry->pst_hash()] = entry; } } @@ -188,7 +193,7 @@ OldUsageTableEntry *OldUsageTable::CreateEntry( LOGE("OldUsageTable: Could not compute hash of pst."); return NULL; } - OldUsageTableEntry *entry = new OldUsageTableEntry(pst_hash); + OldUsageTableEntry *entry = new OldUsageTableEntry(this, pst_hash); wvcdm::AutoLock lock(lock_); table_[pst_hash] = entry; return entry; diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_old_usage_table_ref.h b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_old_usage_table_ref.h index 5d1b7a82..1072d9ec 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_old_usage_table_ref.h +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_old_usage_table_ref.h @@ -23,6 +23,7 @@ namespace wvoec_ref { class CryptoEngine; +class OldUsageTable; class UsagetTableEntry; struct OldStoredUsageEntry { @@ -51,13 +52,16 @@ struct OldStoredUsageTable { class OldUsageTableEntry { public: - OldUsageTableEntry(const std::vector &pst_hash); - OldUsageTableEntry(const OldStoredUsageEntry *buffer); + OldUsageTableEntry(OldUsageTable *old_usage_table, + const std::vector &pst_hash); + OldUsageTableEntry(OldUsageTable *old_usage_table, + const OldStoredUsageEntry *buffer); ~OldUsageTableEntry(); const std::vector &pst_hash() const { return pst_hash_; } private: std::vector pst_hash_; + const OldUsageTable *old_usage_table_; int64_t time_of_license_received_; int64_t time_of_first_decrypt_; int64_t time_of_last_decrypt_; @@ -88,6 +92,8 @@ class OldUsageTable { wvcdm::Lock lock_; int64_t generation_; CryptoEngine *ce_; + + friend class OldUsageTableEntry; }; } // namespace wvoec_ref diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.cpp b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.cpp index ba5ef9e6..c14d4043 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.cpp +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.cpp @@ -483,10 +483,10 @@ OEMCryptoResult SessionContext::CheckNonceOrEntry( return OEMCrypto_SUCCESS; } -void SessionContext::StartTimer() { timer_start_ = time(NULL); } +void SessionContext::StartTimer() { timer_start_ = ce_->OnlineTime(); } uint32_t SessionContext::CurrentTimer() { - time_t now = time(NULL); + time_t now = ce_->OnlineTime(); return now - timer_start_; } diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_usage_table_ref.cpp b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_usage_table_ref.cpp index d87fcd6c..21eb7e0c 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_usage_table_ref.cpp +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_usage_table_ref.cpp @@ -71,7 +71,8 @@ OEMCryptoResult UsageTableEntry::SetPST(const uint8_t* pst, size_t pst_length) { data_.pst_length = pst_length; if (!pst || !pst_length) return OEMCrypto_ERROR_INVALID_CONTEXT; memcpy(data_.pst, pst, pst_length); - data_.time_of_license_received = time(NULL); + data_.time_of_license_received = + usage_table_->ce_->RollbackCorrectedOfflineTime(); return OEMCrypto_SUCCESS; } @@ -105,7 +106,8 @@ bool UsageTableEntry::CheckForUse() { recent_decrypt_ = true; if (data_.status == kUnused) { data_.status = kActive; - data_.time_of_first_decrypt = time(NULL); + data_.time_of_first_decrypt = + usage_table_->ce_->RollbackCorrectedOfflineTime(); data_.generation_number++; usage_table_->IncrementGeneration(); } @@ -149,7 +151,7 @@ OEMCryptoResult UsageTableEntry::ReportUsage(const std::vector& pst, return OEMCrypto_ERROR_INVALID_CONTEXT; } wvcdm::Unpacked_PST_Report pst_report(buffer); - int64_t now = time(NULL); + int64_t now = usage_table_->ce_->RollbackCorrectedOfflineTime(); pst_report.set_seconds_since_license_received(now - data_.time_of_license_received); pst_report.set_seconds_since_first_decrypt(now - data_.time_of_first_decrypt); @@ -170,7 +172,8 @@ OEMCryptoResult UsageTableEntry::ReportUsage(const std::vector& pst, void UsageTableEntry::UpdateAndIncrement() { if (recent_decrypt_) { - data_.time_of_last_decrypt = time(NULL); + data_.time_of_last_decrypt = + usage_table_->ce_->RollbackCorrectedOfflineTime(); recent_decrypt_ = false; } data_.generation_number++; @@ -757,7 +760,7 @@ OEMCryptoResult UsageTable::CreateOldUsageEntry( std::vector pstv(pst, pst + pst_length); OldUsageTableEntry* old_entry = old_table_->CreateEntry(pstv); - int64_t now = time(NULL); + int64_t now = ce_->RollbackCorrectedOfflineTime(); old_entry->time_of_license_received_ = now - time_since_license_received; old_entry->time_of_first_decrypt_ = now - time_since_first_decrypt; old_entry->time_of_last_decrypt_ = now - time_since_last_decrypt; diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_usage_table_ref.h b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_usage_table_ref.h index 1e0d9a96..3278852a 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_usage_table_ref.h +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_usage_table_ref.h @@ -129,6 +129,8 @@ class UsageTable { std::vector generation_numbers_; std::vector sessions_; OldUsageTable* old_table_; + + friend class UsageTableEntry; }; } // namespace wvoec_ref