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
This commit is contained in:
committed by
Fred Gylys-Colwell
parent
b7e4b56934
commit
0ee5214b92
@@ -14,12 +14,14 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#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<uint8_t> encrypted_buffer(sizeof(TimeInfo));
|
||||
std::vector<uint8_t> clear_buffer(sizeof(TimeInfo));
|
||||
TimeInfo time_info;
|
||||
memset(&time_info, 0, sizeof(time_info));
|
||||
// Use the device key for encrypt/decrypt.
|
||||
const std::vector<uint8_t>& 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<char*>(&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<uint8_t> 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<uint8_t> 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<char*>(&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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user