[ Merge of http://go/wvgerrit/116944 ] This change is the last part of a three part change for restructing the root of trust used by the reference implementation. OEM Certificates are now managed by the root of trust of the crypto engine. Previously, OEM certs where handled separately on a session by session basis. Bug: 135283522 Test: oemcrypto_unittests ce_cdm_tests Change-Id: I6cf1fa3fade28baad85b5fce57a8eab6f2ed17c1
313 lines
15 KiB
C++
313 lines
15 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_SESSION_H_
|
|
#define REF_OEMCRYPTO_SESSION_H_
|
|
|
|
#include <stdint.h>
|
|
#include <time.h>
|
|
#include <map>
|
|
#include <vector>
|
|
|
|
#include <openssl/rsa.h>
|
|
|
|
#include "OEMCryptoCENC.h"
|
|
#include "odk_structs.h"
|
|
#include "oemcrypto_auth_ref.h"
|
|
#include "oemcrypto_key_ref.h"
|
|
#include "oemcrypto_rsa_key.h"
|
|
#include "oemcrypto_session_key_table.h"
|
|
#include "oemcrypto_types.h"
|
|
#include "oemcrypto_usage_table_ref.h"
|
|
|
|
namespace wvoec_ref {
|
|
|
|
class CryptoEngine;
|
|
typedef uint32_t SessionId;
|
|
|
|
enum SRMVersionStatus { NoSRMVersion, ValidSRMVersion, InvalidSRMVersion };
|
|
|
|
// TODO(jfore): Is there a better name?
|
|
class SessionContextKeys {
|
|
public:
|
|
virtual OEMCrypto_LicenseType type() = 0;
|
|
virtual size_t size() = 0;
|
|
virtual bool Insert(const KeyId& key_id, const Key& key_data) = 0;
|
|
virtual Key* Find(const KeyId& key_id) = 0;
|
|
virtual Key* FirstKey() = 0;
|
|
virtual void Remove(const KeyId& key_id) = 0;
|
|
virtual void UpdateDuration(const KeyControlBlock& control) = 0;
|
|
|
|
// Methods supported exclusively for entitlement keys. Returns false if
|
|
// entitlement keys are not found or not supported by the current key table.
|
|
// It is the caller's responsibility to check the context.
|
|
virtual bool SetContentKey(const KeyId& entitlement_id,
|
|
const KeyId& content_key_id,
|
|
const std::vector<uint8_t>& content_key) = 0;
|
|
virtual EntitlementKey* GetEntitlementKey(const KeyId& entitlement_id) = 0;
|
|
|
|
virtual ~SessionContextKeys() {}
|
|
|
|
protected:
|
|
SessionContextKeys() {}
|
|
|
|
private:
|
|
CORE_DISALLOW_COPY_AND_ASSIGN(SessionContextKeys);
|
|
};
|
|
|
|
class SessionContext {
|
|
public:
|
|
SessionContext(CryptoEngine* ce, SessionId sid);
|
|
SessionContext(CryptoEngine* ce, SessionId sid,
|
|
std::shared_ptr<RsaPrivateKey>&& rsa_key);
|
|
SessionContext() = delete;
|
|
virtual ~SessionContext();
|
|
|
|
bool isValid() const { return valid_; }
|
|
|
|
virtual OEMCryptoResult DeriveKeys(const std::vector<uint8_t>& master_key,
|
|
const std::vector<uint8_t>& mac_context,
|
|
const std::vector<uint8_t>& enc_context);
|
|
virtual OEMCryptoResult RSADeriveKeys(
|
|
const std::vector<uint8_t>& enc_session_key,
|
|
const std::vector<uint8_t>& mac_context,
|
|
const std::vector<uint8_t>& enc_context);
|
|
|
|
virtual OEMCryptoResult LoadOemPrivateKey();
|
|
|
|
virtual OEMCryptoResult PrepAndSignLicenseRequest(uint8_t* message,
|
|
size_t message_length,
|
|
size_t* core_message_length,
|
|
uint8_t* signature,
|
|
size_t* signature_length);
|
|
virtual OEMCryptoResult PrepAndSignRenewalRequest(uint8_t* message,
|
|
size_t message_length,
|
|
size_t* core_message_length,
|
|
uint8_t* signature,
|
|
size_t* signature_length);
|
|
virtual OEMCryptoResult PrepAndSignProvisioningRequest(
|
|
uint8_t* message, size_t message_length, size_t* core_message_length,
|
|
uint8_t* signature, size_t* signature_length);
|
|
// Restricted to CAST receivers using PKCS1 block padding only.
|
|
virtual OEMCryptoResult GenerateRSASignature(
|
|
const uint8_t* message, size_t message_length, uint8_t* signature,
|
|
size_t* signature_length, RSA_Padding_Scheme padding_scheme);
|
|
virtual bool ValidateMessage(const uint8_t* message, size_t message_length,
|
|
const uint8_t* signature,
|
|
size_t signature_length);
|
|
OEMCryptoResult DecryptSamples(
|
|
const OEMCrypto_SampleDescription* samples, size_t samples_length,
|
|
const OEMCrypto_CENCEncryptPatternDesc* pattern);
|
|
|
|
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);
|
|
virtual OEMCryptoResult LoadLicense(const uint8_t* message,
|
|
size_t message_length,
|
|
size_t core_message_length,
|
|
const uint8_t* signature,
|
|
size_t signature_length);
|
|
virtual OEMCryptoResult LoadKeys(
|
|
const uint8_t* message, size_t message_length, const uint8_t* signature,
|
|
size_t signature_length, OEMCrypto_Substring enc_mac_keys_iv,
|
|
OEMCrypto_Substring enc_mac_keys, size_t num_keys,
|
|
const OEMCrypto_KeyObject* key_array, OEMCrypto_Substring pst,
|
|
OEMCrypto_Substring srm_restriction_data,
|
|
OEMCrypto_LicenseType license_type);
|
|
virtual OEMCryptoResult LoadKeysNoSignature(
|
|
const uint8_t* message, size_t message_length,
|
|
OEMCrypto_Substring enc_mac_keys_iv, OEMCrypto_Substring enc_mac_keys,
|
|
size_t num_keys, const OEMCrypto_KeyObject* key_array,
|
|
OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data,
|
|
OEMCrypto_LicenseType license_type);
|
|
virtual OEMCryptoResult LoadEntitledContentKeys(
|
|
const uint8_t* message, size_t message_length, size_t key_array_length,
|
|
const OEMCrypto_EntitledContentKeyObject* key_array);
|
|
virtual 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 InstallRSAEncryptedKey(const std::vector<uint8_t>& enc_encryption_key);
|
|
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 LoadRsaDrmKey(const uint8_t* pkcs8_rsa_key, size_t rsa_key_length);
|
|
virtual OEMCryptoResult LoadRenewal(const uint8_t* message,
|
|
size_t message_length,
|
|
size_t core_message_length,
|
|
const uint8_t* signature,
|
|
size_t signature_length);
|
|
virtual OEMCryptoResult RefreshKey(
|
|
const KeyId& key_id, const std::vector<uint8_t>& key_control,
|
|
const std::vector<uint8_t>& key_control_iv);
|
|
virtual bool UpdateMacKeys(const std::vector<uint8_t>& mac_keys,
|
|
const std::vector<uint8_t>& iv);
|
|
virtual bool QueryKeyControlBlock(const KeyId& key_id, uint32_t* data);
|
|
virtual OEMCryptoResult SelectContentKey(const KeyId& key_id,
|
|
OEMCryptoCipherMode cipher_mode);
|
|
virtual OEMCryptoResult SetDecryptHash(uint32_t frame_number,
|
|
const uint8_t* hash,
|
|
size_t hash_length);
|
|
virtual OEMCryptoResult GetHashErrorCode(uint32_t* failed_frame_number);
|
|
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_; }
|
|
|
|
// Return true if nonce was set.
|
|
bool set_nonce(uint32_t nonce);
|
|
uint32_t nonce() const { return nonce_values_.nonce; }
|
|
ODK_NonceValues& nonce_values() { return nonce_values_; }
|
|
|
|
bool CheckNonce(uint32_t nonce) const {
|
|
return nonce != 0 && nonce == nonce_values_.nonce;
|
|
};
|
|
|
|
virtual OEMCryptoResult CreateNewUsageEntry(uint32_t* usage_entry_number);
|
|
virtual OEMCryptoResult LoadUsageEntry(uint32_t index,
|
|
const std::vector<uint8_t>& buffer);
|
|
virtual OEMCryptoResult UpdateUsageEntry(uint8_t* header_buffer,
|
|
size_t* header_buffer_length,
|
|
uint8_t* entry_buffer,
|
|
size_t* entry_buffer_length);
|
|
virtual OEMCryptoResult DeactivateUsageEntry(const std::vector<uint8_t>& pst);
|
|
virtual OEMCryptoResult ReportUsage(const std::vector<uint8_t>& pst,
|
|
uint8_t* buffer, size_t* buffer_length);
|
|
OEMCryptoResult MoveEntry(uint32_t new_index);
|
|
bool usage_entry_present() const { return usage_entry_ != nullptr; }
|
|
|
|
protected:
|
|
// Signature size of the currently loaded private key.
|
|
size_t CertSignatureSize() const;
|
|
// Signature size when using a keybox or OEM Cert's private key.
|
|
size_t ROTSignatureSize() const;
|
|
virtual OEMCryptoResult GenerateCertSignature(const uint8_t* message,
|
|
size_t message_length,
|
|
uint8_t* signature,
|
|
size_t* signature_length);
|
|
virtual OEMCryptoResult GenerateSignature(const uint8_t* message,
|
|
size_t message_length,
|
|
uint8_t* signature,
|
|
size_t* signature_length);
|
|
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,
|
|
uint32_t key_size); // AES key size, in bits.
|
|
// 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 DecryptSubsample(
|
|
const OEMCrypto_SubSampleDescription& subsample,
|
|
const uint8_t* cipher_data, uint8_t* clear_data,
|
|
OEMCryptoBufferType buffer_type, const uint8_t (&iv)[wvoec::KEY_IV_SIZE],
|
|
const OEMCrypto_CENCEncryptPatternDesc* pattern);
|
|
OEMCryptoResult ChooseDecrypt(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,
|
|
OEMCryptoBufferType buffer_type);
|
|
OEMCryptoResult PatternDecryptCBC(
|
|
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 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);
|
|
|
|
bool valid_ = false;
|
|
CryptoEngine* ce_ = nullptr;
|
|
SessionId id_;
|
|
|
|
// Message keys.
|
|
std::shared_ptr<RsaPrivateKey> rsa_key_;
|
|
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_;
|
|
|
|
ODK_NonceValues nonce_values_;
|
|
uint8_t license_request_hash_[ODK_SHA256_HASH_SIZE];
|
|
|
|
// Content/entitlement keys.
|
|
const Key* current_content_key_ = nullptr;
|
|
std::unique_ptr<SessionContextKeys> session_keys_;
|
|
|
|
bool decrypt_started_ =
|
|
false; // If the license has been used in this session.
|
|
ODK_TimerLimits timer_limits_;
|
|
ODK_ClockValues clock_values_;
|
|
std::unique_ptr<UsageTableEntry> usage_entry_;
|
|
SRMVersionStatus srm_requirements_status_ = NoSRMVersion;
|
|
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_ = kNoUsageEntry;
|
|
|
|
// These are used when doing full decrypt path testing.
|
|
bool compute_hash_ = false; // True if the current frame needs a hash.
|
|
uint32_t current_hash_ = 0; // Running CRC hash of frame.
|
|
uint32_t given_hash_ = 0; // True CRC hash of frame.
|
|
uint32_t current_frame_number_ = 0; // Current frame for CRC hash.
|
|
uint32_t bad_frame_number_ = 0; // Frame number with bad hash.
|
|
OEMCryptoResult hash_error_ =
|
|
OEMCrypto_SUCCESS; // Error code for first bad frame.
|
|
|
|
// The bare minimum state machine is to only call each of these function
|
|
// categories at most once.
|
|
bool state_nonce_created_ = false;
|
|
bool state_request_signed_ = false;
|
|
bool state_response_loaded_ = false;
|
|
|
|
CORE_DISALLOW_COPY_AND_ASSIGN(SessionContext);
|
|
};
|
|
|
|
} // namespace wvoec_ref
|
|
|
|
#endif // REF_OEMCRYPTO_SESSION_H_
|