Merge changes I4e4a6a01,I4e360ea5,I6e08e76f
* changes: Refactor OEMCrypto Engine Add Shared License bit to key control block Reference Code for Big Usage Tables
This commit is contained in:
committed by
Android (Google) Code Review
commit
a118988ecf
@@ -4,6 +4,7 @@ include $(CLEAR_VARS)
|
|||||||
|
|
||||||
LOCAL_SRC_FILES:= \
|
LOCAL_SRC_FILES:= \
|
||||||
src/keys.cpp \
|
src/keys.cpp \
|
||||||
|
src/oemcrypto_auth_mock.cpp \
|
||||||
src/oemcrypto_engine_device_properties.cpp \
|
src/oemcrypto_engine_device_properties.cpp \
|
||||||
src/oemcrypto_engine_mock.cpp \
|
src/oemcrypto_engine_mock.cpp \
|
||||||
src/oemcrypto_key_mock.cpp \
|
src/oemcrypto_key_mock.cpp \
|
||||||
@@ -11,6 +12,10 @@ LOCAL_SRC_FILES:= \
|
|||||||
src/oemcrypto_keybox_testkey.cpp \
|
src/oemcrypto_keybox_testkey.cpp \
|
||||||
src/oemcrypto_logging.cpp \
|
src/oemcrypto_logging.cpp \
|
||||||
src/oemcrypto_mock.cpp \
|
src/oemcrypto_mock.cpp \
|
||||||
|
src/oemcrypto_nonce_table.cpp \
|
||||||
|
src/oemcrypto_rsa_key_shared.cpp \
|
||||||
|
src/oemcrypto_session.cpp \
|
||||||
|
src/oemcrypto_session_key_table.cpp \
|
||||||
src/oemcrypto_usage_table_mock.cpp \
|
src/oemcrypto_usage_table_mock.cpp \
|
||||||
src/wvcrc.cpp \
|
src/wvcrc.cpp \
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -2,8 +2,8 @@
|
|||||||
//
|
//
|
||||||
// Mock implementation of OEMCrypto APIs
|
// Mock implementation of OEMCrypto APIs
|
||||||
//
|
//
|
||||||
#ifndef OEMCRYPTO_ENGINE_MOCK_H_
|
#ifndef MOCK_OEMCRYPTO_ENGINE_MOCK_H_
|
||||||
#define OEMCRYPTO_ENGINE_MOCK_H_
|
#define MOCK_OEMCRYPTO_ENGINE_MOCK_H_
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
@@ -18,210 +18,14 @@
|
|||||||
#include "oemcrypto_auth_mock.h"
|
#include "oemcrypto_auth_mock.h"
|
||||||
#include "oemcrypto_key_mock.h"
|
#include "oemcrypto_key_mock.h"
|
||||||
#include "oemcrypto_rsa_key_shared.h"
|
#include "oemcrypto_rsa_key_shared.h"
|
||||||
|
#include "oemcrypto_session.h"
|
||||||
|
#include "oemcrypto_usage_table_mock.h"
|
||||||
#include "wv_cdm_types.h"
|
#include "wv_cdm_types.h"
|
||||||
|
|
||||||
namespace wvoec_mock {
|
namespace wvoec_mock {
|
||||||
|
|
||||||
class SessionContext;
|
|
||||||
class CryptoEngine;
|
|
||||||
class UsageTable;
|
|
||||||
class UsageTableEntry;
|
|
||||||
|
|
||||||
typedef uint32_t SessionId;
|
|
||||||
typedef std::map<SessionId, SessionContext*> ActiveSessions;
|
typedef std::map<SessionId, SessionContext*> ActiveSessions;
|
||||||
|
|
||||||
typedef std::vector<uint8_t> KeyId;
|
|
||||||
typedef std::map<KeyId, Key*> KeyMap;
|
|
||||||
|
|
||||||
// SessionKeyTable holds the keys for the current session
|
|
||||||
class SessionKeyTable {
|
|
||||||
public:
|
|
||||||
SessionKeyTable() {}
|
|
||||||
~SessionKeyTable();
|
|
||||||
|
|
||||||
bool Insert(const KeyId key_id, const Key& key_data);
|
|
||||||
Key* Find(const KeyId key_id);
|
|
||||||
void Remove(const KeyId key_id);
|
|
||||||
void UpdateDuration(const KeyControlBlock& control);
|
|
||||||
|
|
||||||
private:
|
|
||||||
KeyMap keys_;
|
|
||||||
|
|
||||||
CORE_DISALLOW_COPY_AND_ASSIGN(SessionKeyTable);
|
|
||||||
};
|
|
||||||
|
|
||||||
class NonceTable {
|
|
||||||
public:
|
|
||||||
static const int kTableSize = 16;
|
|
||||||
NonceTable() {
|
|
||||||
for (int i = 0; i < kTableSize; ++i) {
|
|
||||||
state_[i] = kNTStateInvalid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
~NonceTable() {}
|
|
||||||
void AddNonce(uint32_t nonce);
|
|
||||||
bool CheckNonce(uint32_t nonce);
|
|
||||||
void Flush();
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum NonceTableState {
|
|
||||||
kNTStateInvalid,
|
|
||||||
kNTStateValid,
|
|
||||||
kNTStateFlushPending
|
|
||||||
};
|
|
||||||
NonceTableState state_[kTableSize];
|
|
||||||
uint32_t age_[kTableSize];
|
|
||||||
uint32_t nonces_[kTableSize];
|
|
||||||
};
|
|
||||||
|
|
||||||
class SessionContext {
|
|
||||||
private:
|
|
||||||
SessionContext() {}
|
|
||||||
|
|
||||||
public:
|
|
||||||
SessionContext(CryptoEngine* ce, SessionId sid, const RSA_shared_ptr& rsa_key)
|
|
||||||
: valid_(true),
|
|
||||||
ce_(ce),
|
|
||||||
id_(sid),
|
|
||||||
current_content_key_(NULL),
|
|
||||||
rsa_key_(rsa_key),
|
|
||||||
allowed_schemes_(kSign_RSASSA_PSS),
|
|
||||||
usage_entry_(NULL) {}
|
|
||||||
~SessionContext();
|
|
||||||
|
|
||||||
bool isValid() { return valid_; }
|
|
||||||
|
|
||||||
bool DeriveKeys(const std::vector<uint8_t>& master_key,
|
|
||||||
const std::vector<uint8_t>& mac_context,
|
|
||||||
const std::vector<uint8_t>& enc_context);
|
|
||||||
bool RSADeriveKeys(const std::vector<uint8_t>& enc_session_key,
|
|
||||||
const std::vector<uint8_t>& mac_context,
|
|
||||||
const std::vector<uint8_t>& enc_context);
|
|
||||||
bool GenerateSignature(const uint8_t* message, size_t message_length,
|
|
||||||
uint8_t* signature, size_t* signature_length);
|
|
||||||
size_t RSASignatureSize();
|
|
||||||
OEMCryptoResult GenerateRSASignature(const uint8_t* message,
|
|
||||||
size_t message_length,
|
|
||||||
uint8_t* signature,
|
|
||||||
size_t* signature_length,
|
|
||||||
RSA_Padding_Scheme padding_scheme);
|
|
||||||
bool ValidateMessage(const uint8_t* message, size_t message_length,
|
|
||||||
const uint8_t* signature, size_t signature_length);
|
|
||||||
OEMCryptoResult DecryptCENC(const uint8_t* iv, size_t block_offset,
|
|
||||||
const OEMCrypto_CENCEncryptPatternDesc* pattern,
|
|
||||||
const uint8_t* cipher_data,
|
|
||||||
size_t cipher_data_length, bool is_encrypted,
|
|
||||||
uint8_t* clear_data,
|
|
||||||
OEMCryptoBufferType buffer_type);
|
|
||||||
|
|
||||||
OEMCryptoResult Generic_Encrypt(const uint8_t* in_buffer,
|
|
||||||
size_t buffer_length, const uint8_t* iv,
|
|
||||||
OEMCrypto_Algorithm algorithm,
|
|
||||||
uint8_t* out_buffer);
|
|
||||||
OEMCryptoResult Generic_Decrypt(const uint8_t* in_buffer,
|
|
||||||
size_t buffer_length, const uint8_t* iv,
|
|
||||||
OEMCrypto_Algorithm algorithm,
|
|
||||||
uint8_t* out_buffer);
|
|
||||||
OEMCryptoResult Generic_Sign(const uint8_t* in_buffer, size_t buffer_length,
|
|
||||||
OEMCrypto_Algorithm algorithm,
|
|
||||||
uint8_t* signature, size_t* signature_length);
|
|
||||||
OEMCryptoResult Generic_Verify(const uint8_t* in_buffer, size_t buffer_length,
|
|
||||||
OEMCrypto_Algorithm algorithm,
|
|
||||||
const uint8_t* signature,
|
|
||||||
size_t signature_length);
|
|
||||||
void StartTimer();
|
|
||||||
uint32_t CurrentTimer(); // (seconds).
|
|
||||||
OEMCryptoResult LoadKeys(const uint8_t* message, size_t message_length,
|
|
||||||
const uint8_t* signature, size_t signature_length,
|
|
||||||
const uint8_t* enc_mac_key_iv,
|
|
||||||
const uint8_t* enc_mac_keys, size_t num_keys,
|
|
||||||
const OEMCrypto_KeyObject* key_array,
|
|
||||||
const uint8_t* pst, size_t pst_length);
|
|
||||||
bool InstallKey(const KeyId& key_id, const std::vector<uint8_t>& key_data,
|
|
||||||
const std::vector<uint8_t>& key_data_iv,
|
|
||||||
const std::vector<uint8_t>& key_control,
|
|
||||||
const std::vector<uint8_t>& key_control_iv,
|
|
||||||
const std::vector<uint8_t>& pst, bool ctr_mode);
|
|
||||||
bool InstallRSAEncryptedKey(const uint8_t* encrypted_message_key,
|
|
||||||
size_t encrypted_message_key_length);
|
|
||||||
bool DecryptRSAKey(const uint8_t* enc_rsa_key, size_t enc_rsa_key_length,
|
|
||||||
const uint8_t* wrapped_rsa_key_iv, uint8_t* pkcs8_rsa_key);
|
|
||||||
bool EncryptRSAKey(const uint8_t* pkcs8_rsa_key, size_t enc_rsa_key_length,
|
|
||||||
const uint8_t* enc_rsa_key_iv, uint8_t* enc_rsa_key);
|
|
||||||
bool LoadRSAKey(const uint8_t* pkcs8_rsa_key, size_t rsa_key_length);
|
|
||||||
OEMCryptoResult RefreshKey(const KeyId& key_id,
|
|
||||||
const std::vector<uint8_t>& key_control,
|
|
||||||
const std::vector<uint8_t>& key_control_iv);
|
|
||||||
bool UpdateMacKeys(const std::vector<uint8_t>& mac_keys,
|
|
||||||
const std::vector<uint8_t>& iv);
|
|
||||||
bool QueryKeyControlBlock(const KeyId& key_id, uint32_t* data);
|
|
||||||
OEMCryptoResult SelectContentKey(const KeyId& key_id);
|
|
||||||
const Key* current_content_key(void) { return current_content_key_; }
|
|
||||||
void set_mac_key_server(const std::vector<uint8_t>& mac_key_server) {
|
|
||||||
mac_key_server_ = mac_key_server;
|
|
||||||
}
|
|
||||||
const std::vector<uint8_t>& mac_key_server() { return mac_key_server_; }
|
|
||||||
void set_mac_key_client(const std::vector<uint8_t>& mac_key_client) {
|
|
||||||
mac_key_client_ = mac_key_client;
|
|
||||||
}
|
|
||||||
const std::vector<uint8_t>& mac_key_client() { return mac_key_client_; }
|
|
||||||
|
|
||||||
void set_encryption_key(const std::vector<uint8_t>& enc_key) {
|
|
||||||
encryption_key_ = enc_key;
|
|
||||||
}
|
|
||||||
const std::vector<uint8_t>& encryption_key() { return encryption_key_; }
|
|
||||||
uint32_t allowed_schemes() const { return allowed_schemes_; }
|
|
||||||
|
|
||||||
void AddNonce(uint32_t nonce);
|
|
||||||
bool CheckNonce(uint32_t nonce);
|
|
||||||
void FlushNonces();
|
|
||||||
void ReleaseUsageEntry();
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool DeriveKey(const std::vector<uint8_t>& key,
|
|
||||||
const std::vector<uint8_t>& context, int counter,
|
|
||||||
std::vector<uint8_t>* out);
|
|
||||||
bool DecryptMessage(const std::vector<uint8_t>& key,
|
|
||||||
const std::vector<uint8_t>& iv,
|
|
||||||
const std::vector<uint8_t>& message,
|
|
||||||
std::vector<uint8_t>* decrypted);
|
|
||||||
bool CheckNonceOrEntry(const KeyControlBlock& key_control_block,
|
|
||||||
const std::vector<uint8_t>& pst);
|
|
||||||
bool IsUsageEntryValid();
|
|
||||||
OEMCryptoResult DecryptCBC(const uint8_t* key, const uint8_t* iv,
|
|
||||||
const OEMCrypto_CENCEncryptPatternDesc* pattern,
|
|
||||||
const uint8_t* cipher_data,
|
|
||||||
size_t cipher_data_length, uint8_t* clear_data);
|
|
||||||
OEMCryptoResult PatternDecryptCTR(
|
|
||||||
const uint8_t* key, const uint8_t* iv, size_t block_offset,
|
|
||||||
const OEMCrypto_CENCEncryptPatternDesc* pattern,
|
|
||||||
const uint8_t* cipher_data, size_t cipher_data_length,
|
|
||||||
uint8_t* clear_data);
|
|
||||||
OEMCryptoResult DecryptCTR(const uint8_t* key_u8, const uint8_t* iv,
|
|
||||||
size_t block_offset, const uint8_t* cipher_data,
|
|
||||||
size_t cipher_data_length, uint8_t* clear_data);
|
|
||||||
OEMCryptoResult AllowKeyUse(const std::string& log_string, uint32_t use_type,
|
|
||||||
OEMCryptoBufferType buffer_type);
|
|
||||||
RSA* rsa_key() { return rsa_key_.get(); }
|
|
||||||
|
|
||||||
bool valid_;
|
|
||||||
CryptoEngine* ce_;
|
|
||||||
SessionId id_;
|
|
||||||
std::vector<uint8_t> mac_key_server_;
|
|
||||||
std::vector<uint8_t> mac_key_client_;
|
|
||||||
std::vector<uint8_t> encryption_key_;
|
|
||||||
std::vector<uint8_t> session_key_;
|
|
||||||
const Key* current_content_key_;
|
|
||||||
SessionKeyTable session_keys_;
|
|
||||||
NonceTable nonce_table_;
|
|
||||||
RSA_shared_ptr rsa_key_;
|
|
||||||
uint32_t allowed_schemes_; // for RSA signatures.
|
|
||||||
time_t timer_start_;
|
|
||||||
UsageTableEntry* usage_entry_;
|
|
||||||
|
|
||||||
CORE_DISALLOW_COPY_AND_ASSIGN(SessionContext);
|
|
||||||
};
|
|
||||||
|
|
||||||
class CryptoEngine {
|
class CryptoEngine {
|
||||||
public:
|
public:
|
||||||
CryptoEngine(wvcdm::FileSystem* file_system);
|
CryptoEngine(wvcdm::FileSystem* file_system);
|
||||||
@@ -275,7 +79,7 @@ class CryptoEngine {
|
|||||||
OEMCrypto_HDCP_Capability config_current_hdcp_capability();
|
OEMCrypto_HDCP_Capability config_current_hdcp_capability();
|
||||||
OEMCrypto_HDCP_Capability config_maximum_hdcp_capability();
|
OEMCrypto_HDCP_Capability config_maximum_hdcp_capability();
|
||||||
|
|
||||||
UsageTable* usage_table() { return usage_table_; }
|
UsageTable& usage_table() { return usage_table_; }
|
||||||
wvcdm::FileSystem* file_system() { return file_system_; }
|
wvcdm::FileSystem* file_system() { return file_system_; }
|
||||||
|
|
||||||
bool config_local_display_only();
|
bool config_local_display_only();
|
||||||
@@ -295,11 +99,11 @@ class CryptoEngine {
|
|||||||
AuthenticationRoot root_of_trust_;
|
AuthenticationRoot root_of_trust_;
|
||||||
wvcdm::Lock session_table_lock_;
|
wvcdm::Lock session_table_lock_;
|
||||||
wvcdm::FileSystem* file_system_;
|
wvcdm::FileSystem* file_system_;
|
||||||
UsageTable* usage_table_;
|
UsageTable usage_table_;
|
||||||
|
|
||||||
CORE_DISALLOW_COPY_AND_ASSIGN(CryptoEngine);
|
CORE_DISALLOW_COPY_AND_ASSIGN(CryptoEngine);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace wvoec_mock
|
} // namespace wvoec_mock
|
||||||
|
|
||||||
#endif // OEMCRYPTO_ENGINE_MOCK_H_
|
#endif // MOCK_OEMCRYPTO_ENGINE_MOCK_H_
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ KeyControlBlock::KeyControlBlock(
|
|||||||
LOGD(" nonce: %08X", nonce());
|
LOGD(" nonce: %08X", nonce());
|
||||||
LOGD(" magic: %08X", verification());
|
LOGD(" magic: %08X", verification());
|
||||||
LOGD(" bits: %08X", control_bits());
|
LOGD(" bits: %08X", control_bits());
|
||||||
|
LOGD(" bit kSharedLicense %s.",
|
||||||
|
(control_bits() & kSharedLicense) ? "set" : "unset");
|
||||||
LOGD(" bit kControlSRMVersionRequired %s.",
|
LOGD(" bit kControlSRMVersionRequired %s.",
|
||||||
(control_bits() & kControlSRMVersionRequired) ? "set" : "unset");
|
(control_bits() & kControlSRMVersionRequired) ? "set" : "unset");
|
||||||
LOGD(" bit kControlDisableAnalogOutput %s.",
|
LOGD(" bit kControlDisableAnalogOutput %s.",
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ const uint32_t kControlObserveDataPath = (1<<31);
|
|||||||
const uint32_t kControlObserveHDCP = (1<<30);
|
const uint32_t kControlObserveHDCP = (1<<30);
|
||||||
const uint32_t kControlObserveCGMS = (1<<29);
|
const uint32_t kControlObserveCGMS = (1<<29);
|
||||||
const uint32_t kControlRequireAntiRollbackHardware = (1<<28);
|
const uint32_t kControlRequireAntiRollbackHardware = (1<<28);
|
||||||
|
const uint32_t kSharedLicense = (1<<23);
|
||||||
const uint32_t kControlSRMVersionRequired = (1<<22);
|
const uint32_t kControlSRMVersionRequired = (1<<22);
|
||||||
const uint32_t kControlDisableAnalogOutput = (1<<21);
|
const uint32_t kControlDisableAnalogOutput = (1<<21);
|
||||||
const uint32_t kControlSecurityPatchLevelShift = 15;
|
const uint32_t kControlSecurityPatchLevelShift = 15;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "oemcrypto_engine_mock.h"
|
#include "oemcrypto_engine_mock.h"
|
||||||
#include "oemcrypto_logging.h"
|
#include "oemcrypto_logging.h"
|
||||||
|
#include "oemcrypto_session.h"
|
||||||
#include "oemcrypto_usage_table_mock.h"
|
#include "oemcrypto_usage_table_mock.h"
|
||||||
#include "string_conversions.h"
|
#include "string_conversions.h"
|
||||||
#include "wv_cdm_constants.h"
|
#include "wv_cdm_constants.h"
|
||||||
@@ -45,7 +46,14 @@ extern "C" OEMCryptoResult OEMCrypto_Initialize(void) {
|
|||||||
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
|
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
|
||||||
LOGI("------------------------- OEMCrypto_Initialize(void)\n");
|
LOGI("------------------------- OEMCrypto_Initialize(void)\n");
|
||||||
}
|
}
|
||||||
|
if (crypto_engine) {
|
||||||
|
LOGE("------------------------- Calling Initialize without Terminate\n");
|
||||||
|
if (crypto_engine->Initialized()) {
|
||||||
|
crypto_engine->Terminate();
|
||||||
|
}
|
||||||
|
delete crypto_engine;
|
||||||
|
crypto_engine = NULL;
|
||||||
|
}
|
||||||
// NOTE: This requires a compatible Filesystem implementation.
|
// NOTE: This requires a compatible Filesystem implementation.
|
||||||
wvcdm::FileSystem* fs = new wvcdm::FileSystem();
|
wvcdm::FileSystem* fs = new wvcdm::FileSystem();
|
||||||
crypto_engine = new CryptoEngine(fs);
|
crypto_engine = new CryptoEngine(fs);
|
||||||
@@ -1400,6 +1408,13 @@ extern "C" bool OEMCrypto_IsAntiRollbackHwPresent() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" uint32_t OEMCrypto_SupportedCertificates() {
|
extern "C" uint32_t OEMCrypto_SupportedCertificates() {
|
||||||
|
if (!crypto_engine) {
|
||||||
|
LOGE("OEMCrypto_GetProvisioningMethod: OEMCrypto Not Initialized.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (crypto_engine->config_provisioning_method() == OEMCrypto_DrmCertificate) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return OEMCrypto_Supports_RSA_2048bit | OEMCrypto_Supports_RSA_3072bit |
|
return OEMCrypto_Supports_RSA_2048bit | OEMCrypto_Supports_RSA_3072bit |
|
||||||
OEMCrypto_Supports_RSA_CAST;
|
OEMCrypto_Supports_RSA_CAST;
|
||||||
if (!crypto_engine) {
|
if (!crypto_engine) {
|
||||||
@@ -1575,14 +1590,7 @@ extern "C" OEMCryptoResult OEMCrypto_UpdateUsageTable() {
|
|||||||
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
|
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
|
||||||
LOGI("-- OEMCryptoResult OEMCrypto_UpdateUsageTable();\n");
|
LOGI("-- OEMCryptoResult OEMCrypto_UpdateUsageTable();\n");
|
||||||
}
|
}
|
||||||
if (!crypto_engine) {
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
LOGE("OEMCrypto_UpdateUsageTable: OEMCrypto Not Initialized.");
|
|
||||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
||||||
}
|
|
||||||
if (!crypto_engine->config_supports_usage_table()) {
|
|
||||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
|
||||||
}
|
|
||||||
return crypto_engine->usage_table()->UpdateTable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" OEMCryptoResult OEMCrypto_DeactivateUsageEntry(
|
extern "C" OEMCryptoResult OEMCrypto_DeactivateUsageEntry(
|
||||||
@@ -1600,8 +1608,13 @@ extern "C" OEMCryptoResult OEMCrypto_DeactivateUsageEntry(
|
|||||||
if (!crypto_engine->config_supports_usage_table()) {
|
if (!crypto_engine->config_supports_usage_table()) {
|
||||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||||
|
if (!session_ctx || !session_ctx->isValid()) {
|
||||||
|
LOGE("[OEMCrypto_DeactivateUsageEntry(): ERROR_INVALID_SESSION]");
|
||||||
|
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||||
|
}
|
||||||
std::vector<uint8_t> pstv(pst, pst + pst_length);
|
std::vector<uint8_t> pstv(pst, pst + pst_length);
|
||||||
return crypto_engine->usage_table()->DeactivateEntry(pstv);
|
return session_ctx->DeactivateUsageEntry(pstv);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" OEMCryptoResult OEMCrypto_ReportUsage(OEMCrypto_SESSION session,
|
extern "C" OEMCryptoResult OEMCrypto_ReportUsage(OEMCrypto_SESSION session,
|
||||||
@@ -1622,20 +1635,16 @@ extern "C" OEMCryptoResult OEMCrypto_ReportUsage(OEMCrypto_SESSION session,
|
|||||||
if (!crypto_engine->config_supports_usage_table()) {
|
if (!crypto_engine->config_supports_usage_table()) {
|
||||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
if (!buffer_length) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||||
if (!session_ctx || !session_ctx->isValid()) {
|
if (!session_ctx || !session_ctx->isValid()) {
|
||||||
LOGE("[OEMCrypto_ReportUsage(): ERROR_INVALID_SESSION]");
|
LOGE("[OEMCrypto_ReportUsage(): ERROR_INVALID_SESSION]");
|
||||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||||
}
|
}
|
||||||
std::vector<uint8_t> pstv(pst, pst + pst_length);
|
std::vector<uint8_t> pstv(pst, pst + pst_length);
|
||||||
UsageTableEntry* entry = crypto_engine->usage_table()->FindEntry(pstv);
|
OEMCryptoResult sts = session_ctx->ReportUsage(pstv, buffer, buffer_length);
|
||||||
if (!entry) {
|
|
||||||
LOGE("[OEMCrypto_ReportUsage(): Usage Table Entry not found]");
|
|
||||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
|
||||||
}
|
|
||||||
OEMCryptoResult sts =
|
|
||||||
entry->ReportUsage(session_ctx, pstv, buffer, buffer_length);
|
|
||||||
crypto_engine->usage_table()->UpdateTable();
|
|
||||||
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
|
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
|
||||||
if (wvcdm::g_cutoff >= wvcdm::LOG_VERBOSE) {
|
if (wvcdm::g_cutoff >= wvcdm::LOG_VERBOSE) {
|
||||||
dump_hex("usage buffer", buffer, *buffer_length);
|
dump_hex("usage buffer", buffer, *buffer_length);
|
||||||
@@ -1648,68 +1657,14 @@ extern "C" OEMCryptoResult OEMCrypto_DeleteUsageEntry(
|
|||||||
OEMCrypto_SESSION session, const uint8_t* pst, size_t pst_length,
|
OEMCrypto_SESSION session, const uint8_t* pst, size_t pst_length,
|
||||||
const uint8_t* message, size_t message_length, const uint8_t* signature,
|
const uint8_t* message, size_t message_length, const uint8_t* signature,
|
||||||
size_t signature_length) {
|
size_t signature_length) {
|
||||||
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
|
// TODO(fredgc): delete this.
|
||||||
LOGI("-- OEMCryptoResult OEMCrypto_DeleteUsageEntry(\n");
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
if (wvcdm::g_cutoff >= wvcdm::LOG_VERBOSE) {
|
|
||||||
dump_hex("pst", pst, pst_length);
|
|
||||||
dump_hex("message", message, message_length);
|
|
||||||
dump_hex("signature", signature, signature_length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!crypto_engine) {
|
|
||||||
LOGE("OEMCrypto_DeleteUsageEntry: OEMCrypto Not Initialized.");
|
|
||||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
||||||
}
|
|
||||||
if (!crypto_engine->config_supports_usage_table()) {
|
|
||||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
|
||||||
}
|
|
||||||
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
|
||||||
if (!session_ctx || !session_ctx->isValid()) {
|
|
||||||
LOGE("[OEMCrypto_DeleteUsageEntry(): ERROR_INVALID_SESSION]");
|
|
||||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
|
||||||
}
|
|
||||||
if (message == NULL || message_length == 0 || signature == NULL ||
|
|
||||||
signature_length == 0 || pst == NULL || pst_length == 0) {
|
|
||||||
LOGE("[OEMCrypto_DeleteUsageEntry(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
|
||||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
|
||||||
}
|
|
||||||
if (!RangeCheck(message, message_length, pst, pst_length, false)) {
|
|
||||||
LOGE("[OEMCrypto_DeleteUsageEntry(): range check.]");
|
|
||||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
|
||||||
}
|
|
||||||
// Validate message signature
|
|
||||||
if (!session_ctx->ValidateMessage(message, message_length, signature,
|
|
||||||
signature_length)) {
|
|
||||||
LOGE("[OEMCrypto_DeleteUsageEntry(): OEMCrypto_ERROR_SIGNATURE_FAILURE.]");
|
|
||||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
|
||||||
}
|
|
||||||
std::vector<uint8_t> pstv(pst, pst + pst_length);
|
|
||||||
if (crypto_engine->usage_table()->DeleteEntry(pstv)) {
|
|
||||||
return OEMCrypto_SUCCESS;
|
|
||||||
}
|
|
||||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" OEMCryptoResult OEMCrypto_ForceDeleteUsageEntry(const uint8_t* pst,
|
extern "C" OEMCryptoResult OEMCrypto_ForceDeleteUsageEntry(const uint8_t* pst,
|
||||||
size_t pst_length) {
|
size_t pst_length) {
|
||||||
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
|
// TODO(fredgc): delete this.
|
||||||
LOGI("-- OEMCryptoResult OEMCrypto_ForceDeleteUsageEntry()\n");
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
if (wvcdm::g_cutoff >= wvcdm::LOG_VERBOSE) {
|
|
||||||
dump_hex("pst", pst, pst_length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!crypto_engine) {
|
|
||||||
LOGE("OEMCrypto_ForceDeleteUsageEntry: OEMCrypto Not Initialized.");
|
|
||||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
||||||
}
|
|
||||||
if (!crypto_engine->config_supports_usage_table()) {
|
|
||||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
|
||||||
}
|
|
||||||
std::vector<uint8_t> pstv(pst, pst + pst_length);
|
|
||||||
if (crypto_engine->usage_table()->DeleteEntry(pstv)) {
|
|
||||||
return OEMCrypto_SUCCESS;
|
|
||||||
}
|
|
||||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" OEMCryptoResult OEMCrypto_DeleteOldUsageTable() {
|
extern "C" OEMCryptoResult OEMCrypto_DeleteOldUsageTable() {
|
||||||
@@ -1723,9 +1678,7 @@ extern "C" OEMCryptoResult OEMCrypto_DeleteOldUsageTable() {
|
|||||||
if (!crypto_engine->config_supports_usage_table()) {
|
if (!crypto_engine->config_supports_usage_table()) {
|
||||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
crypto_engine->usage_table()->Clear();
|
return crypto_engine->usage_table().DeleteOldUsageTable();
|
||||||
crypto_engine->usage_table()->UpdateTable();
|
|
||||||
return OEMCrypto_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" bool OEMCrypto_IsSRMUpdateSupported() { return false; }
|
extern "C" bool OEMCrypto_IsSRMUpdateSupported() { return false; }
|
||||||
@@ -1744,48 +1697,183 @@ extern "C" OEMCryptoResult OEMCrypto_RemoveSRM() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" OEMCryptoResult OEMCrypto_CreateUsageTableHeader(
|
extern "C" OEMCryptoResult OEMCrypto_CreateUsageTableHeader(
|
||||||
uint8_t* header_buffer, size_t* header_buffer_length) {
|
uint8_t* header_buffer,
|
||||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
size_t* header_buffer_length) {
|
||||||
|
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
|
||||||
|
LOGI("-- OEMCryptoResult OEMCrypto_CreateUsageTableHeader()\n");
|
||||||
|
}
|
||||||
|
if (!crypto_engine) {
|
||||||
|
LOGE("OEMCrypto_CreateUsageTableHeader: OEMCrypto Not Initialized.");
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
if (!crypto_engine->config_supports_usage_table()) {
|
||||||
|
LOGE("OEMCrypto_CreateUsageTableHeader: Configured without Usage Tables.");
|
||||||
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
return crypto_engine->usage_table()
|
||||||
|
.CreateUsageTableHeader(header_buffer, header_buffer_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" OEMCryptoResult OEMCrypto_LoadUsageTableHeader(
|
extern "C" OEMCryptoResult OEMCrypto_LoadUsageTableHeader(
|
||||||
const uint8_t* buffer, size_t buffer_length) {
|
const uint8_t* buffer, size_t buffer_length) {
|
||||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
|
||||||
|
LOGI("-- OEMCryptoResult OEMCrypto_LoadUsageTableHeader()\n");
|
||||||
|
}
|
||||||
|
if (!crypto_engine) {
|
||||||
|
LOGE("OEMCrypto_LoadUsageTableHeader: OEMCrypto Not Initialized.");
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
if (!crypto_engine->config_supports_usage_table()) {
|
||||||
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
if (!buffer) {
|
||||||
|
LOGE("OEMCrypto_LoadUsageTableHeader: buffer null.");
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
std::vector<uint8_t> bufferv(buffer, buffer + buffer_length);
|
||||||
|
return crypto_engine->usage_table().LoadUsageTableHeader(bufferv);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" OEMCryptoResult OEMCrypto_CreateNewUsageEntry(
|
extern "C" OEMCryptoResult OEMCrypto_CreateNewUsageEntry(
|
||||||
OEMCrypto_SESSION session, uint32_t* usage_entry_number) {
|
OEMCrypto_SESSION session, uint32_t* usage_entry_number) {
|
||||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
|
||||||
|
LOGI("-- OEMCryptoResult OEMCrypto_CreateNewUsageEntry(\n");
|
||||||
|
}
|
||||||
|
if (!crypto_engine) {
|
||||||
|
LOGE("OEMCrypto_CreateNewUsageEntry: OEMCrypto Not Initialized.");
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
if (!crypto_engine->config_supports_usage_table()) {
|
||||||
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||||
|
if (!session_ctx || !session_ctx->isValid()) {
|
||||||
|
LOGE("[OEMCrypto_CreateNewUsageEntry(): ERROR_INVALID_SESSION]");
|
||||||
|
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||||
|
}
|
||||||
|
if (!usage_entry_number) {
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
OEMCryptoResult sts = session_ctx->CreateNewUsageEntry(usage_entry_number);
|
||||||
|
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
|
||||||
|
LOGI("-- usage_entry_number = %d", *usage_entry_number);
|
||||||
|
}
|
||||||
|
return sts;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" OEMCryptoResult OEMCrypto_LoadUsageEntry(OEMCrypto_SESSION session,
|
extern "C" OEMCryptoResult OEMCrypto_LoadUsageEntry(OEMCrypto_SESSION session,
|
||||||
uint32_t index,
|
uint32_t index,
|
||||||
const uint8_t* buffer,
|
const uint8_t* buffer,
|
||||||
size_t buffer_size) {
|
size_t buffer_size) {
|
||||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
|
||||||
|
LOGI("-- OEMCryptoResult OEMCrypto_LoadUsageEntry(\n");
|
||||||
|
}
|
||||||
|
if (!crypto_engine) {
|
||||||
|
LOGE("OEMCrypto_LoadUsageEntry: OEMCrypto Not Initialized.");
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
if (!crypto_engine->config_supports_usage_table()) {
|
||||||
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||||
|
if (!session_ctx || !session_ctx->isValid()) {
|
||||||
|
LOGE("[OEMCrypto_LoadUsageEntry(): ERROR_INVALID_SESSION]");
|
||||||
|
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||||
|
}
|
||||||
|
if (!buffer) {
|
||||||
|
LOGE("[OEMCrypto_LoadUsageEntry(): buffer null]");
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
std::vector<uint8_t> bufferv(buffer, buffer + buffer_size);
|
||||||
|
return session_ctx->LoadUsageEntry(index, bufferv);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" OEMCryptoResult OEMCrypto_UpdateUsageEntry(
|
extern "C" OEMCryptoResult OEMCrypto_UpdateUsageEntry(
|
||||||
OEMCrypto_SESSION session, uint8_t* header_buffer,
|
OEMCrypto_SESSION session, uint8_t* header_buffer,
|
||||||
size_t* header_buffer_length, uint8_t* entry_buffer,
|
size_t* header_buffer_length, uint8_t* entry_buffer,
|
||||||
size_t* entry_buffer_length) {
|
size_t* entry_buffer_length) {
|
||||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
|
||||||
|
LOGI("-- OEMCryptoResult OEMCrypto_UpdateUsageEntry(\n");
|
||||||
|
}
|
||||||
|
if (!crypto_engine) {
|
||||||
|
LOGE("OEMCrypto_UpdateUsageEntry: OEMCrypto Not Initialized.");
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
if (!crypto_engine->config_supports_usage_table()) {
|
||||||
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
if (!header_buffer_length || !entry_buffer_length) {
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||||
|
if (!session_ctx || !session_ctx->isValid()) {
|
||||||
|
LOGE("[OEMCrypto_UpdateUsageEntry(): ERROR_INVALID_SESSION]");
|
||||||
|
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||||
|
}
|
||||||
|
return session_ctx->UpdateUsageEntry(header_buffer, header_buffer_length,
|
||||||
|
entry_buffer, entry_buffer_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" OEMCryptoResult OEMCrypto_ShrinkUsageTableHeader(
|
extern "C" OEMCryptoResult OEMCrypto_ShrinkUsageTableHeader(
|
||||||
uint32_t new_table_size, uint8_t* header_buffer,
|
uint32_t new_table_size, uint8_t* header_buffer,
|
||||||
size_t* header_buffer_length) {
|
size_t* header_buffer_length) {
|
||||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
|
||||||
|
LOGI("-- OEMCryptoResult OEMCrypto_ShrinkUsageTableHeader()\n");
|
||||||
|
}
|
||||||
|
if (!crypto_engine) {
|
||||||
|
LOGE("OEMCrypto_ShrinkUsageTableHeader: OEMCrypto Not Initialized.");
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
if (!crypto_engine->config_supports_usage_table()) {
|
||||||
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
if (!header_buffer) {
|
||||||
|
LOGE("OEMCrypto_ShrinkUsageTableHeader: buffer null.");
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
return crypto_engine->usage_table().ShrinkUsageTableHeader(
|
||||||
|
new_table_size, header_buffer, header_buffer_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" OEMCryptoResult OEMCrypto_MoveEntry(OEMCrypto_SESSION session,
|
extern "C" OEMCryptoResult OEMCrypto_MoveEntry(OEMCrypto_SESSION session,
|
||||||
uint32_t new_index) {
|
uint32_t new_index) {
|
||||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
|
||||||
|
LOGI("-- OEMCryptoResult OEMCrypto_MoveEntry(\n");
|
||||||
|
}
|
||||||
|
if (!crypto_engine) {
|
||||||
|
LOGE("OEMCrypto_MoveEntry: OEMCrypto Not Initialized.");
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
if (!crypto_engine->config_supports_usage_table()) {
|
||||||
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||||
|
if (!session_ctx || !session_ctx->isValid()) {
|
||||||
|
LOGE("[OEMCrypto_MoveEntry(): ERROR_INVALID_SESSION]");
|
||||||
|
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||||
|
}
|
||||||
|
return session_ctx->MoveEntry(new_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" OEMCryptoResult OEMCrypto_CopyOldUsageEntry(
|
extern "C" OEMCryptoResult OEMCrypto_CopyOldUsageEntry(
|
||||||
OEMCrypto_SESSION session, const uint8_t* pst, size_t pst_length) {
|
OEMCrypto_SESSION session, const uint8_t* pst, size_t pst_length) {
|
||||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
|
||||||
|
LOGI("-- OEMCryptoResult OEMCrypto_CopyOldUsageEntry(\n");
|
||||||
|
}
|
||||||
|
if (!crypto_engine) {
|
||||||
|
LOGE("OEMCrypto_CopyOldUsageEntry: OEMCrypto Not Initialized.");
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
if (!crypto_engine->config_supports_usage_table()) {
|
||||||
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||||
|
if (!session_ctx || !session_ctx->isValid()) {
|
||||||
|
LOGE("[OEMCrypto_CopyOldUsageEntry(): ERROR_INVALID_SESSION]");
|
||||||
|
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||||
|
}
|
||||||
|
std::vector<uint8_t> pstv(pst, pst + pst_length);
|
||||||
|
return session_ctx->CopyOldUsageEntry(pstv);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace wvoec_mock
|
} // namespace wvoec_mock
|
||||||
|
|||||||
67
libwvdrmengine/oemcrypto/mock/src/oemcrypto_nonce_table.cpp
Normal file
67
libwvdrmengine/oemcrypto/mock/src/oemcrypto_nonce_table.cpp
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Mock implementation of OEMCrypto APIs
|
||||||
|
//
|
||||||
|
#include "oemcrypto_nonce_table.h"
|
||||||
|
|
||||||
|
namespace wvoec_mock {
|
||||||
|
|
||||||
|
void NonceTable::AddNonce(uint32_t nonce) {
|
||||||
|
int new_slot = -1;
|
||||||
|
int oldest_slot = -1;
|
||||||
|
|
||||||
|
// Flush any nonces that have been checked but not flushed.
|
||||||
|
// After flush, nonces will be either valid or invalid.
|
||||||
|
Flush();
|
||||||
|
|
||||||
|
for (int i = 0; i < kTableSize; ++i) {
|
||||||
|
// Increase age of all valid nonces.
|
||||||
|
if (kNTStateValid == state_[i]) {
|
||||||
|
++age_[i];
|
||||||
|
if (-1 == oldest_slot) {
|
||||||
|
oldest_slot = i;
|
||||||
|
} else {
|
||||||
|
if (age_[i] > age_[oldest_slot]) {
|
||||||
|
oldest_slot = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (-1 == new_slot) {
|
||||||
|
age_[i] = 0;
|
||||||
|
nonces_[i] = nonce;
|
||||||
|
state_[i] = kNTStateValid;
|
||||||
|
new_slot = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (-1 == new_slot) {
|
||||||
|
// reuse oldest
|
||||||
|
// assert (oldest_slot != -1)
|
||||||
|
int i = oldest_slot;
|
||||||
|
age_[i] = 0;
|
||||||
|
nonces_[i] = nonce;
|
||||||
|
state_[i] = kNTStateValid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NonceTable::CheckNonce(uint32_t nonce) {
|
||||||
|
for (int i = 0; i < kTableSize; ++i) {
|
||||||
|
if (kNTStateInvalid != state_[i]) {
|
||||||
|
if (nonce == nonces_[i]) {
|
||||||
|
state_[i] = kNTStateFlushPending;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NonceTable::Flush() {
|
||||||
|
for (int i = 0; i < kTableSize; ++i) {
|
||||||
|
if (kNTStateFlushPending == state_[i]) {
|
||||||
|
state_[i] = kNTStateInvalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace wvoec_mock
|
||||||
38
libwvdrmengine/oemcrypto/mock/src/oemcrypto_nonce_table.h
Normal file
38
libwvdrmengine/oemcrypto/mock/src/oemcrypto_nonce_table.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Mock implementation of OEMCrypto APIs
|
||||||
|
//
|
||||||
|
#ifndef MOCK_OEMCRYPTO_NONCE_TABLE_H_
|
||||||
|
#define MOCK_OEMCRYPTO_NONCE_TABLE_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace wvoec_mock {
|
||||||
|
|
||||||
|
class NonceTable {
|
||||||
|
public:
|
||||||
|
static const int kTableSize = 16;
|
||||||
|
NonceTable() {
|
||||||
|
for (int i = 0; i < kTableSize; ++i) {
|
||||||
|
state_[i] = kNTStateInvalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~NonceTable() {}
|
||||||
|
void AddNonce(uint32_t nonce);
|
||||||
|
bool CheckNonce(uint32_t nonce);
|
||||||
|
void Flush();
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum NonceTableState {
|
||||||
|
kNTStateInvalid,
|
||||||
|
kNTStateValid,
|
||||||
|
kNTStateFlushPending
|
||||||
|
};
|
||||||
|
NonceTableState state_[kTableSize];
|
||||||
|
uint32_t age_[kTableSize];
|
||||||
|
uint32_t nonces_[kTableSize];
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace wvoec_mock
|
||||||
|
|
||||||
|
#endif // MOCK_OEMCRYPTO_NONCE_TABLE_H_
|
||||||
1288
libwvdrmengine/oemcrypto/mock/src/oemcrypto_session.cpp
Normal file
1288
libwvdrmengine/oemcrypto/mock/src/oemcrypto_session.cpp
Normal file
File diff suppressed because it is too large
Load Diff
210
libwvdrmengine/oemcrypto/mock/src/oemcrypto_session.h
Normal file
210
libwvdrmengine/oemcrypto/mock/src/oemcrypto_session.h
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Mock implementation of OEMCrypto APIs
|
||||||
|
//
|
||||||
|
#ifndef MOCK_OEMCRYPTO_SESSION_H_
|
||||||
|
#define MOCK_OEMCRYPTO_SESSION_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <openssl/rsa.h>
|
||||||
|
|
||||||
|
#include "OEMCryptoCENC.h" // Needed for enums only.
|
||||||
|
#include "file_store.h"
|
||||||
|
#include "lock.h"
|
||||||
|
#include "oemcrypto_auth_mock.h"
|
||||||
|
#include "oemcrypto_key_mock.h"
|
||||||
|
#include "oemcrypto_nonce_table.h"
|
||||||
|
#include "oemcrypto_rsa_key_shared.h"
|
||||||
|
#include "oemcrypto_session_key_table.h"
|
||||||
|
#include "oemcrypto_usage_table_mock.h"
|
||||||
|
#include "wv_cdm_types.h"
|
||||||
|
|
||||||
|
namespace wvoec_mock {
|
||||||
|
|
||||||
|
class CryptoEngine;
|
||||||
|
typedef uint32_t SessionId;
|
||||||
|
|
||||||
|
class SessionContext {
|
||||||
|
private:
|
||||||
|
SessionContext() {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
SessionContext(CryptoEngine* ce, SessionId sid, const RSA_shared_ptr& rsa_key)
|
||||||
|
: valid_(true),
|
||||||
|
ce_(ce),
|
||||||
|
id_(sid),
|
||||||
|
current_content_key_(NULL),
|
||||||
|
rsa_key_(rsa_key),
|
||||||
|
allowed_schemes_(kSign_RSASSA_PSS),
|
||||||
|
usage_entry_(NULL),
|
||||||
|
usage_entry_status_(kNoUsageEntry) {}
|
||||||
|
~SessionContext();
|
||||||
|
|
||||||
|
bool isValid() { return valid_; }
|
||||||
|
|
||||||
|
bool DeriveKeys(const std::vector<uint8_t>& master_key,
|
||||||
|
const std::vector<uint8_t>& mac_context,
|
||||||
|
const std::vector<uint8_t>& enc_context);
|
||||||
|
bool RSADeriveKeys(const std::vector<uint8_t>& enc_session_key,
|
||||||
|
const std::vector<uint8_t>& mac_context,
|
||||||
|
const std::vector<uint8_t>& enc_context);
|
||||||
|
bool GenerateSignature(const uint8_t* message, size_t message_length,
|
||||||
|
uint8_t* signature, size_t* signature_length);
|
||||||
|
size_t RSASignatureSize();
|
||||||
|
OEMCryptoResult GenerateRSASignature(const uint8_t* message,
|
||||||
|
size_t message_length,
|
||||||
|
uint8_t* signature,
|
||||||
|
size_t* signature_length,
|
||||||
|
RSA_Padding_Scheme padding_scheme);
|
||||||
|
bool ValidateMessage(const uint8_t* message, size_t message_length,
|
||||||
|
const uint8_t* signature, size_t signature_length);
|
||||||
|
OEMCryptoResult DecryptCENC(const uint8_t* iv, size_t block_offset,
|
||||||
|
const OEMCrypto_CENCEncryptPatternDesc* pattern,
|
||||||
|
const uint8_t* cipher_data,
|
||||||
|
size_t cipher_data_length, bool is_encrypted,
|
||||||
|
uint8_t* clear_data,
|
||||||
|
OEMCryptoBufferType buffer_type);
|
||||||
|
|
||||||
|
OEMCryptoResult Generic_Encrypt(const uint8_t* in_buffer,
|
||||||
|
size_t buffer_length, const uint8_t* iv,
|
||||||
|
OEMCrypto_Algorithm algorithm,
|
||||||
|
uint8_t* out_buffer);
|
||||||
|
OEMCryptoResult Generic_Decrypt(const uint8_t* in_buffer,
|
||||||
|
size_t buffer_length, const uint8_t* iv,
|
||||||
|
OEMCrypto_Algorithm algorithm,
|
||||||
|
uint8_t* out_buffer);
|
||||||
|
OEMCryptoResult Generic_Sign(const uint8_t* in_buffer, size_t buffer_length,
|
||||||
|
OEMCrypto_Algorithm algorithm,
|
||||||
|
uint8_t* signature, size_t* signature_length);
|
||||||
|
OEMCryptoResult Generic_Verify(const uint8_t* in_buffer, size_t buffer_length,
|
||||||
|
OEMCrypto_Algorithm algorithm,
|
||||||
|
const uint8_t* signature,
|
||||||
|
size_t signature_length);
|
||||||
|
void StartTimer();
|
||||||
|
uint32_t CurrentTimer(); // (seconds).
|
||||||
|
OEMCryptoResult LoadKeys(const uint8_t* message, size_t message_length,
|
||||||
|
const uint8_t* signature, size_t signature_length,
|
||||||
|
const uint8_t* enc_mac_key_iv,
|
||||||
|
const uint8_t* enc_mac_keys, size_t num_keys,
|
||||||
|
const OEMCrypto_KeyObject* key_array,
|
||||||
|
const uint8_t* pst, size_t pst_length);
|
||||||
|
OEMCryptoResult InstallKey(const KeyId& key_id,
|
||||||
|
const std::vector<uint8_t>& key_data,
|
||||||
|
const std::vector<uint8_t>& key_data_iv,
|
||||||
|
const std::vector<uint8_t>& key_control,
|
||||||
|
const std::vector<uint8_t>& key_control_iv,
|
||||||
|
bool ctr_mode, bool second_license);
|
||||||
|
bool InstallRSAEncryptedKey(const uint8_t* encrypted_message_key,
|
||||||
|
size_t encrypted_message_key_length);
|
||||||
|
bool DecryptRSAKey(const uint8_t* enc_rsa_key, size_t enc_rsa_key_length,
|
||||||
|
const uint8_t* wrapped_rsa_key_iv, uint8_t* pkcs8_rsa_key);
|
||||||
|
bool EncryptRSAKey(const uint8_t* pkcs8_rsa_key, size_t enc_rsa_key_length,
|
||||||
|
const uint8_t* enc_rsa_key_iv, uint8_t* enc_rsa_key);
|
||||||
|
bool LoadRSAKey(const uint8_t* pkcs8_rsa_key, size_t rsa_key_length);
|
||||||
|
OEMCryptoResult RefreshKey(const KeyId& key_id,
|
||||||
|
const std::vector<uint8_t>& key_control,
|
||||||
|
const std::vector<uint8_t>& key_control_iv);
|
||||||
|
bool UpdateMacKeys(const std::vector<uint8_t>& mac_keys,
|
||||||
|
const std::vector<uint8_t>& iv);
|
||||||
|
bool QueryKeyControlBlock(const KeyId& key_id, uint32_t* data);
|
||||||
|
OEMCryptoResult SelectContentKey(const KeyId& key_id);
|
||||||
|
const Key* current_content_key(void) { return current_content_key_; }
|
||||||
|
void set_mac_key_server(const std::vector<uint8_t>& mac_key_server) {
|
||||||
|
mac_key_server_ = mac_key_server;
|
||||||
|
}
|
||||||
|
const std::vector<uint8_t>& mac_key_server() { return mac_key_server_; }
|
||||||
|
void set_mac_key_client(const std::vector<uint8_t>& mac_key_client) {
|
||||||
|
mac_key_client_ = mac_key_client;
|
||||||
|
}
|
||||||
|
const std::vector<uint8_t>& mac_key_client() { return mac_key_client_; }
|
||||||
|
|
||||||
|
void set_encryption_key(const std::vector<uint8_t>& enc_key) {
|
||||||
|
encryption_key_ = enc_key;
|
||||||
|
}
|
||||||
|
const std::vector<uint8_t>& encryption_key() { return encryption_key_; }
|
||||||
|
uint32_t allowed_schemes() const { return allowed_schemes_; }
|
||||||
|
|
||||||
|
void AddNonce(uint32_t nonce);
|
||||||
|
bool CheckNonce(uint32_t nonce);
|
||||||
|
void FlushNonces();
|
||||||
|
|
||||||
|
OEMCryptoResult CreateNewUsageEntry(uint32_t* usage_entry_number);
|
||||||
|
OEMCryptoResult LoadUsageEntry(uint32_t index,
|
||||||
|
const std::vector<uint8_t>& buffer);
|
||||||
|
OEMCryptoResult UpdateUsageEntry(uint8_t* header_buffer,
|
||||||
|
size_t* header_buffer_length,
|
||||||
|
uint8_t* entry_buffer,
|
||||||
|
size_t* entry_buffer_length);
|
||||||
|
OEMCryptoResult DeactivateUsageEntry(const std::vector<uint8_t>& pst);
|
||||||
|
OEMCryptoResult ReportUsage(const std::vector<uint8_t>& pst, uint8_t* buffer,
|
||||||
|
size_t* buffer_length);
|
||||||
|
OEMCryptoResult MoveEntry(uint32_t new_index);
|
||||||
|
OEMCryptoResult CopyOldUsageEntry(const std::vector<uint8_t>& pst);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool DeriveKey(const std::vector<uint8_t>& key,
|
||||||
|
const std::vector<uint8_t>& context, int counter,
|
||||||
|
std::vector<uint8_t>* out);
|
||||||
|
bool DecryptMessage(const std::vector<uint8_t>& key,
|
||||||
|
const std::vector<uint8_t>& iv,
|
||||||
|
const std::vector<uint8_t>& message,
|
||||||
|
std::vector<uint8_t>* decrypted);
|
||||||
|
// Either verify the nonce or usage entry, as required by the key control
|
||||||
|
// block.
|
||||||
|
OEMCryptoResult CheckNonceOrEntry(const KeyControlBlock& key_control_block);
|
||||||
|
// If there is a usage entry, check that it is not inactive.
|
||||||
|
// It also updates the status of the entry if needed.
|
||||||
|
bool CheckUsageEntry();
|
||||||
|
// Check that the usage entry status is valid for online use.
|
||||||
|
OEMCryptoResult CheckStatusOnline(uint32_t nonce, uint32_t control);
|
||||||
|
// Check that the usage entry status is valid for offline use.
|
||||||
|
OEMCryptoResult CheckStatusOffline(uint32_t nonce, uint32_t control);
|
||||||
|
OEMCryptoResult DecryptCBC(const uint8_t* key, const uint8_t* iv,
|
||||||
|
const OEMCrypto_CENCEncryptPatternDesc* pattern,
|
||||||
|
const uint8_t* cipher_data,
|
||||||
|
size_t cipher_data_length, uint8_t* clear_data);
|
||||||
|
OEMCryptoResult PatternDecryptCTR(
|
||||||
|
const uint8_t* key, const uint8_t* iv, size_t block_offset,
|
||||||
|
const OEMCrypto_CENCEncryptPatternDesc* pattern,
|
||||||
|
const uint8_t* cipher_data, size_t cipher_data_length,
|
||||||
|
uint8_t* clear_data);
|
||||||
|
OEMCryptoResult DecryptCTR(const uint8_t* key_u8, const uint8_t* iv,
|
||||||
|
size_t block_offset, const uint8_t* cipher_data,
|
||||||
|
size_t cipher_data_length, uint8_t* clear_data);
|
||||||
|
// Checks if the key is allowed for the specified type. If there is a usage
|
||||||
|
// entry, it also checks the usage entry.
|
||||||
|
OEMCryptoResult CheckKeyUse(const std::string& log_string, uint32_t use_type,
|
||||||
|
OEMCryptoBufferType buffer_type);
|
||||||
|
RSA* rsa_key() { return rsa_key_.get(); }
|
||||||
|
|
||||||
|
bool valid_;
|
||||||
|
CryptoEngine* ce_;
|
||||||
|
SessionId id_;
|
||||||
|
std::vector<uint8_t> mac_key_server_;
|
||||||
|
std::vector<uint8_t> mac_key_client_;
|
||||||
|
std::vector<uint8_t> encryption_key_;
|
||||||
|
std::vector<uint8_t> session_key_;
|
||||||
|
const Key* current_content_key_;
|
||||||
|
SessionKeyTable session_keys_;
|
||||||
|
NonceTable nonce_table_;
|
||||||
|
RSA_shared_ptr rsa_key_;
|
||||||
|
uint32_t allowed_schemes_; // for RSA signatures.
|
||||||
|
time_t timer_start_;
|
||||||
|
UsageTableEntry* usage_entry_;
|
||||||
|
|
||||||
|
enum UsageEntryStatus {
|
||||||
|
kNoUsageEntry, // No entry loaded for this session.
|
||||||
|
kUsageEntryNew, // After entry was created.
|
||||||
|
kUsageEntryLoaded, // After loading entry or loading keys.
|
||||||
|
};
|
||||||
|
UsageEntryStatus usage_entry_status_;
|
||||||
|
CORE_DISALLOW_COPY_AND_ASSIGN(SessionContext);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace wvoec_mock
|
||||||
|
|
||||||
|
#endif // MOCK_OEMCRYPTO_SESSION_H_
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Mock implementation of OEMCrypto APIs
|
||||||
|
//
|
||||||
|
#include "oemcrypto_session_key_table.h"
|
||||||
|
|
||||||
|
#include "keys.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
namespace wvoec_mock {
|
||||||
|
|
||||||
|
SessionKeyTable::~SessionKeyTable() {
|
||||||
|
for (KeyMap::iterator i = keys_.begin(); i != keys_.end(); ++i) {
|
||||||
|
if (NULL != i->second) {
|
||||||
|
delete i->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SessionKeyTable::Insert(const KeyId key_id, const Key& key_data) {
|
||||||
|
if (keys_.find(key_id) != keys_.end()) return false;
|
||||||
|
keys_[key_id] = new Key(key_data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Key* SessionKeyTable::Find(const KeyId key_id) {
|
||||||
|
if (keys_.find(key_id) == keys_.end()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return keys_[key_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
void SessionKeyTable::Remove(const KeyId key_id) {
|
||||||
|
if (keys_.find(key_id) != keys_.end()) {
|
||||||
|
delete keys_[key_id];
|
||||||
|
keys_.erase(key_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SessionKeyTable::UpdateDuration(const KeyControlBlock& control) {
|
||||||
|
for (KeyMap::iterator it = keys_.begin(); it != keys_.end(); ++it) {
|
||||||
|
it->second->UpdateDuration(control);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace wvoec_mock
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Mock implementation of OEMCrypto APIs
|
||||||
|
//
|
||||||
|
#ifndef MOCK_OEMCRYPTO_SESSION_KEY_TABLE_H_
|
||||||
|
#define MOCK_OEMCRYPTO_SESSION_KEY_TABLE_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "oemcrypto_key_mock.h"
|
||||||
|
#include "wv_cdm_types.h"
|
||||||
|
|
||||||
|
namespace wvoec_mock {
|
||||||
|
|
||||||
|
class SessionContext;
|
||||||
|
class CryptoEngine;
|
||||||
|
class UsageTable;
|
||||||
|
class UsageTableEntry;
|
||||||
|
|
||||||
|
typedef std::vector<uint8_t> KeyId;
|
||||||
|
typedef std::map<KeyId, Key*> KeyMap;
|
||||||
|
|
||||||
|
// SessionKeyTable holds the keys for the current session
|
||||||
|
class SessionKeyTable {
|
||||||
|
public:
|
||||||
|
SessionKeyTable() {}
|
||||||
|
~SessionKeyTable();
|
||||||
|
|
||||||
|
bool Insert(const KeyId key_id, const Key& key_data);
|
||||||
|
Key* Find(const KeyId key_id);
|
||||||
|
void Remove(const KeyId key_id);
|
||||||
|
void UpdateDuration(const KeyControlBlock& control);
|
||||||
|
size_t size() const { return keys_.size(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
KeyMap keys_;
|
||||||
|
|
||||||
|
CORE_DISALLOW_COPY_AND_ASSIGN(SessionKeyTable);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace wvoec_mock
|
||||||
|
|
||||||
|
#endif // MOCK_OEMCRYPTO_SESSION_KEY_TABLE_H_
|
||||||
@@ -24,83 +24,118 @@
|
|||||||
#include "string_conversions.h"
|
#include "string_conversions.h"
|
||||||
#include "wv_cdm_constants.h"
|
#include "wv_cdm_constants.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const size_t kMagicLength = 8;
|
||||||
|
const char* kEntryVerification = "USEENTRY";
|
||||||
|
const char* kHeaderVerification = "USEHEADR";
|
||||||
|
// Offset into a signed block where we start encrypting. We need to
|
||||||
|
// skip the signature and the iv.
|
||||||
|
const size_t kEncryptionOffset = SHA256_DIGEST_LENGTH + SHA256_DIGEST_LENGTH;
|
||||||
|
// A structure that holds an usage entry and its signature.
|
||||||
|
struct SignedEntryBlock {
|
||||||
|
uint8_t signature[SHA256_DIGEST_LENGTH];
|
||||||
|
uint8_t iv[SHA256_DIGEST_LENGTH];
|
||||||
|
uint8_t verification[kMagicLength];
|
||||||
|
wvoec_mock::StoredUsageEntry data;
|
||||||
|
};
|
||||||
|
// This has the data in the header of constant size. There is also an array
|
||||||
|
// of generation numbers.
|
||||||
|
struct SignedHeaderBlock {
|
||||||
|
uint8_t signature[SHA256_DIGEST_LENGTH];
|
||||||
|
uint8_t iv[SHA256_DIGEST_LENGTH];
|
||||||
|
uint8_t verification[kMagicLength];
|
||||||
|
int64_t master_generation;
|
||||||
|
uint64_t count;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
namespace wvoec_mock {
|
namespace wvoec_mock {
|
||||||
|
|
||||||
UsageTableEntry::UsageTableEntry(const std::vector<uint8_t> &pst_hash,
|
UsageTableEntry::UsageTableEntry(UsageTable* table, uint32_t index,
|
||||||
SessionContext *ctx)
|
int64_t generation)
|
||||||
: pst_hash_(pst_hash),
|
: usage_table_(table), recent_decrypt_(false), forbid_report_(true) {
|
||||||
time_of_license_received_(time(NULL)),
|
memset(&data_, 0, sizeof(data_));
|
||||||
time_of_first_decrypt_(0),
|
data_.generation_number = generation;
|
||||||
time_of_last_decrypt_(0),
|
data_.index = index;
|
||||||
status_(kUnused),
|
|
||||||
session_(ctx) {}
|
|
||||||
|
|
||||||
UsageTableEntry::~UsageTableEntry() {
|
|
||||||
if (session_) session_->ReleaseUsageEntry();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UsageTableEntry::UsageTableEntry(const StoredUsageEntry *buffer) {
|
UsageTableEntry::~UsageTableEntry() { usage_table_->ReleaseEntry(data_.index); }
|
||||||
pst_hash_.assign(buffer->pst_hash, buffer->pst_hash + SHA256_DIGEST_LENGTH);
|
|
||||||
time_of_license_received_ = buffer->time_of_license_received;
|
OEMCryptoResult UsageTableEntry::SetPST(const uint8_t* pst, size_t pst_length) {
|
||||||
time_of_first_decrypt_ = buffer->time_of_first_decrypt;
|
if (pst_length > kMaxPSTLength) return OEMCrypto_ERROR_BUFFER_TOO_LARGE;
|
||||||
time_of_last_decrypt_ = buffer->time_of_last_decrypt;
|
data_.pst_length = pst_length;
|
||||||
status_ = buffer->status;
|
if (!pst) return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
mac_key_server_.assign(buffer->mac_key_server,
|
memcpy(data_.pst, pst, pst_length);
|
||||||
buffer->mac_key_server + wvcdm::MAC_KEY_SIZE);
|
data_.time_of_license_received = time(NULL);
|
||||||
mac_key_client_.assign(buffer->mac_key_client,
|
return OEMCrypto_SUCCESS;
|
||||||
buffer->mac_key_client + wvcdm::MAC_KEY_SIZE);
|
|
||||||
session_ = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UsageTableEntry::SaveToBuffer(StoredUsageEntry *buffer) {
|
bool UsageTableEntry::VerifyPST(const uint8_t* pst, size_t pst_length) {
|
||||||
if (pst_hash_.size() != sizeof(buffer->pst_hash)) {
|
if (pst_length > kMaxPSTLength) return false;
|
||||||
LOGE("Coding Error: pst hash has wrong size.");
|
if (data_.pst_length != pst_length) return false;
|
||||||
return;
|
if (!pst) return false;
|
||||||
|
return 0 == memcmp(pst, data_.pst, pst_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UsageTableEntry::VerifyMacKeys(const std::vector<uint8_t>& server,
|
||||||
|
const std::vector<uint8_t>& client) {
|
||||||
|
return (server.size() == wvcdm::MAC_KEY_SIZE) &&
|
||||||
|
(client.size() == wvcdm::MAC_KEY_SIZE) &&
|
||||||
|
(0 == memcmp(&server[0], data_.mac_key_server, wvcdm::MAC_KEY_SIZE)) &&
|
||||||
|
(0 == memcmp(&client[0], data_.mac_key_client, wvcdm::MAC_KEY_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UsageTableEntry::SetMacKeys(const std::vector<uint8_t>& server,
|
||||||
|
const std::vector<uint8_t>& client) {
|
||||||
|
if ((server.size() != wvcdm::MAC_KEY_SIZE) ||
|
||||||
|
(client.size() != wvcdm::MAC_KEY_SIZE))
|
||||||
|
return false;
|
||||||
|
memcpy(data_.mac_key_server, &server[0], wvcdm::MAC_KEY_SIZE);
|
||||||
|
memcpy(data_.mac_key_client, &client[0], wvcdm::MAC_KEY_SIZE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UsageTableEntry::CheckForUse() {
|
||||||
|
if (Inactive()) return false;
|
||||||
|
recent_decrypt_ = true;
|
||||||
|
if (data_.status == kUnused) {
|
||||||
|
data_.status = kActive;
|
||||||
|
data_.time_of_first_decrypt = time(NULL);
|
||||||
|
data_.generation_number++;
|
||||||
|
usage_table_->IncrementGeneration();
|
||||||
}
|
}
|
||||||
memcpy(buffer->pst_hash, &pst_hash_[0], pst_hash_.size());
|
return true;
|
||||||
buffer->time_of_license_received = time_of_license_received_;
|
|
||||||
buffer->time_of_first_decrypt = time_of_first_decrypt_;
|
|
||||||
buffer->time_of_last_decrypt = time_of_last_decrypt_;
|
|
||||||
buffer->status = status_;
|
|
||||||
memcpy(buffer->mac_key_server, &mac_key_server_[0], wvcdm::MAC_KEY_SIZE);
|
|
||||||
memcpy(buffer->mac_key_client, &mac_key_client_[0], wvcdm::MAC_KEY_SIZE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UsageTableEntry::Deactivate() {
|
void UsageTableEntry::Deactivate(const std::vector<uint8_t>& pst) {
|
||||||
if (status_ == kUnused) {
|
if (data_.status == kUnused) {
|
||||||
status_ = kInactiveUnused;
|
data_.status = kInactiveUnused;
|
||||||
} else if (status_ == kActive) {
|
} else if (data_.status == kActive) {
|
||||||
status_ = kInactiveUsed;
|
data_.status = kInactiveUsed;
|
||||||
}
|
|
||||||
if (session_) {
|
|
||||||
session_->ReleaseUsageEntry();
|
|
||||||
session_ = NULL;
|
|
||||||
}
|
}
|
||||||
|
forbid_report_ = false;
|
||||||
|
data_.generation_number++;
|
||||||
|
usage_table_->IncrementGeneration();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UsageTableEntry::UpdateTime() {
|
OEMCryptoResult UsageTableEntry::ReportUsage(const std::vector<uint8_t>& pst,
|
||||||
int64_t now = time(NULL);
|
uint8_t* buffer,
|
||||||
switch (status_) {
|
size_t* buffer_length) {
|
||||||
case kUnused:
|
if (forbid_report_) return OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE;
|
||||||
status_ = kActive;
|
if (recent_decrypt_) return OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE;
|
||||||
time_of_first_decrypt_ = now;
|
if (pst.size() == 0 || pst.size() > kMaxPSTLength ||
|
||||||
time_of_last_decrypt_ = now;
|
pst.size() != data_.pst_length) {
|
||||||
return true;
|
LOGE("ReportUsage: bad pst length = %d, should be %d.",
|
||||||
case kActive:
|
pst.size(), data_.pst_length);
|
||||||
time_of_last_decrypt_ = now;
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
return true;
|
}
|
||||||
case kInactive:
|
if (memcmp(&pst[0], data_.pst, data_.pst_length)) {
|
||||||
case kInactiveUsed:
|
LOGE("ReportUsage: wrong pst %s, should be %s.",
|
||||||
case kInactiveUnused:
|
wvcdm::b2a_hex(pst).c_str(),
|
||||||
return false;
|
wvcdm::HexEncode(data_.pst, data_.pst_length).c_str());
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
OEMCryptoResult UsageTableEntry::ReportUsage(SessionContext *session,
|
|
||||||
const std::vector<uint8_t> &pst,
|
|
||||||
uint8_t *buffer,
|
|
||||||
size_t *buffer_length) {
|
|
||||||
size_t length_needed = wvcdm::Unpacked_PST_Report::report_size(pst.size());
|
size_t length_needed = wvcdm::Unpacked_PST_Report::report_size(pst.size());
|
||||||
if (*buffer_length < length_needed) {
|
if (*buffer_length < length_needed) {
|
||||||
*buffer_length = length_needed;
|
*buffer_length = length_needed;
|
||||||
@@ -112,206 +147,426 @@ OEMCryptoResult UsageTableEntry::ReportUsage(SessionContext *session,
|
|||||||
}
|
}
|
||||||
wvcdm::Unpacked_PST_Report pst_report(buffer);
|
wvcdm::Unpacked_PST_Report pst_report(buffer);
|
||||||
int64_t now = time(NULL);
|
int64_t now = time(NULL);
|
||||||
pst_report.set_seconds_since_license_received(now - time_of_license_received_);
|
pst_report.set_seconds_since_license_received(now -
|
||||||
pst_report.set_seconds_since_first_decrypt(now - time_of_first_decrypt_);
|
data_.time_of_license_received);
|
||||||
pst_report.set_seconds_since_last_decrypt(now - time_of_last_decrypt_);
|
pst_report.set_seconds_since_first_decrypt(now - data_.time_of_first_decrypt);
|
||||||
pst_report.set_status(status_);
|
pst_report.set_seconds_since_last_decrypt(now - data_.time_of_last_decrypt);
|
||||||
|
pst_report.set_status(data_.status);
|
||||||
pst_report.set_clock_security_level(kSecureTimer);
|
pst_report.set_clock_security_level(kSecureTimer);
|
||||||
pst_report.set_pst_length(static_cast<uint8_t>(pst.size()));
|
pst_report.set_pst_length(data_.pst_length);
|
||||||
memcpy(pst_report.pst(), &pst[0], pst.size());
|
memcpy(pst_report.pst(), data_.pst, data_.pst_length);
|
||||||
unsigned int md_len = SHA_DIGEST_LENGTH;
|
unsigned int md_len = SHA_DIGEST_LENGTH;
|
||||||
if (!HMAC(EVP_sha1(), &mac_key_client_[0], mac_key_client_.size(),
|
if (!HMAC(EVP_sha1(), data_.mac_key_client, wvcdm::MAC_KEY_SIZE,
|
||||||
buffer + SHA_DIGEST_LENGTH, length_needed - SHA_DIGEST_LENGTH,
|
buffer + SHA_DIGEST_LENGTH, length_needed - SHA_DIGEST_LENGTH,
|
||||||
pst_report.signature(), &md_len)) {
|
pst_report.signature(), &md_len)) {
|
||||||
LOGE("UsageTableEntry: could not compute signature.");
|
LOGE("ReportUsage: could not compute signature.");
|
||||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
}
|
}
|
||||||
session->set_mac_key_server(mac_key_server_);
|
|
||||||
session->set_mac_key_client(mac_key_client_);
|
|
||||||
|
|
||||||
return OEMCrypto_SUCCESS;
|
return OEMCrypto_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UsageTableEntry::VerifyOrSetMacKeys(const std::vector<uint8_t> &server,
|
void UsageTableEntry::UpdateAndIncrement() {
|
||||||
const std::vector<uint8_t> &client) {
|
if (recent_decrypt_) {
|
||||||
if (mac_key_server_.size() == 0) { // Not set yet, so set it now.
|
data_.time_of_last_decrypt = time(NULL);
|
||||||
mac_key_server_ = server;
|
recent_decrypt_ = false;
|
||||||
mac_key_client_ = client;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return (mac_key_server_ == server && mac_key_client_ == client);
|
|
||||||
}
|
}
|
||||||
|
data_.generation_number++;
|
||||||
|
usage_table_->IncrementGeneration();
|
||||||
|
forbid_report_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
UsageTable::UsageTable(CryptoEngine *ce) {
|
OEMCryptoResult UsageTableEntry::SaveData(CryptoEngine* ce,
|
||||||
ce_ = ce;
|
SessionContext* session,
|
||||||
generation_ = 0;
|
uint8_t* signed_buffer,
|
||||||
table_.clear();
|
size_t buffer_size) {
|
||||||
|
// buffer_size was determined by calling function.
|
||||||
// Load saved table.
|
if (buffer_size != SignedEntrySize()) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
wvcdm::FileSystem *file_system = ce->file_system();
|
std::vector<uint8_t> clear_buffer(buffer_size);
|
||||||
wvcdm::File *file;
|
memset(&clear_buffer[0], 0, buffer_size);
|
||||||
std::string path;
|
memset(signed_buffer, 0, buffer_size);
|
||||||
// Note: this path is OK for a real implementation, but using security level 1
|
SignedEntryBlock* clear =
|
||||||
// would be better.
|
reinterpret_cast<SignedEntryBlock*>(&clear_buffer[0]);
|
||||||
if (!wvcdm::Properties::GetDeviceFilesBasePath(wvcdm::kSecurityLevelL3,
|
SignedEntryBlock* encrypted =
|
||||||
&path)) {
|
reinterpret_cast<SignedEntryBlock*>(signed_buffer);
|
||||||
LOGE("UsageTable: Unable to get base path");
|
clear->data = this->data_; // Copy the current data.
|
||||||
return;
|
memcpy(clear->verification, kEntryVerification, kMagicLength);
|
||||||
}
|
|
||||||
|
|
||||||
std::string filename = path + "UsageTable.dat";
|
|
||||||
if (!file_system->Exists(filename)) {
|
|
||||||
if (LogCategoryEnabled(kLoggingTraceUsageTable)) {
|
|
||||||
LOGI("UsageTable: No saved usage table. Creating new table.");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t file_size = file_system->FileSize(filename);
|
|
||||||
std::vector<uint8_t> encrypted_buffer(file_size);
|
|
||||||
std::vector<uint8_t> buffer(file_size);
|
|
||||||
StoredUsageTable *stored_table =
|
|
||||||
reinterpret_cast<StoredUsageTable *>(&buffer[0]);
|
|
||||||
StoredUsageTable *encrypted_table =
|
|
||||||
reinterpret_cast<StoredUsageTable *>(&encrypted_buffer[0]);
|
|
||||||
|
|
||||||
file = file_system->Open(filename, wvcdm::FileSystem::kReadOnly);
|
|
||||||
if (!file) {
|
|
||||||
LOGE("UsageTable: File open failed: %s", path.c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
file->Read(reinterpret_cast<char *>(&encrypted_buffer[0]), file_size);
|
|
||||||
file->Close();
|
|
||||||
|
|
||||||
// Verify the signature of the usage table file.
|
|
||||||
|
|
||||||
// This should be encrypted and signed with a device specific key.
|
// This should be encrypted and signed with a device specific key.
|
||||||
// For the reference implementation, I'm just going to use the keybox key.
|
// For the reference implementation, I'm just going to use the keybox key.
|
||||||
const bool override_to_real = true;
|
const bool override_to_real = true;
|
||||||
const std::vector<uint8_t> &key = ce_->DeviceRootKey(override_to_real);
|
const std::vector<uint8_t>& key = ce->DeviceRootKey(override_to_real);
|
||||||
|
|
||||||
uint8_t computed_signature[SHA256_DIGEST_LENGTH];
|
// Encrypt the entry.
|
||||||
unsigned int sig_length = sizeof(computed_signature);
|
RAND_bytes(encrypted->iv, wvcdm::KEY_IV_SIZE);
|
||||||
if (!HMAC(EVP_sha256(), &key[0], key.size(),
|
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE]; // working iv buffer.
|
||||||
&encrypted_buffer[SHA256_DIGEST_LENGTH],
|
memcpy(iv_buffer, encrypted->iv, wvcdm::KEY_IV_SIZE);
|
||||||
file_size - SHA256_DIGEST_LENGTH, computed_signature,
|
|
||||||
&sig_length)) {
|
|
||||||
LOGE("UsageTable: Could not recreate signature.");
|
|
||||||
table_.clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (memcmp(encrypted_table->signature, computed_signature, sig_length)) {
|
|
||||||
LOGE("UsageTable: Invalid signature given: %s",
|
|
||||||
wvcdm::HexEncode(&encrypted_buffer[0], sig_length).c_str());
|
|
||||||
LOGE("UsageTable: Invalid signature computed: %s",
|
|
||||||
wvcdm::HexEncode(computed_signature, sig_length).c_str());
|
|
||||||
table_.clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next, decrypt the table.
|
|
||||||
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE];
|
|
||||||
memcpy(iv_buffer, encrypted_table->iv, wvcdm::KEY_IV_SIZE);
|
|
||||||
AES_KEY aes_key;
|
|
||||||
AES_set_decrypt_key(&key[0], 128, &aes_key);
|
|
||||||
AES_cbc_encrypt(&encrypted_buffer[SHA256_DIGEST_LENGTH + wvcdm::KEY_IV_SIZE],
|
|
||||||
&buffer[SHA256_DIGEST_LENGTH + wvcdm::KEY_IV_SIZE],
|
|
||||||
file_size - SHA256_DIGEST_LENGTH - wvcdm::KEY_IV_SIZE,
|
|
||||||
&aes_key, iv_buffer, AES_DECRYPT);
|
|
||||||
|
|
||||||
// Next, read the generation number from a different location.
|
|
||||||
// On a real implementation, you should NOT put the generation number in
|
|
||||||
// a file in user space. It should be stored in secure memory. For the
|
|
||||||
// reference implementation, we'll just pretend this is secure.
|
|
||||||
std::string filename2 = path + "GenerationNumber.dat";
|
|
||||||
file = file_system->Open(filename2, wvcdm::FileSystem::kReadOnly);
|
|
||||||
if (!file) {
|
|
||||||
LOGE("UsageTable: File open failed: %s (clearing table)", path.c_str());
|
|
||||||
generation_ = 0;
|
|
||||||
table_.clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
file->Read(reinterpret_cast<char *>(&generation_), sizeof(int64_t));
|
|
||||||
file->Close();
|
|
||||||
if (stored_table->generation == generation_ + 1) {
|
|
||||||
if (LogCategoryEnabled(kLoggingTraceUsageTable)) {
|
|
||||||
LOGW("UsageTable: File is one generation old. Acceptable rollback.");
|
|
||||||
}
|
|
||||||
} else if (stored_table->generation == generation_ - 1) {
|
|
||||||
if (LogCategoryEnabled(kLoggingTraceUsageTable)) {
|
|
||||||
LOGW("UsageTable: File is one generation new. Acceptable rollback.");
|
|
||||||
}
|
|
||||||
// This might happen if the generation number was rolled back?
|
|
||||||
} else if (stored_table->generation != generation_) {
|
|
||||||
LOGE("UsageTable: Rollback detected. Clearing Usage Table. %lx -> %lx",
|
|
||||||
generation_, stored_table->generation);
|
|
||||||
table_.clear();
|
|
||||||
generation_ = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// At this point, the stored table looks valid. We can load in all the
|
|
||||||
// entries.
|
|
||||||
for (uint64_t i = 0; i < stored_table->count; i++) {
|
|
||||||
UsageTableEntry *entry =
|
|
||||||
new UsageTableEntry(&stored_table->entries[i].entry);
|
|
||||||
table_[entry->pst_hash()] = entry;
|
|
||||||
}
|
|
||||||
if (LogCategoryEnabled(kLoggingTraceUsageTable)) {
|
|
||||||
LOGI("UsageTable: loaded %d entries.", stored_table->count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UsageTable::SaveToFile() {
|
|
||||||
// This is always called by a locking function.
|
|
||||||
// Update the generation number so we can detect rollback.
|
|
||||||
generation_++;
|
|
||||||
// Now save data to the file as seen in the constructor, above.
|
|
||||||
size_t file_size = sizeof(StoredUsageTable) +
|
|
||||||
table_.size() * sizeof(AlignedStoredUsageEntry);
|
|
||||||
std::vector<uint8_t> buffer(file_size);
|
|
||||||
std::vector<uint8_t> encrypted_buffer(file_size);
|
|
||||||
StoredUsageTable *stored_table =
|
|
||||||
reinterpret_cast<StoredUsageTable *>(&buffer[0]);
|
|
||||||
StoredUsageTable *encrypted_table =
|
|
||||||
reinterpret_cast<StoredUsageTable *>(&encrypted_buffer[0]);
|
|
||||||
stored_table->generation = generation_;
|
|
||||||
stored_table->count = 0;
|
|
||||||
for (EntryMap::iterator i = table_.begin(); i != table_.end(); ++i) {
|
|
||||||
UsageTableEntry *entry = i->second;
|
|
||||||
entry->SaveToBuffer(&stored_table->entries[stored_table->count].entry);
|
|
||||||
stored_table->count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This should be encrypted and signed with a device specific key.
|
|
||||||
// For the reference implementation, I'm just going to use the keybox key.
|
|
||||||
const bool override_to_real = true;
|
|
||||||
const std::vector<uint8_t> &key = ce_->DeviceRootKey(override_to_real);
|
|
||||||
|
|
||||||
// Encrypt the table.
|
|
||||||
RAND_bytes(encrypted_table->iv, wvcdm::KEY_IV_SIZE);
|
|
||||||
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE];
|
|
||||||
memcpy(iv_buffer, encrypted_table->iv, wvcdm::KEY_IV_SIZE);
|
|
||||||
AES_KEY aes_key;
|
AES_KEY aes_key;
|
||||||
AES_set_encrypt_key(&key[0], 128, &aes_key);
|
AES_set_encrypt_key(&key[0], 128, &aes_key);
|
||||||
AES_cbc_encrypt(&buffer[SHA256_DIGEST_LENGTH + wvcdm::KEY_IV_SIZE],
|
AES_cbc_encrypt(
|
||||||
&encrypted_buffer[SHA256_DIGEST_LENGTH + wvcdm::KEY_IV_SIZE],
|
&clear_buffer[kEncryptionOffset], &signed_buffer[kEncryptionOffset],
|
||||||
file_size - SHA256_DIGEST_LENGTH - wvcdm::KEY_IV_SIZE,
|
buffer_size - kEncryptionOffset, &aes_key, iv_buffer, AES_ENCRYPT);
|
||||||
&aes_key, iv_buffer, AES_ENCRYPT);
|
|
||||||
|
|
||||||
// Sign the table.
|
// Sign the entry.
|
||||||
unsigned int sig_length = sizeof(stored_table->signature);
|
unsigned int sig_length = SHA256_DIGEST_LENGTH;
|
||||||
if (!HMAC(EVP_sha256(), &key[0], key.size(),
|
if (!HMAC(EVP_sha256(), &key[0], key.size(),
|
||||||
&encrypted_buffer[SHA256_DIGEST_LENGTH],
|
&signed_buffer[SHA256_DIGEST_LENGTH],
|
||||||
file_size - SHA256_DIGEST_LENGTH, encrypted_table->signature,
|
buffer_size - SHA256_DIGEST_LENGTH, encrypted->signature,
|
||||||
&sig_length)) {
|
&sig_length)) {
|
||||||
LOGE("UsageTable: Could not sign table.");
|
LOGE("SaveUsageEntry: Could not sign entry.");
|
||||||
return false;
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult UsageTableEntry::LoadData(CryptoEngine* ce, uint32_t index,
|
||||||
|
const std::vector<uint8_t>& buffer) {
|
||||||
|
if (buffer.size() < SignedEntrySize()) return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||||
|
if (buffer.size() > SignedEntrySize())
|
||||||
|
LOGW("LoadUsageTableEntry: buffer is large. %d > %d", buffer.size(),
|
||||||
|
SignedEntrySize());
|
||||||
|
std::vector<uint8_t> clear_buffer(buffer.size());
|
||||||
|
SignedEntryBlock* clear =
|
||||||
|
reinterpret_cast<SignedEntryBlock*>(&clear_buffer[0]);
|
||||||
|
const SignedEntryBlock* encrypted =
|
||||||
|
reinterpret_cast<const SignedEntryBlock*>(&buffer[0]);
|
||||||
|
|
||||||
|
// This should be encrypted and signed with a device specific key.
|
||||||
|
// For the reference implementation, I'm just going to use the keybox key.
|
||||||
|
const bool override_to_real = true;
|
||||||
|
const std::vector<uint8_t>& key = ce->DeviceRootKey(override_to_real);
|
||||||
|
|
||||||
|
// Verify the signature of the usage entry. Sign encrypted into clear buffer.
|
||||||
|
unsigned int sig_length = SHA256_DIGEST_LENGTH;
|
||||||
|
if (!HMAC(EVP_sha256(), &key[0], key.size(), &buffer[SHA256_DIGEST_LENGTH],
|
||||||
|
buffer.size() - SHA256_DIGEST_LENGTH, clear->signature,
|
||||||
|
&sig_length)) {
|
||||||
|
LOGE("LoadUsageEntry: Could not sign entry.");
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
if (memcmp(clear->signature, encrypted->signature, SHA256_DIGEST_LENGTH)) {
|
||||||
|
LOGE("LoadUsageEntry: Signature did not match.");
|
||||||
|
LOGE("LoadUsageEntry: Invalid signature given: %s",
|
||||||
|
wvcdm::HexEncode(encrypted->signature, sig_length).c_str());
|
||||||
|
LOGE("LoadUsageEntry: Invalid signature computed: %s",
|
||||||
|
wvcdm::HexEncode(clear->signature, sig_length).c_str());
|
||||||
|
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
wvcdm::FileSystem *file_system = ce_->file_system();
|
// Next, decrypt the entry.
|
||||||
wvcdm::File *file;
|
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE];
|
||||||
|
memcpy(iv_buffer, encrypted->iv, wvcdm::KEY_IV_SIZE);
|
||||||
|
AES_KEY aes_key;
|
||||||
|
AES_set_decrypt_key(&key[0], 128, &aes_key);
|
||||||
|
AES_cbc_encrypt(&buffer[kEncryptionOffset], &clear_buffer[kEncryptionOffset],
|
||||||
|
buffer.size() - kEncryptionOffset, &aes_key, iv_buffer,
|
||||||
|
AES_DECRYPT);
|
||||||
|
|
||||||
|
// Check the verification string is correct.
|
||||||
|
if (memcmp(kEntryVerification, clear->verification, kMagicLength)) {
|
||||||
|
LOGE("LoadUsageEntry: Invalid magic: %s=%8.8s expected: %s=%8.8s",
|
||||||
|
wvcdm::HexEncode(clear->verification, kMagicLength).c_str(),
|
||||||
|
clear->verification,
|
||||||
|
wvcdm::HexEncode(reinterpret_cast<const uint8_t*>(kEntryVerification),
|
||||||
|
kMagicLength).c_str(),
|
||||||
|
reinterpret_cast<const uint8_t*>(kEntryVerification));
|
||||||
|
return OEMCrypto_ERROR_BAD_MAGIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the index is correct.
|
||||||
|
if (index != clear->data.index) {
|
||||||
|
LOGE("LoadUsageEntry: entry says index is %d, not %d", clear->data.index,
|
||||||
|
index);
|
||||||
|
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||||
|
}
|
||||||
|
if (clear->data.status > kInactiveUnused) {
|
||||||
|
LOGE("LoadUsageEntry: entry has bad status %d", clear->data.status);
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
this->data_ = clear->data;
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t UsageTableEntry::SignedEntrySize() {
|
||||||
|
size_t base = sizeof(SignedEntryBlock);
|
||||||
|
// round up to make even number of blocks:
|
||||||
|
size_t blocks = (base - 1) / wvcdm::KEY_IV_SIZE + 1;
|
||||||
|
return blocks * wvcdm::KEY_IV_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t UsageTable::SignedHeaderSize(size_t count) {
|
||||||
|
size_t base = sizeof(SignedHeaderBlock) + count * sizeof(int64_t);
|
||||||
|
// round up to make even number of blocks:
|
||||||
|
size_t blocks = (base - 1) / wvcdm::KEY_IV_SIZE + 1;
|
||||||
|
return blocks * wvcdm::KEY_IV_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult UsageTable::UpdateUsageEntry(SessionContext* session,
|
||||||
|
UsageTableEntry* entry,
|
||||||
|
uint8_t* header_buffer,
|
||||||
|
size_t* header_buffer_length,
|
||||||
|
uint8_t* entry_buffer,
|
||||||
|
size_t* entry_buffer_length) {
|
||||||
|
size_t signed_header_size = SignedHeaderSize(generation_numbers_.size());
|
||||||
|
if (*entry_buffer_length < UsageTableEntry::SignedEntrySize() ||
|
||||||
|
*header_buffer_length < signed_header_size) {
|
||||||
|
*entry_buffer_length = UsageTableEntry::SignedEntrySize();
|
||||||
|
*header_buffer_length = signed_header_size;
|
||||||
|
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||||
|
}
|
||||||
|
*entry_buffer_length = UsageTableEntry::SignedEntrySize();
|
||||||
|
*header_buffer_length = signed_header_size;
|
||||||
|
if ((!header_buffer) || (!entry_buffer))
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
entry->UpdateAndIncrement();
|
||||||
|
generation_numbers_[entry->index()] = entry->generation_number();
|
||||||
|
OEMCryptoResult result =
|
||||||
|
entry->SaveData(ce_, session, entry_buffer, *entry_buffer_length);
|
||||||
|
if (result != OEMCrypto_SUCCESS) return result;
|
||||||
|
result = SaveUsageTableHeader(header_buffer, *header_buffer_length);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult UsageTable::CreateNewUsageEntry(SessionContext* session,
|
||||||
|
UsageTableEntry** entry,
|
||||||
|
uint32_t* usage_entry_number) {
|
||||||
|
if (!header_loaded_) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
if (!entry) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
if (!usage_entry_number) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
uint32_t index = generation_numbers_.size();
|
||||||
|
UsageTableEntry* new_entry =
|
||||||
|
new UsageTableEntry(this, index, master_generation_number_);
|
||||||
|
generation_numbers_.push_back(master_generation_number_);
|
||||||
|
sessions_.push_back(session);
|
||||||
|
master_generation_number_++;
|
||||||
|
*entry = new_entry;
|
||||||
|
*usage_entry_number = index;
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult UsageTable::LoadUsageEntry(SessionContext* session,
|
||||||
|
UsageTableEntry** entry,
|
||||||
|
uint32_t index,
|
||||||
|
const std::vector<uint8_t>& buffer) {
|
||||||
|
if (!header_loaded_) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
if (!entry) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
if (index >= generation_numbers_.size())
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
if (sessions_[index]) {
|
||||||
|
LOGE("LoadUsageEntry: index %d used by other session.", index);
|
||||||
|
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||||
|
}
|
||||||
|
UsageTableEntry* new_entry =
|
||||||
|
new UsageTableEntry(this, index, master_generation_number_);
|
||||||
|
|
||||||
|
OEMCryptoResult status = new_entry->LoadData(ce_, index, buffer);
|
||||||
|
if (status != OEMCrypto_SUCCESS) {
|
||||||
|
delete new_entry;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
if (new_entry->generation_number() != generation_numbers_[index]) {
|
||||||
|
LOGE("Generation SKEW: %ld -> %ld", new_entry->generation_number(),
|
||||||
|
generation_numbers_[index]);
|
||||||
|
if ((new_entry->generation_number() + 1 < generation_numbers_[index]) ||
|
||||||
|
(new_entry->generation_number() - 1 > generation_numbers_[index])) {
|
||||||
|
delete new_entry;
|
||||||
|
return OEMCrypto_ERROR_GENERATION_SKEW;
|
||||||
|
}
|
||||||
|
status = OEMCrypto_WARNING_GENERATION_SKEW;
|
||||||
|
}
|
||||||
|
sessions_[index] = session;
|
||||||
|
*entry = new_entry;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult UsageTable::ShrinkUsageTableHeader(
|
||||||
|
uint32_t new_table_size, uint8_t* header_buffer,
|
||||||
|
size_t* header_buffer_length) {
|
||||||
|
if (new_table_size > generation_numbers_.size())
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
size_t signed_header_size = SignedHeaderSize(new_table_size);
|
||||||
|
if (*header_buffer_length < signed_header_size) {
|
||||||
|
*header_buffer_length = signed_header_size;
|
||||||
|
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||||
|
}
|
||||||
|
*header_buffer_length = signed_header_size;
|
||||||
|
for (size_t i = new_table_size; i < sessions_.size(); i++) {
|
||||||
|
if (sessions_[i]) {
|
||||||
|
LOGE("ShrinkUsageTableHeader: session open for %d", i);
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
generation_numbers_.resize(new_table_size);
|
||||||
|
sessions_.resize(new_table_size);
|
||||||
|
master_generation_number_++;
|
||||||
|
return SaveUsageTableHeader(header_buffer, *header_buffer_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult UsageTable::SaveUsageTableHeader(uint8_t* signed_buffer,
|
||||||
|
size_t buffer_size) {
|
||||||
|
if (!SaveGenerationNumber()) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
size_t count = generation_numbers_.size();
|
||||||
|
// buffer_size was determined by calling function.
|
||||||
|
if (buffer_size != SignedHeaderSize(count))
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
std::vector<uint8_t> clear_buffer(buffer_size);
|
||||||
|
memset(&clear_buffer[0], 0, buffer_size);
|
||||||
|
memset(signed_buffer, 0, buffer_size);
|
||||||
|
SignedHeaderBlock* clear =
|
||||||
|
reinterpret_cast<SignedHeaderBlock*>(&clear_buffer[0]);
|
||||||
|
SignedHeaderBlock* encrypted =
|
||||||
|
reinterpret_cast<SignedHeaderBlock*>(signed_buffer);
|
||||||
|
|
||||||
|
// Pack the clear data into the clear buffer.
|
||||||
|
memcpy(clear->verification, kHeaderVerification, kMagicLength);
|
||||||
|
clear->master_generation = master_generation_number_;
|
||||||
|
clear->count = count;
|
||||||
|
// This points to the variable size part of the buffer.
|
||||||
|
int64_t* stored_generations =
|
||||||
|
reinterpret_cast<int64_t*>(&clear_buffer[sizeof(SignedHeaderBlock)]);
|
||||||
|
std::copy(generation_numbers_.begin(), generation_numbers_.begin() + count,
|
||||||
|
stored_generations);
|
||||||
|
|
||||||
|
// This should be encrypted and signed with a device specific key.
|
||||||
|
// For the reference implementation, I'm just going to use the keybox key.
|
||||||
|
const bool override_to_real = true;
|
||||||
|
const std::vector<uint8_t>& key = ce_->DeviceRootKey(override_to_real);
|
||||||
|
|
||||||
|
// Encrypt the entry.
|
||||||
|
RAND_bytes(encrypted->iv, wvcdm::KEY_IV_SIZE);
|
||||||
|
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE]; // working iv buffer.
|
||||||
|
memcpy(iv_buffer, encrypted->iv, wvcdm::KEY_IV_SIZE);
|
||||||
|
AES_KEY aes_key;
|
||||||
|
AES_set_encrypt_key(&key[0], 128, &aes_key);
|
||||||
|
AES_cbc_encrypt(
|
||||||
|
&clear_buffer[kEncryptionOffset], &signed_buffer[kEncryptionOffset],
|
||||||
|
buffer_size - kEncryptionOffset, &aes_key, iv_buffer, AES_ENCRYPT);
|
||||||
|
|
||||||
|
// Sign the entry.
|
||||||
|
unsigned int sig_length = SHA256_DIGEST_LENGTH;
|
||||||
|
if (!HMAC(EVP_sha256(), &key[0], key.size(),
|
||||||
|
&signed_buffer[SHA256_DIGEST_LENGTH],
|
||||||
|
buffer_size - SHA256_DIGEST_LENGTH, encrypted->signature,
|
||||||
|
&sig_length)) {
|
||||||
|
LOGE("SaveUsageHeader: Could not sign entry.");
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult UsageTable::LoadUsageTableHeader(
|
||||||
|
const std::vector<uint8_t>& buffer) {
|
||||||
|
if (!LoadGenerationNumber(false)) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
|
||||||
|
if (buffer.size() < SignedHeaderSize(0)) return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||||
|
std::vector<uint8_t> clear_buffer(buffer.size());
|
||||||
|
SignedHeaderBlock* clear =
|
||||||
|
reinterpret_cast<SignedHeaderBlock*>(&clear_buffer[0]);
|
||||||
|
const SignedHeaderBlock* encrypted =
|
||||||
|
reinterpret_cast<const SignedHeaderBlock*>(&buffer[0]);
|
||||||
|
|
||||||
|
// This should be encrypted and signed with a device specific key.
|
||||||
|
// For the reference implementation, I'm just going to use the keybox key.
|
||||||
|
const bool override_to_real = true;
|
||||||
|
const std::vector<uint8_t>& key = ce_->DeviceRootKey(override_to_real);
|
||||||
|
|
||||||
|
// Verify the signature of the usage entry. Sign encrypted into clear buffer.
|
||||||
|
unsigned int sig_length = SHA256_DIGEST_LENGTH;
|
||||||
|
if (!HMAC(EVP_sha256(), &key[0], key.size(), &buffer[SHA256_DIGEST_LENGTH],
|
||||||
|
buffer.size() - SHA256_DIGEST_LENGTH, clear->signature,
|
||||||
|
&sig_length)) {
|
||||||
|
LOGE("LoadUsageTableHeader: Could not sign entry.");
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
if (memcmp(clear->signature, encrypted->signature, SHA256_DIGEST_LENGTH)) {
|
||||||
|
LOGE("LoadUsageTableHeader: Signature did not match.");
|
||||||
|
LOGE("LoadUsageTableHeader: Invalid signature given: %s",
|
||||||
|
wvcdm::HexEncode(encrypted->signature, sig_length).c_str());
|
||||||
|
LOGE("LoadUsageTableHeader: Invalid signature computed: %s",
|
||||||
|
wvcdm::HexEncode(clear->signature, sig_length).c_str());
|
||||||
|
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next, decrypt the entry.
|
||||||
|
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE];
|
||||||
|
memcpy(iv_buffer, encrypted->iv, wvcdm::KEY_IV_SIZE);
|
||||||
|
AES_KEY aes_key;
|
||||||
|
AES_set_decrypt_key(&key[0], 128, &aes_key);
|
||||||
|
AES_cbc_encrypt(&buffer[kEncryptionOffset], &clear_buffer[kEncryptionOffset],
|
||||||
|
buffer.size() - kEncryptionOffset, &aes_key, iv_buffer,
|
||||||
|
AES_DECRYPT);
|
||||||
|
|
||||||
|
// Check the verification string is correct.
|
||||||
|
if (memcmp(kHeaderVerification, clear->verification, kMagicLength)) {
|
||||||
|
LOGE("LoadUsageTableHeader: Invalid magic: %s=%8.8s expected: %s=%8.8s",
|
||||||
|
wvcdm::HexEncode(clear->verification, kMagicLength).c_str(),
|
||||||
|
clear->verification,
|
||||||
|
wvcdm::HexEncode(reinterpret_cast<const uint8_t*>(kHeaderVerification),
|
||||||
|
kMagicLength).c_str(),
|
||||||
|
reinterpret_cast<const uint8_t*>(kHeaderVerification));
|
||||||
|
return OEMCrypto_ERROR_BAD_MAGIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that size is correct, now that we know what it should be.
|
||||||
|
if (buffer.size() < SignedHeaderSize(clear->count)) {
|
||||||
|
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||||
|
}
|
||||||
|
if (buffer.size() > SignedHeaderSize(clear->count)) {
|
||||||
|
LOGW("LoadUsageTableHeader: buffer is large. %d > %d", buffer.size(),
|
||||||
|
SignedHeaderSize(clear->count));
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult status = OEMCrypto_SUCCESS;
|
||||||
|
if (clear->master_generation != master_generation_number_) {
|
||||||
|
LOGE("Generation SKEW: %ld -> %ld", clear->master_generation,
|
||||||
|
master_generation_number_);
|
||||||
|
if ((clear->master_generation + 1 < master_generation_number_) ||
|
||||||
|
(clear->master_generation - 1 > master_generation_number_)) {
|
||||||
|
return OEMCrypto_ERROR_GENERATION_SKEW;
|
||||||
|
}
|
||||||
|
status = OEMCrypto_WARNING_GENERATION_SKEW;
|
||||||
|
}
|
||||||
|
int64_t* stored_generations =
|
||||||
|
reinterpret_cast<int64_t*>(&clear_buffer[0] + sizeof(SignedHeaderBlock));
|
||||||
|
generation_numbers_.assign(stored_generations,
|
||||||
|
stored_generations + clear->count);
|
||||||
|
sessions_.clear();
|
||||||
|
sessions_.resize(clear->count);
|
||||||
|
header_loaded_ = true;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult UsageTable::MoveEntry(UsageTableEntry* entry,
|
||||||
|
uint32_t new_index) {
|
||||||
|
if (new_index >= generation_numbers_.size()) {
|
||||||
|
LOGE("MoveEntry: index beyond end of usage table %d >= %d", new_index,
|
||||||
|
generation_numbers_.size());
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
if (sessions_[new_index]) {
|
||||||
|
LOGE("MoveEntry: session open for %d", new_index);
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
|
if (!entry) {
|
||||||
|
LOGE("MoveEntry: null entry");
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
sessions_[new_index] = sessions_[entry->index()];
|
||||||
|
sessions_[entry->index()] = 0;
|
||||||
|
|
||||||
|
entry->set_index(new_index);
|
||||||
|
generation_numbers_[new_index] = master_generation_number_;
|
||||||
|
entry->set_generation_number(master_generation_number_);
|
||||||
|
master_generation_number_++;
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UsageTable::IncrementGeneration() {
|
||||||
|
master_generation_number_++;
|
||||||
|
SaveGenerationNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UsageTable::SaveGenerationNumber() {
|
||||||
|
wvcdm::FileSystem* file_system = ce_->file_system();
|
||||||
std::string path;
|
std::string path;
|
||||||
// Note: this path is OK for a real implementation, but using security level 1
|
// Note: this path is OK for a real implementation, but using security level 1
|
||||||
// would be better.
|
// would be better.
|
||||||
@@ -320,115 +575,76 @@ bool UsageTable::SaveToFile() {
|
|||||||
LOGE("UsageTable: Unable to get base path");
|
LOGE("UsageTable: Unable to get base path");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string filename = path + "UsageTable.dat";
|
|
||||||
if (!file_system->Exists(filename)) {
|
|
||||||
if (LogCategoryEnabled(kLoggingTraceUsageTable)) {
|
|
||||||
LOGI("UsageTable: No saved usage table. Creating new table.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
file = file_system->Open(
|
|
||||||
filename, wvcdm::FileSystem::kCreate | wvcdm::FileSystem::kTruncate);
|
|
||||||
if (!file) {
|
|
||||||
LOGE("UsageTable: Could not save usage table: %s", path.c_str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
file->Write(reinterpret_cast<char *>(&encrypted_buffer[0]), file_size);
|
|
||||||
file->Close();
|
|
||||||
|
|
||||||
// On a real implementation, you should NOT put the generation number in
|
// On a real implementation, you should NOT put the generation number in
|
||||||
// a file in user space. It should be stored in secure memory.
|
// a file in user space. It should be stored in secure memory.
|
||||||
std::string filename2 = path + "GenerationNumber.dat";
|
std::string filename = path + "GenerationNumber.dat";
|
||||||
file = file_system->Open(
|
wvcdm::File* file = file_system->Open(
|
||||||
filename2, wvcdm::FileSystem::kCreate | wvcdm::FileSystem::kTruncate);
|
filename, wvcdm::FileSystem::kCreate | wvcdm::FileSystem::kTruncate);
|
||||||
if (!file) {
|
if (!file) {
|
||||||
LOGE("UsageTable: File open failed: %s", path.c_str());
|
LOGE("UsageTable: File open failed: %s", path.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
file->Write(reinterpret_cast<char *>(&generation_), sizeof(int64_t));
|
file->Write(reinterpret_cast<char*>(&master_generation_number_),
|
||||||
|
sizeof(int64_t));
|
||||||
file->Close();
|
file->Close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
UsageTableEntry *UsageTable::FindEntry(const std::vector<uint8_t> &pst) {
|
bool UsageTable::LoadGenerationNumber(bool or_make_new_one) {
|
||||||
wvcdm::AutoLock lock(lock_);
|
wvcdm::FileSystem* file_system = ce_->file_system();
|
||||||
return FindEntryLocked(pst);
|
std::string path;
|
||||||
}
|
// Note: this path is OK for a real implementation, but using security level 1
|
||||||
|
// would be better.
|
||||||
UsageTableEntry *UsageTable::FindEntryLocked(const std::vector<uint8_t> &pst) {
|
if (!wvcdm::Properties::GetDeviceFilesBasePath(wvcdm::kSecurityLevelL3,
|
||||||
std::vector<uint8_t> pst_hash;
|
&path)) {
|
||||||
if (!ComputeHash(pst, pst_hash)) {
|
LOGE("UsageTable: Unable to get base path");
|
||||||
LOGE("UsageTable: Could not compute hash of pst.");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
EntryMap::iterator it = table_.find(pst_hash);
|
|
||||||
if (it == table_.end()) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
UsageTableEntry *UsageTable::CreateEntry(const std::vector<uint8_t> &pst,
|
|
||||||
SessionContext *ctx) {
|
|
||||||
std::vector<uint8_t> pst_hash;
|
|
||||||
if (!ComputeHash(pst, pst_hash)) {
|
|
||||||
LOGE("UsageTable: Could not compute hash of pst.");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
UsageTableEntry *entry = new UsageTableEntry(pst_hash, ctx);
|
|
||||||
wvcdm::AutoLock lock(lock_);
|
|
||||||
table_[pst_hash] = entry;
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
OEMCryptoResult UsageTable::UpdateTable() {
|
|
||||||
wvcdm::AutoLock lock(lock_);
|
|
||||||
if (SaveToFile()) return OEMCrypto_SUCCESS;
|
|
||||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
OEMCryptoResult UsageTable::DeactivateEntry(const std::vector<uint8_t> &pst) {
|
|
||||||
wvcdm::AutoLock lock(lock_);
|
|
||||||
UsageTableEntry *entry = FindEntryLocked(pst);
|
|
||||||
if (!entry) return OEMCrypto_ERROR_INVALID_CONTEXT;
|
|
||||||
entry->Deactivate();
|
|
||||||
if (SaveToFile()) return OEMCrypto_SUCCESS;
|
|
||||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UsageTable::DeleteEntry(const std::vector<uint8_t> &pst) {
|
|
||||||
std::vector<uint8_t> pst_hash;
|
|
||||||
if (!ComputeHash(pst, pst_hash)) {
|
|
||||||
LOGE("UsageTable: Could not compute hash of pst.");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
wvcdm::AutoLock lock(lock_);
|
// On a real implementation, you should NOT put the generation number in
|
||||||
EntryMap::iterator it = table_.find(pst_hash);
|
// a file in user space. It should be stored in secure memory.
|
||||||
if (it == table_.end()) return false;
|
std::string filename = path + "GenerationNumber.dat";
|
||||||
if (it->second) delete it->second;
|
wvcdm::File* file = file_system->Open(filename, wvcdm::FileSystem::kReadOnly);
|
||||||
table_.erase(it);
|
if (!file) {
|
||||||
return SaveToFile();
|
if (or_make_new_one) {
|
||||||
}
|
RAND_bytes(reinterpret_cast<uint8_t*>(&master_generation_number_),
|
||||||
|
sizeof(int64_t));
|
||||||
void UsageTable::Clear() {
|
master_generation_number_ = 0; // TODO(fredgc): remove after debugging.
|
||||||
wvcdm::AutoLock lock(lock_);
|
return true;
|
||||||
for (EntryMap::iterator i = table_.begin(); i != table_.end(); ++i) {
|
}
|
||||||
if (i->second) delete i->second;
|
LOGE("UsageTable: File open failed: %s (clearing table)", path.c_str());
|
||||||
|
master_generation_number_ = 0;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
table_.clear();
|
file->Read(reinterpret_cast<char*>(&master_generation_number_),
|
||||||
|
sizeof(int64_t));
|
||||||
|
file->Close();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UsageTable::ComputeHash(const std::vector<uint8_t> &pst,
|
OEMCryptoResult UsageTable::CreateUsageTableHeader(
|
||||||
std::vector<uint8_t> &pst_hash) {
|
uint8_t* header_buffer, size_t* header_buffer_length) {
|
||||||
// The PST is not fixed size, and we have no promises that it is reasonbly
|
size_t signed_header_size = SignedHeaderSize(0);
|
||||||
// sized, so we compute a hash of it, and store that instead.
|
if (*header_buffer_length < signed_header_size) {
|
||||||
pst_hash.resize(SHA256_DIGEST_LENGTH);
|
*header_buffer_length = signed_header_size;
|
||||||
SHA256_CTX context;
|
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||||
if (!SHA256_Init(&context)) return false;
|
}
|
||||||
if (!SHA256_Update(&context, &pst[0], pst.size())) return false;
|
*header_buffer_length = signed_header_size;
|
||||||
if (!SHA256_Final(&pst_hash[0], &context)) return false;
|
if (!LoadGenerationNumber(true)) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
return true;
|
sessions_.clear();
|
||||||
|
generation_numbers_.clear();
|
||||||
|
header_loaded_ = true;
|
||||||
|
return SaveUsageTableHeader(header_buffer, *header_buffer_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult UsageTable::CopyOldUsageEntry(UsageTableEntry* entry,
|
||||||
|
const std::vector<uint8_t>& pst) {
|
||||||
|
// TODO(fredgc): add this.
|
||||||
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult UsageTable::DeleteOldUsageTable() {
|
||||||
|
// TODO(fredgc): add this.
|
||||||
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace wvoec_mock
|
} // namespace wvoec_mock
|
||||||
|
|||||||
@@ -10,8 +10,9 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "lock.h"
|
|
||||||
#include "OEMCryptoCENC.h"
|
#include "OEMCryptoCENC.h"
|
||||||
|
#include "file_store.h"
|
||||||
|
#include "lock.h"
|
||||||
#include "openssl/sha.h"
|
#include "openssl/sha.h"
|
||||||
#include "wv_cdm_constants.h"
|
#include "wv_cdm_constants.h"
|
||||||
|
|
||||||
@@ -19,85 +20,104 @@ namespace wvoec_mock {
|
|||||||
|
|
||||||
class SessionContext;
|
class SessionContext;
|
||||||
class CryptoEngine;
|
class CryptoEngine;
|
||||||
|
class UsageTable;
|
||||||
|
|
||||||
|
const size_t kMaxPSTLength = 255;
|
||||||
|
// This is the data we store offline.
|
||||||
struct StoredUsageEntry {
|
struct StoredUsageEntry {
|
||||||
// To save disk space, we only store a hash of the pst.
|
int64_t generation_number;
|
||||||
uint8_t pst_hash[SHA256_DIGEST_LENGTH];
|
|
||||||
int64_t time_of_license_received;
|
int64_t time_of_license_received;
|
||||||
int64_t time_of_first_decrypt;
|
int64_t time_of_first_decrypt;
|
||||||
int64_t time_of_last_decrypt;
|
int64_t time_of_last_decrypt;
|
||||||
enum OEMCrypto_Usage_Entry_Status status;
|
enum OEMCrypto_Usage_Entry_Status status;
|
||||||
uint8_t mac_key_server[wvcdm::MAC_KEY_SIZE];
|
uint8_t mac_key_server[wvcdm::MAC_KEY_SIZE];
|
||||||
uint8_t mac_key_client[wvcdm::MAC_KEY_SIZE];
|
uint8_t mac_key_client[wvcdm::MAC_KEY_SIZE];
|
||||||
};
|
uint32_t index;
|
||||||
typedef union {
|
uint8_t pst[kMaxPSTLength+1]; // add 1 for padding.
|
||||||
struct StoredUsageEntry entry;
|
uint8_t pst_length;
|
||||||
uint8_t padding[128]; // multiple of block size and bigger than entry size.
|
|
||||||
} AlignedStoredUsageEntry;
|
|
||||||
|
|
||||||
struct StoredUsageTable {
|
|
||||||
uint8_t signature[SHA256_DIGEST_LENGTH];
|
|
||||||
uint8_t iv[wvcdm::KEY_IV_SIZE];
|
|
||||||
int64_t generation;
|
|
||||||
uint64_t count;
|
|
||||||
AlignedStoredUsageEntry entries[];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class UsageTableEntry {
|
class UsageTableEntry {
|
||||||
public:
|
public:
|
||||||
UsageTableEntry(const std::vector<uint8_t> &pst_hash, SessionContext *ctx);
|
UsageTableEntry(UsageTable* table, uint32_t index, int64_t generation);
|
||||||
UsageTableEntry(const StoredUsageEntry *buffer);
|
// owner_(owner), session_(session), loaded_(false) {}
|
||||||
~UsageTableEntry();
|
~UsageTableEntry(); // Free memory, remove reference in header.
|
||||||
void SaveToBuffer(StoredUsageEntry *buffer);
|
bool Inactive() { return data_.status >= kInactive; }
|
||||||
OEMCrypto_Usage_Entry_Status status() const { return status_; }
|
OEMCryptoResult SetPST(const uint8_t* pst, size_t pst_length);
|
||||||
bool inactive() const { return status_ >= kInactive; }
|
bool VerifyPST(const uint8_t* pst, size_t pst_length);
|
||||||
void Deactivate();
|
bool VerifyMacKeys(const std::vector<uint8_t>& server,
|
||||||
bool UpdateTime();
|
const std::vector<uint8_t>& client);
|
||||||
OEMCryptoResult ReportUsage(SessionContext *session,
|
bool SetMacKeys(const std::vector<uint8_t>& server,
|
||||||
const std::vector<uint8_t> &pst,
|
const std::vector<uint8_t>& client);
|
||||||
uint8_t *buffer,
|
// Returns false if the entry is inactive. Otherwise, returns true.
|
||||||
size_t *buffer_length);
|
// If the status was unused, it is updated, and decrypt times are flaged
|
||||||
// Set them if not set, verify if already set.
|
// for update.
|
||||||
bool VerifyOrSetMacKeys(const std::vector<uint8_t> &server,
|
bool CheckForUse();
|
||||||
const std::vector<uint8_t> &client);
|
void Deactivate(const std::vector<uint8_t>& pst);
|
||||||
const std::vector<uint8_t> &pst_hash() const { return pst_hash_; }
|
OEMCryptoResult ReportUsage(const std::vector<uint8_t>& pst, uint8_t* buffer,
|
||||||
void set_session(SessionContext *session) { session_ = session; }
|
size_t* buffer_length);
|
||||||
|
void UpdateAndIncrement();
|
||||||
|
OEMCryptoResult SaveData(CryptoEngine* ce, SessionContext* session,
|
||||||
|
uint8_t* signed_buffer, size_t buffer_size);
|
||||||
|
OEMCryptoResult LoadData(CryptoEngine* ce, uint32_t index,
|
||||||
|
const std::vector<uint8_t>& buffer);
|
||||||
|
int64_t generation_number() { return data_.generation_number; }
|
||||||
|
void set_generation_number(int64_t value) { data_.generation_number = value; }
|
||||||
|
void set_index(int32_t index) { data_.index = index; }
|
||||||
|
uint32_t index() { return data_.index; }
|
||||||
|
static size_t SignedEntrySize();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<uint8_t> pst_hash_;
|
UsageTable* usage_table_; // Owner of this object.
|
||||||
int64_t time_of_license_received_;
|
bool recent_decrypt_;
|
||||||
int64_t time_of_first_decrypt_;
|
bool forbid_report_;
|
||||||
int64_t time_of_last_decrypt_;
|
StoredUsageEntry data_;
|
||||||
enum OEMCrypto_Usage_Entry_Status status_;
|
|
||||||
std::vector<uint8_t> mac_key_server_;
|
|
||||||
std::vector<uint8_t> mac_key_client_;
|
|
||||||
|
|
||||||
SessionContext *session_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class UsageTable {
|
class UsageTable {
|
||||||
public:
|
public:
|
||||||
UsageTable(CryptoEngine *ce);
|
UsageTable(CryptoEngine* ce, wvcdm::FileSystem* file_system)
|
||||||
~UsageTable() { Clear(); }
|
: ce_(ce), file_system_(file_system), header_loaded_(false){};
|
||||||
UsageTableEntry *FindEntry(const std::vector<uint8_t> &pst);
|
|
||||||
UsageTableEntry *CreateEntry(const std::vector<uint8_t> &pst,
|
OEMCryptoResult CreateNewUsageEntry(SessionContext* session,
|
||||||
SessionContext *ctx);
|
UsageTableEntry** entry,
|
||||||
OEMCryptoResult UpdateTable();
|
uint32_t* usage_entry_number);
|
||||||
OEMCryptoResult DeactivateEntry(const std::vector<uint8_t> &pst);
|
OEMCryptoResult LoadUsageEntry(SessionContext* session,
|
||||||
bool DeleteEntry(const std::vector<uint8_t> &pst);
|
UsageTableEntry** entry, uint32_t index,
|
||||||
void Clear();
|
const std::vector<uint8_t>& buffer);
|
||||||
|
OEMCryptoResult UpdateUsageEntry(SessionContext* session,
|
||||||
|
UsageTableEntry* entry,
|
||||||
|
uint8_t* header_buffer,
|
||||||
|
size_t* header_buffer_length,
|
||||||
|
uint8_t* entry_buffer,
|
||||||
|
size_t* entry_buffer_length);
|
||||||
|
OEMCryptoResult MoveEntry(UsageTableEntry* entry, uint32_t new_index);
|
||||||
|
OEMCryptoResult CopyOldUsageEntry(UsageTableEntry* entry,
|
||||||
|
const std::vector<uint8_t>& pst);
|
||||||
|
OEMCryptoResult DeleteOldUsageTable();
|
||||||
|
OEMCryptoResult CreateUsageTableHeader(uint8_t* header_buffer,
|
||||||
|
size_t* header_buffer_length);
|
||||||
|
OEMCryptoResult LoadUsageTableHeader(const std::vector<uint8_t>& buffer);
|
||||||
|
OEMCryptoResult ShrinkUsageTableHeader(uint32_t new_table_size,
|
||||||
|
uint8_t* header_buffer,
|
||||||
|
size_t* header_buffer_length);
|
||||||
|
// Diassociates this entry with it's session.
|
||||||
|
void ReleaseEntry(uint32_t index) { sessions_[index] = 0; }
|
||||||
|
void IncrementGeneration();
|
||||||
|
static size_t SignedHeaderSize(size_t count);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UsageTableEntry *FindEntryLocked(const std::vector<uint8_t> &pst);
|
OEMCryptoResult SaveUsageTableHeader(uint8_t* signed_buffer,
|
||||||
bool SaveToFile();
|
size_t buffer_size);
|
||||||
bool ComputeHash(const std::vector<uint8_t> &pst,
|
bool SaveGenerationNumber();
|
||||||
std::vector<uint8_t> &pst_hash);
|
bool LoadGenerationNumber(bool or_make_new_one);
|
||||||
|
|
||||||
typedef std::map<std::vector<uint8_t>, UsageTableEntry *> EntryMap;
|
CryptoEngine* ce_;
|
||||||
EntryMap table_;
|
wvcdm::FileSystem* file_system_;
|
||||||
wvcdm::Lock lock_;
|
bool header_loaded_;
|
||||||
int64_t generation_;
|
int64_t master_generation_number_;
|
||||||
CryptoEngine *ce_;
|
std::vector<int64_t> generation_numbers_;
|
||||||
|
std::vector<SessionContext*> sessions_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace wvoec_mock
|
} // namespace wvoec_mock
|
||||||
|
|||||||
@@ -819,8 +819,47 @@ void Session::InstallRSASessionTestKey(const vector<uint8_t>& wrapped_rsa_key) {
|
|||||||
GenerateDerivedKeysFromSessionKey();
|
GenerateDerivedKeysFromSessionKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Session::CreateNewUsageEntry() {
|
||||||
|
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||||
|
OEMCrypto_CreateNewUsageEntry(session_id(), &usage_entry_number_));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::UpdateUsageEntry(std::vector<uint8_t>* header_buffer) {
|
||||||
|
size_t header_buffer_length = 0;
|
||||||
|
size_t entry_buffer_length = 0;
|
||||||
|
ASSERT_EQ(
|
||||||
|
OEMCrypto_ERROR_SHORT_BUFFER,
|
||||||
|
OEMCrypto_UpdateUsageEntry(session_id(), NULL, &header_buffer_length,
|
||||||
|
NULL, &entry_buffer_length));
|
||||||
|
ASSERT_LT(0u, header_buffer_length);
|
||||||
|
header_buffer->resize(header_buffer_length);
|
||||||
|
ASSERT_LT(0u, entry_buffer_length);
|
||||||
|
encrypted_usage_entry_.resize(entry_buffer_length);
|
||||||
|
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||||
|
OEMCrypto_UpdateUsageEntry(
|
||||||
|
session_id(), &(header_buffer->front()), &header_buffer_length,
|
||||||
|
&encrypted_usage_entry_[0], &entry_buffer_length));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::DeactivateUsageEntry(const std::string& pst,
|
||||||
|
OEMCryptoResult expect_result) {
|
||||||
|
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||||
|
OEMCrypto_DeactivateUsageEntry(
|
||||||
|
session_id(), reinterpret_cast<const uint8_t*>(pst.c_str()),
|
||||||
|
pst.length()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::LoadUsageEntry(uint32_t index, const vector<uint8_t>& buffer) {
|
||||||
|
usage_entry_number_ = index;
|
||||||
|
encrypted_usage_entry_ = buffer;
|
||||||
|
ASSERT_EQ(
|
||||||
|
OEMCrypto_SUCCESS,
|
||||||
|
OEMCrypto_LoadUsageEntry(session_id(), index, &buffer[0], buffer.size()));
|
||||||
|
}
|
||||||
|
|
||||||
void Session::GenerateReport(const std::string& pst, bool expect_success,
|
void Session::GenerateReport(const std::string& pst, bool expect_success,
|
||||||
Session* other) {
|
Session* other) {
|
||||||
|
ASSERT_TRUE(open_);
|
||||||
if (other) { // If other is specified, copy mac keys.
|
if (other) { // If other is specified, copy mac keys.
|
||||||
mac_key_server_ = other->mac_key_server_;
|
mac_key_server_ = other->mac_key_server_;
|
||||||
mac_key_client_ = other->mac_key_client_;
|
mac_key_client_ = other->mac_key_client_;
|
||||||
@@ -834,7 +873,7 @@ void Session::GenerateReport(const std::string& pst, bool expect_success,
|
|||||||
}
|
}
|
||||||
if (sts == OEMCrypto_ERROR_SHORT_BUFFER) {
|
if (sts == OEMCrypto_ERROR_SHORT_BUFFER) {
|
||||||
ASSERT_EQ(wvcdm::Unpacked_PST_Report::report_size(pst.length()), length);
|
ASSERT_EQ(wvcdm::Unpacked_PST_Report::report_size(pst.length()), length);
|
||||||
pst_report_buffer_.resize(length);
|
pst_report_buffer_.assign(length, 0xFF); // Fill with garbage values.
|
||||||
}
|
}
|
||||||
sts = OEMCrypto_ReportUsage(session_id(),
|
sts = OEMCrypto_ReportUsage(session_id(),
|
||||||
reinterpret_cast<const uint8_t*>(pst.c_str()),
|
reinterpret_cast<const uint8_t*>(pst.c_str()),
|
||||||
@@ -843,6 +882,7 @@ void Session::GenerateReport(const std::string& pst, bool expect_success,
|
|||||||
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
ASSERT_EQ(pst_report_buffer_.size(), length);
|
||||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||||
vector<uint8_t> computed_signature(SHA_DIGEST_LENGTH);
|
vector<uint8_t> computed_signature(SHA_DIGEST_LENGTH);
|
||||||
unsigned int sig_len = SHA_DIGEST_LENGTH;
|
unsigned int sig_len = SHA_DIGEST_LENGTH;
|
||||||
@@ -857,23 +897,6 @@ void Session::GenerateReport(const std::string& pst, bool expect_success,
|
|||||||
EXPECT_EQ(0, memcmp(pst.c_str(), pst_report().pst(), pst.length()));
|
EXPECT_EQ(0, memcmp(pst.c_str(), pst_report().pst(), pst.length()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::DeleteEntry(const std::string& pst) {
|
|
||||||
uint8_t* pst_ptr = encrypted_license().pst;
|
|
||||||
memcpy(pst_ptr, pst.c_str(), min(sizeof(license_.pst), pst.length()));
|
|
||||||
ServerSignBuffer(reinterpret_cast<const uint8_t*>(&padded_message_),
|
|
||||||
message_size_, &signature_);
|
|
||||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
|
||||||
OEMCrypto_DeleteUsageEntry(session_id(), pst_ptr, pst.length(),
|
|
||||||
message_ptr(), message_size_,
|
|
||||||
&signature_[0], signature_.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::ForceDeleteEntry(const std::string& pst) {
|
|
||||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
|
||||||
OEMCrypto_ForceDeleteUsageEntry(
|
|
||||||
reinterpret_cast<const uint8_t*>(pst.c_str()), pst.length()));
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t* Session::message_ptr() {
|
const uint8_t* Session::message_ptr() {
|
||||||
return reinterpret_cast<const uint8_t*>(&encrypted_license());
|
return reinterpret_cast<const uint8_t*>(&encrypted_license());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -248,6 +248,29 @@ class Session {
|
|||||||
// Loads the specified wrapped_rsa_key into OEMCrypto, and then runs
|
// Loads the specified wrapped_rsa_key into OEMCrypto, and then runs
|
||||||
// GenerateDerivedKeysFromSessionKey to install known encryption and mac keys.
|
// GenerateDerivedKeysFromSessionKey to install known encryption and mac keys.
|
||||||
void InstallRSASessionTestKey(const vector<uint8_t>& wrapped_rsa_key);
|
void InstallRSASessionTestKey(const vector<uint8_t>& wrapped_rsa_key);
|
||||||
|
// Creates a new usage entry, and keeps track of the index.
|
||||||
|
void CreateNewUsageEntry();
|
||||||
|
// Copy encrypted usage entry from other session, and then load it.
|
||||||
|
// This session must already be open.
|
||||||
|
void LoadUsageEntry(uint32_t index, const vector<uint8_t>& buffer);
|
||||||
|
// Copy encrypted usage entry from other session.
|
||||||
|
// This session must already be open.
|
||||||
|
void LoadUsageEntry(const Session& other) {
|
||||||
|
LoadUsageEntry(other.usage_entry_number(), other.encrypted_usage_entry());
|
||||||
|
}
|
||||||
|
// Reload previously used usage entry.
|
||||||
|
void ReloadUsageEntry() { LoadUsageEntry(*this); }
|
||||||
|
// Update the usage entry and save the header to the specified buffer.
|
||||||
|
void UpdateUsageEntry(std::vector<uint8_t>* header_buffer);
|
||||||
|
// Deactivate this sessions usage entry.
|
||||||
|
void DeactivateUsageEntry(const std::string& pst,
|
||||||
|
OEMCryptoResult expect_result = OEMCrypto_SUCCESS);
|
||||||
|
// The usage entry number for this session's usage entry.
|
||||||
|
uint32_t usage_entry_number() const { return usage_entry_number_; }
|
||||||
|
// The encrypted buffer holding the recently updated and saved usage entry.
|
||||||
|
const vector<uint8_t>& encrypted_usage_entry() const {
|
||||||
|
return encrypted_usage_entry_;
|
||||||
|
}
|
||||||
// Generates a usage report for the specified pst. If expect_success is true,
|
// Generates a usage report for the specified pst. If expect_success is true,
|
||||||
// the report's signature is verified, and several fields are given sanity
|
// the report's signature is verified, and several fields are given sanity
|
||||||
// checks. If other is not null, then the mac keys are copied from other in
|
// checks. If other is not null, then the mac keys are copied from other in
|
||||||
@@ -259,12 +282,6 @@ class Session {
|
|||||||
wvcdm::Unpacked_PST_Report pst_report() {
|
wvcdm::Unpacked_PST_Report pst_report() {
|
||||||
return wvcdm::Unpacked_PST_Report(&pst_report_buffer_[0]);
|
return wvcdm::Unpacked_PST_Report(&pst_report_buffer_[0]);
|
||||||
}
|
}
|
||||||
// Creates a signed delete usage table entry message and calls
|
|
||||||
// OEMCrypto_DeleteUsageEntry on it.
|
|
||||||
void DeleteEntry(const std::string& pst);
|
|
||||||
// Calls OEMCrypto_ForceDeleteUsageEntry to delete a usage table entry without
|
|
||||||
// a signed message.
|
|
||||||
void ForceDeleteEntry(const std::string& pst);
|
|
||||||
|
|
||||||
// The unencrypted license response or license renewal response.
|
// The unencrypted license response or license renewal response.
|
||||||
MessageData& license() { return license_; }
|
MessageData& license() { return license_; }
|
||||||
@@ -310,6 +327,8 @@ class Session {
|
|||||||
OEMCrypto_KeyObject key_array_[kMaxNumKeys];
|
OEMCrypto_KeyObject key_array_[kMaxNumKeys];
|
||||||
std::vector<uint8_t> signature_;
|
std::vector<uint8_t> signature_;
|
||||||
int num_keys_;
|
int num_keys_;
|
||||||
|
vector<uint8_t> encrypted_usage_entry_;
|
||||||
|
uint32_t usage_entry_number_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace wvoec
|
} // namespace wvoec
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user