[ Merge of http://go/wvgerrit/115550 ] This change is the first part of a three part change for restructing the root of trust used by the reference implementation. The API of the AuthenticationRoot class has been updated to reflect the OEMCrypto functions that relate to the root of trust. This involves changing the keybox and DRM Cert methods and adding in new stubs for OEM Certificates. The WvKeybox now uses a RAII-like interface to ensure that keyboxes are provisioned correctly or not at all. Bug: 135283522 Test: oemcrypto_unittests ce_cdm_tests Change-Id: I3f2baf29c1022e1806b6196fa6650d761785c626
264 lines
8.9 KiB
C++
264 lines
8.9 KiB
C++
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
|
|
// source code may only be used and distributed under the Widevine Master
|
|
// License Agreement.
|
|
//
|
|
// Reference implementation of OEMCrypto APIs
|
|
//
|
|
#ifndef REF_OEMCRYPTO_ENGINE_REF_H_
|
|
#define REF_OEMCRYPTO_ENGINE_REF_H_
|
|
|
|
#include <stdint.h>
|
|
#include <time.h>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <vector>
|
|
|
|
#include <openssl/rsa.h>
|
|
|
|
#include "OEMCryptoCENC.h"
|
|
#include "file_store.h"
|
|
#include "oemcrypto_auth_ref.h"
|
|
#include "oemcrypto_key_ref.h"
|
|
#include "oemcrypto_rsa_key_shared.h"
|
|
#include "oemcrypto_session.h"
|
|
#include "oemcrypto_types.h"
|
|
#include "oemcrypto_usage_table_ref.h"
|
|
|
|
namespace wvoec_ref {
|
|
|
|
typedef std::map<SessionId, SessionContext*> ActiveSessions;
|
|
|
|
static const std::string kStoredUsageTimeFileName = "StoredUsageTime.dat";
|
|
|
|
typedef struct {
|
|
// The max time recorded
|
|
int64_t previous_time;
|
|
// If the wall time is rollbacked to before the previous_time, this member
|
|
// is updated to reflect the offset.
|
|
int64_t rollback_offset;
|
|
// Pad the struct so that TimeInfo is a multiple of 16.
|
|
uint8_t padding[16 - (2 * sizeof(time_t)) % 16];
|
|
} TimeInfo;
|
|
|
|
// Session types are higher (32 - kSessionIdTypeShift) bits in SessionId.
|
|
typedef enum SessionType {
|
|
kSessionTypeOEMCrypto = 0,
|
|
kSessionTypeEntitledKey = 1,
|
|
} SessionType;
|
|
|
|
class CryptoEngine {
|
|
public:
|
|
static const uint32_t kApiVersion = 16;
|
|
static const uint32_t kMinorApiVersion = 3;
|
|
static const int64_t kTimeInfoUpdateWindowInSeconds = 300;
|
|
|
|
// This is like a factory method, except we choose which version to use at
|
|
// compile time. It is defined in several source files. The build system
|
|
// should choose which one to use by only linking in the correct one.
|
|
// NOTE: The caller must instantiate a FileSystem object - ownership
|
|
// will be transferred to the new CryptoEngine object.
|
|
static CryptoEngine* MakeCryptoEngine(
|
|
std::unique_ptr<wvcdm::FileSystem>&& file_system);
|
|
|
|
virtual ~CryptoEngine();
|
|
|
|
virtual bool Initialize();
|
|
|
|
bool ValidRootOfTrust() const { return root_of_trust_.IsValid(); }
|
|
|
|
OEMCryptoResult InstallKeybox(const uint8_t* keybox, size_t keybox_length) {
|
|
return root_of_trust_.InstallKeybox(keybox, keybox_length);
|
|
}
|
|
|
|
OEMCryptoResult InstallTestKeybox(const uint8_t* keybox_data,
|
|
size_t keybox_length) {
|
|
return root_of_trust_.InstallTestKeybox(keybox_data, keybox_length);
|
|
}
|
|
|
|
OEMCryptoResult LoadTestRsaKey() { return root_of_trust_.LoadTestRsaKey(); }
|
|
|
|
OEMCryptoResult IsKeyboxValid() const {
|
|
return root_of_trust_.IsKeyboxValid();
|
|
}
|
|
|
|
std::vector<uint8_t> DeviceRootKey() const {
|
|
return root_of_trust_.DeviceKey();
|
|
}
|
|
|
|
OEMCryptoResult GetDeviceRootId(uint8_t* device_id,
|
|
size_t* device_id_length) const {
|
|
return root_of_trust_.GetDeviceId(device_id, device_id_length);
|
|
}
|
|
|
|
std::vector<uint8_t> DeviceRootId() const {
|
|
return root_of_trust_.DeviceId();
|
|
}
|
|
|
|
OEMCryptoResult GetRootKeyData(uint8_t* key_data,
|
|
size_t* key_data_length) const {
|
|
return root_of_trust_.GetKeyData(key_data, key_data_length);
|
|
}
|
|
|
|
virtual void Terminate();
|
|
|
|
virtual SessionId OpenSession();
|
|
|
|
virtual bool DestroySession(SessionId sid);
|
|
|
|
SessionContext* FindSession(SessionId sid);
|
|
|
|
size_t GetNumberOfOpenSessions() { return sessions_.size(); }
|
|
|
|
size_t GetMaxNumberOfSessions() {
|
|
// An arbitrary limit for ref implementation.
|
|
static const size_t kMaxSupportedOEMCryptoSessions = 64;
|
|
return kMaxSupportedOEMCryptoSessions;
|
|
}
|
|
|
|
// The OEMCrypto system time. Prevents time rollback.
|
|
int64_t SystemTime();
|
|
|
|
// Verify that this nonce does not collide with another nonce in any session.
|
|
virtual bool NonceCollision(uint32_t nonce);
|
|
|
|
// Returns the HDCP version currently in use.
|
|
virtual OEMCrypto_HDCP_Capability config_current_hdcp_capability();
|
|
|
|
// Returns the max HDCP version supported.
|
|
virtual OEMCrypto_HDCP_Capability config_maximum_hdcp_capability();
|
|
|
|
// Return true if there might be analog video output enabled.
|
|
virtual bool analog_display_active() { return !config_local_display_only(); }
|
|
|
|
// Return true if there is an analog display, and CGMS A is turned on.
|
|
virtual bool cgms_a_active() { return false; }
|
|
|
|
// Return the analog output flags.
|
|
virtual uint32_t analog_output_flags() {
|
|
return config_local_display_only() ? OEMCrypto_No_Analog_Output
|
|
: OEMCrypto_Supports_Analog_Output;
|
|
}
|
|
|
|
UsageTable& usage_table() { return *(usage_table_.get()); }
|
|
wvcdm::FileSystem* file_system() { return file_system_.get(); }
|
|
|
|
// If config_local_display_only() returns true, we pretend we are using a
|
|
// built-in display, instead of HDMI or WiFi output.
|
|
virtual bool config_local_display_only() { return false; }
|
|
|
|
// A closed platform is permitted to use clear buffers.
|
|
virtual bool config_closed_platform() { return false; }
|
|
|
|
// Returns true if the client supports persistent storage of
|
|
// offline usage table information.
|
|
virtual bool config_supports_usage_table() { return true; }
|
|
|
|
virtual OEMCrypto_ProvisioningMethod config_provisioning_method() {
|
|
return OEMCrypto_Keybox;
|
|
}
|
|
|
|
virtual OEMCryptoResult get_oem_certificate(uint8_t* public_cert,
|
|
size_t* public_cert_length) {
|
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
virtual OEMCryptoResult load_oem_private_key(SessionContext* session) {
|
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
// Used for OEMCrypto_IsAntiRollbackHwPresent.
|
|
virtual bool config_is_anti_rollback_hw_present() { return false; }
|
|
|
|
// Returns "L3" for a software only library. L1 is for hardware protected
|
|
// data paths.
|
|
virtual const char* config_security_level() { return "L3"; }
|
|
|
|
// This should start at 0, and be incremented only when a security patch has
|
|
// been applied to the device that fixes a security bug.
|
|
virtual uint8_t config_security_patch_level() { return 0; }
|
|
|
|
// If 0 no restriction, otherwise it's the max subsample size for
|
|
// DecryptCENC. This is not the same as the max sample or buffer size.
|
|
virtual size_t max_subsample_size() { return 4 * 1024 * 1024; } // 4 MiB
|
|
|
|
// If 0 no restriction, otherwise it's the max sample size for DecryptCENC.
|
|
// This is the same as the max input and output buffer size for DecryptCENC
|
|
// and CopyBuffer. It is not the same as the max subsample size.
|
|
virtual size_t max_sample_size() { return 16 * 1024 * 1024; } // 16 MiB
|
|
|
|
virtual bool srm_update_supported() { return false; }
|
|
|
|
virtual OEMCryptoResult current_srm_version(uint16_t* version) {
|
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
virtual OEMCryptoResult load_srm(const uint8_t* buffer,
|
|
size_t buffer_length) {
|
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
virtual OEMCryptoResult remove_srm() {
|
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
virtual bool srm_forbidden_device_attached() { return false; }
|
|
|
|
// Rate limit for nonce generation. Default to 200 nonce/second.
|
|
virtual int nonce_flood_count() { return 200; }
|
|
|
|
// Limit for size of usage table. If this is zero, then the
|
|
// size is unlimited -- or limited only by memory size.
|
|
virtual size_t max_usage_table_size() { return 0; }
|
|
|
|
virtual uint32_t resource_rating() { return 1; }
|
|
|
|
// Set destination pointer based on the output destination description.
|
|
OEMCryptoResult SetDestination(
|
|
const OEMCrypto_DestBufferDesc& out_description, size_t data_length,
|
|
uint8_t subsample_flags);
|
|
|
|
// The current destination.
|
|
uint8_t* destination() { return destination_; }
|
|
|
|
// Subclasses can adjust the destination -- for use in testing.
|
|
virtual void adjust_destination(
|
|
const OEMCrypto_DestBufferDesc& out_description, size_t data_length,
|
|
uint8_t subsample_flags) {}
|
|
|
|
// Push destination buffer to output -- used by subclasses for testing.
|
|
virtual OEMCryptoResult PushDestination(
|
|
const OEMCrypto_DestBufferDesc& out_description,
|
|
uint8_t subsample_flags) {
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
// Get the session type bits from |sid|.
|
|
static uint32_t SessionTypeBits(SessionId sid);
|
|
|
|
protected:
|
|
// System clock, measuring time in seconds, including anti-rollback offset.
|
|
int64_t MonotonicTime();
|
|
|
|
bool LoadOfflineTimeInfo(const std::string& file_path);
|
|
bool SaveOfflineTimeInfo(const std::string& file_path);
|
|
std::string GetUsageTimeFileFullPath() const;
|
|
|
|
explicit CryptoEngine(std::unique_ptr<wvcdm::FileSystem>&& file_system);
|
|
virtual SessionContext* MakeSession(SessionId sid);
|
|
virtual UsageTable* MakeUsageTable();
|
|
uint8_t* destination_;
|
|
ActiveSessions sessions_;
|
|
AuthenticationRoot root_of_trust_;
|
|
std::mutex session_table_lock_;
|
|
std::unique_ptr<wvcdm::FileSystem> file_system_;
|
|
std::unique_ptr<UsageTable> usage_table_;
|
|
TimeInfo offline_time_info_;
|
|
|
|
CORE_DISALLOW_COPY_AND_ASSIGN(CryptoEngine);
|
|
};
|
|
|
|
} // namespace wvoec_ref
|
|
|
|
#endif // REF_OEMCRYPTO_ENGINE_REF_H_
|