The sc-dev branch on Android is out of sync with several important changes on the CDM master branch. This changes copies several CLs. [ Merge of http://go/wvgerrit/104524 ] OEMCrypto unittest: generic crypto APIs Add unit tests to verify that generic crypto APIs do not crash for large input buffer lengths and signature lengths. [ Merge of http://go/wvgerrit/106583 ] Fix secure buffer tests in OEMCrypto testbed The secure buffers were not being used correctly in the testbed, and were failing OEMCryptoMemoryCopyBufferForHugeBufferLengths. [ Merge of http://go/wvgerrit/109603 ] Reject block_offsets of 16 or greater in OEC Ref This is a potential security hole. We will be enforcing that OEMCrypto rejects this in an upcoming test, so the Ref must be updated to reject it. [ Merge of http://go/wvgerrit/110165 ] Fix Format String Signedness See above for full description. [ Merge of http://go/wvgerrit/111784 ] Fix heap overflow test in L3 and OEMCrypto ref Check the length of wrapped_rsa_key_length before casting to WrappedRSAKey struct. [ Merge of http://go/wvgerrit/113563 ] Reword "blacklisted" to "forbidden" [ Merge of http://go/wvgerrit/113583 ] Use error code from RAND_bytes The return code from RAND_bytes was not used correctly. [ Merge of http://go/wvgerrit/113644 ] Check for buffer overflow when computing subsample size The test DecryptCENCForNumBytesClearPlusEncryptedOverflowsSize cleverly picks num_bytes_clear + num_bytes_encrypted = 1 after integer overflow. This is in the refernce code, level 3, and odkitee. [ Merge of http://go/wvgerrit/113683 ] OEMCrypto reference code: respect analog flags for clear buffers The reference code should honor the analog_display_active flag for both clear and secure buffers. [ Merge of http://go/wvgerrit/114883 ] Add size check for IV in OEMCrypto APIs IV is supposed to be 16 bytes but the size is never checked before iv gets used in LoadProvisioning. Bug: 145026457 Bug: 147569428 Bug: 159847851 Bug: 162372059 Bug: 169278035 Bug: 169980065 Bug: 173460694 Bug: 173994023 Bug: 174523584 Bug: 175001473 Bug: 175041667 Test: No compiled files changed Change-Id: If0ccd1cd3a56f72eedd2a6cb202a34bc7b43ca0d
255 lines
8.6 KiB
C++
255 lines
8.6 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() { return root_of_trust_.Validate(); }
|
|
|
|
bool InstallKeybox(const uint8_t* keybox, size_t keybox_length) {
|
|
return root_of_trust_.InstallKeybox(keybox, keybox_length);
|
|
}
|
|
|
|
bool UseTestKeybox(const uint8_t* keybox_data, size_t keybox_length) {
|
|
return root_of_trust_.UseTestKeybox(keybox_data, keybox_length);
|
|
}
|
|
|
|
bool LoadTestRsaKey() { return root_of_trust_.LoadTestRsaKey(); }
|
|
|
|
KeyboxError ValidateKeybox() { return root_of_trust_.ValidateKeybox(); }
|
|
|
|
const std::vector<uint8_t>& DeviceRootKey() {
|
|
return root_of_trust_.DeviceKey();
|
|
}
|
|
|
|
const std::vector<uint8_t>& DeviceRootId() {
|
|
return root_of_trust_.DeviceId();
|
|
}
|
|
|
|
size_t DeviceRootTokenLength() { return root_of_trust_.DeviceTokenLength(); }
|
|
|
|
const uint8_t* DeviceRootToken() { return root_of_trust_.DeviceToken(); }
|
|
|
|
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_
|