Merge of http://go/wvgerrit/93404 This CL updates the Widevine CDM to support OEMCrypto v16.1 Test: Tested in 16.2 CL Bug: 141247171 Change-Id: I69bd993500f6fb63bf6010c8b0250dc7acc3d71b
307 lines
14 KiB
C++
307 lines
14 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_shared.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,
|
|
const RSA_shared_ptr& rsa_key);
|
|
SessionContext() = delete;
|
|
virtual ~SessionContext();
|
|
|
|
bool isValid() { return valid_; }
|
|
|
|
virtual bool DeriveKeys(const std::vector<uint8_t>& master_key,
|
|
const std::vector<uint8_t>& mac_context,
|
|
const std::vector<uint8_t>& enc_context);
|
|
virtual bool 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 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);
|
|
// The size of an RSA signature. This is used when signing as a CAST
|
|
// receiver.
|
|
size_t RSASignatureSize();
|
|
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 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);
|
|
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_; }
|
|
uint32_t allowed_schemes() const { return allowed_schemes_; }
|
|
|
|
// 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();
|
|
// Signature size when using a keybox or OEM Cert's private key.
|
|
size_t ROTSignatureSize();
|
|
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);
|
|
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_;
|
|
SessionContextKeys* session_keys_;
|
|
ODK_NonceValues nonce_values_;
|
|
uint8_t license_request_hash_[ODK_SHA256_HASH_SIZE];
|
|
RSA_shared_ptr rsa_key_;
|
|
uint32_t allowed_schemes_; // for RSA signatures.
|
|
bool decrypt_started_; // If the license has been used in this session.
|
|
ODK_TimerLimits timer_limits_;
|
|
ODK_ClockValues clock_values_;
|
|
UsageTableEntry* usage_entry_;
|
|
SRMVersionStatus srm_requirements_status_;
|
|
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_;
|
|
|
|
// These are used when doing full decrypt path testing.
|
|
bool compute_hash_; // True if the current frame needs a hash.
|
|
uint32_t current_hash_; // Running CRC hash of frame.
|
|
uint32_t given_hash_; // True CRC hash of frame.
|
|
uint32_t current_frame_number_; // Current frame for CRC hash.
|
|
uint32_t bad_frame_number_; // Frame number with bad hash.
|
|
OEMCryptoResult hash_error_; // 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_;
|
|
bool state_request_signed_;
|
|
bool state_response_loaded_;
|
|
|
|
CORE_DISALLOW_COPY_AND_ASSIGN(SessionContext);
|
|
};
|
|
|
|
} // namespace wvoec_ref
|
|
|
|
#endif // REF_OEMCRYPTO_SESSION_H_
|