Reference Code for Big Usage Tables

Merge from widevine of http://go/wvgerrit/23283

This CL adds some big usage table functionality to the oemcrypto
mock and unit tests.

Still missing are: backwards compatibility, defragging the table,
haystack code, and lots of new unit tests.

The haystack now reports it doesn't support usage tables, so that
the unit tests will pass.  This will be fixed in a future CL.

b/31458046
b/32554171
b/34173776
b/34174907

Change-Id: I6e08e76f7612ffb77e413151e00f830339298c62
This commit is contained in:
Fred Gylys-Colwell
2017-01-25 18:56:01 -08:00
parent 1c5b4175aa
commit 3d977d999c
9 changed files with 1259 additions and 1061 deletions

View File

@@ -10,8 +10,9 @@
#include <string>
#include <vector>
#include "lock.h"
#include "OEMCryptoCENC.h"
#include "file_store.h"
#include "lock.h"
#include "openssl/sha.h"
#include "wv_cdm_constants.h"
@@ -19,85 +20,104 @@ namespace wvoec_mock {
class SessionContext;
class CryptoEngine;
class UsageTable;
const size_t kMaxPSTLength = 255;
// This is the data we store offline.
struct StoredUsageEntry {
// To save disk space, we only store a hash of the pst.
uint8_t pst_hash[SHA256_DIGEST_LENGTH];
int64_t generation_number;
int64_t time_of_license_received;
int64_t time_of_first_decrypt;
int64_t time_of_last_decrypt;
enum OEMCrypto_Usage_Entry_Status status;
uint8_t mac_key_server[wvcdm::MAC_KEY_SIZE];
uint8_t mac_key_client[wvcdm::MAC_KEY_SIZE];
};
typedef union {
struct StoredUsageEntry entry;
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[];
uint32_t index;
uint8_t pst[kMaxPSTLength+1]; // add 1 for padding.
uint8_t pst_length;
};
class UsageTableEntry {
public:
UsageTableEntry(const std::vector<uint8_t> &pst_hash, SessionContext *ctx);
UsageTableEntry(const StoredUsageEntry *buffer);
~UsageTableEntry();
void SaveToBuffer(StoredUsageEntry *buffer);
OEMCrypto_Usage_Entry_Status status() const { return status_; }
bool inactive() const { return status_ >= kInactive; }
void Deactivate();
bool UpdateTime();
OEMCryptoResult ReportUsage(SessionContext *session,
const std::vector<uint8_t> &pst,
uint8_t *buffer,
size_t *buffer_length);
// Set them if not set, verify if already set.
bool VerifyOrSetMacKeys(const std::vector<uint8_t> &server,
const std::vector<uint8_t> &client);
const std::vector<uint8_t> &pst_hash() const { return pst_hash_; }
void set_session(SessionContext *session) { session_ = session; }
UsageTableEntry(UsageTable* table, uint32_t index, int64_t generation);
// owner_(owner), session_(session), loaded_(false) {}
~UsageTableEntry(); // Free memory, remove reference in header.
bool Inactive() { return data_.status >= kInactive; }
OEMCryptoResult SetPST(const uint8_t* pst, size_t pst_length);
bool VerifyPST(const uint8_t* pst, size_t pst_length);
bool VerifyMacKeys(const std::vector<uint8_t>& server,
const std::vector<uint8_t>& client);
bool SetMacKeys(const std::vector<uint8_t>& server,
const std::vector<uint8_t>& client);
// Returns false if the entry is inactive. Otherwise, returns true.
// If the status was unused, it is updated, and decrypt times are flaged
// for update.
bool CheckForUse();
void Deactivate(const std::vector<uint8_t>& pst);
OEMCryptoResult ReportUsage(const std::vector<uint8_t>& pst, uint8_t* buffer,
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:
std::vector<uint8_t> pst_hash_;
int64_t time_of_license_received_;
int64_t time_of_first_decrypt_;
int64_t time_of_last_decrypt_;
enum OEMCrypto_Usage_Entry_Status status_;
std::vector<uint8_t> mac_key_server_;
std::vector<uint8_t> mac_key_client_;
SessionContext *session_;
UsageTable* usage_table_; // Owner of this object.
bool recent_decrypt_;
bool forbid_report_;
StoredUsageEntry data_;
};
class UsageTable {
public:
UsageTable(CryptoEngine *ce);
~UsageTable() { Clear(); }
UsageTableEntry *FindEntry(const std::vector<uint8_t> &pst);
UsageTableEntry *CreateEntry(const std::vector<uint8_t> &pst,
SessionContext *ctx);
OEMCryptoResult UpdateTable();
OEMCryptoResult DeactivateEntry(const std::vector<uint8_t> &pst);
bool DeleteEntry(const std::vector<uint8_t> &pst);
void Clear();
UsageTable(CryptoEngine* ce, wvcdm::FileSystem* file_system)
: ce_(ce), file_system_(file_system), header_loaded_(false){};
OEMCryptoResult CreateNewUsageEntry(SessionContext* session,
UsageTableEntry** entry,
uint32_t* usage_entry_number);
OEMCryptoResult LoadUsageEntry(SessionContext* session,
UsageTableEntry** entry, uint32_t index,
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:
UsageTableEntry *FindEntryLocked(const std::vector<uint8_t> &pst);
bool SaveToFile();
bool ComputeHash(const std::vector<uint8_t> &pst,
std::vector<uint8_t> &pst_hash);
OEMCryptoResult SaveUsageTableHeader(uint8_t* signed_buffer,
size_t buffer_size);
bool SaveGenerationNumber();
bool LoadGenerationNumber(bool or_make_new_one);
typedef std::map<std::vector<uint8_t>, UsageTableEntry *> EntryMap;
EntryMap table_;
wvcdm::Lock lock_;
int64_t generation_;
CryptoEngine *ce_;
CryptoEngine* ce_;
wvcdm::FileSystem* file_system_;
bool header_loaded_;
int64_t master_generation_number_;
std::vector<int64_t> generation_numbers_;
std::vector<SessionContext*> sessions_;
};
} // namespace wvoec_mock