Files
android/libwvdrmengine/oemcrypto/test/oec_session_util.h
Alex Dale d874fffaec Support 32 bytes session key
[ Merge of http://go/wvgerrit/149849 ]

With ECC based DRM cert, the session key is expected to be 32, as
compared to 16 bytes in RSA case. This CL adds supports for 32 bytes
session key.

Bug: 236317198
Test: oemcrypto_test
Change-Id: I657fdd92d17736a23375ddcd457f83efa6ca6d1f
2022-06-23 14:48:19 -07:00

746 lines
33 KiB
C++

#ifndef CDM_OEC_SESSION_UTIL_H_
#define CDM_OEC_SESSION_UTIL_H_
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// OEMCrypto unit tests
//
#include <gtest/gtest.h>
#include <time.h>
#include <string>
#include <vector>
#include "core_message_deserialize.h"
#include "core_message_features.h"
#include "core_message_serialize.h"
#include "odk.h"
#include "oec_device_features.h"
#include "oec_key_deriver.h"
#include "oemcrypto_ecc_key.h"
#include "oemcrypto_fuzz_structs.h"
#include "oemcrypto_rsa_key.h"
#include "oemcrypto_types.h"
#include "pst_report.h"
using namespace std;
// GTest requires PrintTo to be in the same namespace as the thing it prints,
// which is std::vector in this case.
namespace std {
void PrintTo(const vector<uint8_t>& value, ostream* os);
} // namespace std
namespace wvoec {
// OEMCrypto Fuzzing: Set max signture length to 1mb.
const size_t MB = 1024 * 1024;
// Make sure this is larger than kMaxKeysPerSession, in oemcrypto_test.cpp
constexpr size_t kMaxNumKeys = 30;
namespace {
#if defined(TEST_SPEED_MULTIPLIER) // Can slow test time limits when
// debugging is slowing everything.
constexpr int kSpeedMultiplier = TEST_SPEED_MULTIPLIER;
#else
constexpr int kSpeedMultiplier = 1;
#endif
constexpr int kShortSleep = 1 * kSpeedMultiplier;
constexpr int kLongSleep = 2 * kSpeedMultiplier;
constexpr uint32_t kDuration = 2 * kSpeedMultiplier;
constexpr uint32_t kLongDuration = 5 * kSpeedMultiplier;
constexpr int32_t kTimeTolerance = 3 * kSpeedMultiplier;
constexpr int64_t kUsageTableTimeTolerance = 10 * kSpeedMultiplier;
} // namespace
// Note: The API does not specify a maximum key id length. We specify a
// maximum just for these tests, so that we have a fixed message size.
constexpr size_t kTestKeyIdMaxLength = 16;
// Most content will use a key id that is 16 bytes long.
constexpr int kDefaultKeyIdLength = 16;
constexpr size_t kMaxPSTLength = 255; // In specification.
constexpr size_t kMaxCoreMessage = 200 * kMaxNumKeys + 200; // Rough estimate.
typedef struct {
uint8_t key_id[kTestKeyIdMaxLength];
size_t key_id_length;
uint8_t key_data[MAC_KEY_SIZE];
size_t key_data_length;
uint8_t key_iv[KEY_IV_SIZE];
uint8_t control_iv[KEY_IV_SIZE];
KeyControlBlock control;
// Note: cipher_mode may not be part of a real signed message. For these
// tests, it is convenient to keep it in this structure anyway.
OEMCryptoCipherMode cipher_mode;
} MessageKeyData;
// This structure will be signed to simulate a message from the server.
struct MessageData {
MessageKeyData keys[kMaxNumKeys];
uint8_t mac_key_iv[KEY_IV_SIZE];
uint8_t padding[KEY_IV_SIZE];
uint8_t mac_keys[2 * MAC_KEY_SIZE];
uint8_t pst[kMaxPSTLength];
SRM_Restriction_Data srm_restriction_data;
};
struct Test_PST_Report {
Test_PST_Report(const std::string& pst_in,
OEMCrypto_Usage_Entry_Status status_in);
OEMCrypto_Usage_Entry_Status status;
int64_t seconds_since_license_received;
int64_t seconds_since_first_decrypt;
int64_t seconds_since_last_decrypt;
std::string pst;
int64_t time_created;
};
struct EntitledContentKeyData {
uint8_t entitlement_key_id[kTestKeyIdMaxLength];
size_t entitlement_key_id_length;
uint8_t content_key_id[kTestKeyIdMaxLength];
size_t content_key_id_length;
uint8_t content_key_data_iv[KEY_IV_SIZE];
uint8_t content_key_data[KEY_SIZE];
uint8_t encrypted_content_key_data[KEY_SIZE];
size_t key_index; // Index into the license's key array. Only for testing.
};
// returns 1 on success, -1 if not supported, or 0 if other failure.
int GetRandBytes(unsigned char* buf, size_t num);
void GenerateSimpleSampleDescription(const std::vector<uint8_t>& in,
std::vector<uint8_t>& out,
OEMCrypto_SampleDescription* sample,
OEMCrypto_SubSampleDescription* subsample);
// Increment counter for AES-CTR. The CENC spec specifies we increment only
// the low 64 bits of the IV counter, and leave the high 64 bits alone. This
// is different from the OpenSSL implementation, so we implement the CTR loop
// ourselves.
void ctr128_inc64(int64_t increaseBy, uint8_t* iv);
// Some compilers don't like the macro htonl within an ASSERT_EQ.
uint32_t htonl_fnc(uint32_t x);
// Prints error string from BoringSSL
void dump_boringssl_error();
class Session;
// The prototype of the OEMCrypto function to prepare and sign a request.
typedef OEMCryptoResult (*PrepAndSignRequest_t)(
OEMCrypto_SESSION session, uint8_t* message, size_t message_length,
size_t* core_message_length, uint8_t* signature, size_t* signature_length);
// A RoundTrip helps generate and verify a request message, helps generate the
// corresponding response, and then helps verify loading the response.
template <class CoreRequest, PrepAndSignRequest_t PrepAndSignRequest,
class CoreResponse, class ResponseData>
class RoundTrip {
public:
RoundTrip() = delete;
RoundTrip(Session* session)
: session_(session),
core_request_(),
core_response_(),
response_data_(),
encrypted_response_data_(),
required_message_size_(0),
required_core_message_size_(0),
required_request_signature_size_(0) {}
virtual ~RoundTrip() {}
// Have OEMCrypto sign a request message and then verify the signature and the
// core message.
virtual void SignAndVerifyRequest() {
// Boolean true generates core request and verifies the request.
// Custom message sizes are 0 by default, so the behavior of following
// functions will be sign and verify request without any custom buffers
// sizes.
ASSERT_EQ(SignAndCreateRequestWithCustomBufferLengths(true),
OEMCrypto_SUCCESS);
}
// Have OEMCrypto sign and call create request APIs. Buffer parameters in API
// can be set to custom values to test with varying lengths of buffers.
virtual OEMCryptoResult SignAndCreateRequestWithCustomBufferLengths(
bool verify_request = false);
// Used for OEMCrypto Fuzzing: Function to convert fuzzer data to valid
// License/Provisioning/Renwal request data that can be serialized.
virtual void InjectFuzzedRequestData(uint8_t* data, size_t size);
// Create a default |response_data| and |core_response|.
virtual void CreateDefaultResponse() = 0;
// Copy fields from |response_data| to |padded_response_data|, encrypting
// those that should be encrypted. Serialize the core message. Then sign the
// response.
virtual void EncryptAndSignResponse() = 0;
// Attempt to load the response and return the error. Short buffer errors are
// handled by LoadResponse, not the caller. All other errors should be
// handled by the caller.
virtual OEMCryptoResult LoadResponse() { return LoadResponse(session_); }
// As with LoadResponse, but load into a different session.
virtual OEMCryptoResult LoadResponse(Session* session) = 0;
// Accessors are all read/write because tests modify default values.
Session* session() { return session_; }
void set_session(Session* session) { session_ = session; }
CoreRequest& core_request() { return core_request_; }
CoreResponse& core_response() { return core_response_; }
ResponseData& response_data() { return response_data_; }
std::vector<uint8_t>& encrypted_response_buffer() {
return encrypted_response_;
}
// Set the size of the buffer used the encrypted license.
void set_message_size(size_t size) { required_message_size_ = size; }
// Set core message size to test OEMCrypto request APIs for varying core
// message lengths.
void set_core_message_size(size_t size) {
required_core_message_size_ = size;
}
// Set signature size to test OEMCrypto request APIs for varying signature
// lengths.
void set_request_signature_size(size_t size) {
required_request_signature_size_ = size;
}
std::vector<uint8_t>& response_signature() { return response_signature_; }
const std::string& serialized_core_message() const {
return serialized_core_message_;
}
protected:
// Returns true if a nonce should be generated before signing the request.
virtual bool RequestHasNonce() = 0;
// ----------------------------------------------------------------------
// Specialized functionality for each message type.
// Verify the signature of the request.
virtual void VerifyRequestSignature(
const vector<uint8_t>& data, const vector<uint8_t>& generated_signature,
size_t core_message_length) = 0;
// Verify the values of the core response.
virtual void FillAndVerifyCoreRequest(
const std::string& core_message_string) = 0;
// Find the given pointer in the response_data_.
virtual OEMCrypto_Substring FindSubstring(const void* pointer, size_t length);
// ----------------------------------------------------------------------
// Member variables.
Session* session_;
CoreRequest core_request_;
CoreResponse core_response_;
ResponseData response_data_, encrypted_response_data_;
// Message buffers will be at least this big. Tests for loading and signing
// messages will increase all buffers to this size.
size_t required_message_size_;
size_t required_core_message_size_;
size_t required_request_signature_size_;
std::vector<uint8_t> response_signature_;
std::string serialized_core_message_;
std::vector<uint8_t> encrypted_response_;
};
class ProvisioningRoundTrip
: public RoundTrip<
/* CoreRequest */ oemcrypto_core_message::ODK_ProvisioningRequest,
OEMCrypto_PrepAndSignProvisioningRequest,
/* CoreResponse */ ODK_ParsedProvisioning,
/* ResponseData */ RSAPrivateKeyMessage> {
public:
ProvisioningRoundTrip(Session* session,
const std::vector<uint8_t>& encoded_rsa_key)
: RoundTrip(session),
allowed_schemes_(kSign_RSASSA_PSS),
encryptor_(),
encoded_rsa_key_(encoded_rsa_key) {}
// Prepare the session for signing the request.
virtual void PrepareSession(const wvoec::WidevineKeybox& keybox);
void CreateDefaultResponse() override;
void EncryptAndSignResponse() override;
void EncryptAndSignResponseWithoutUpdatingEncPrivateKeyLength();
void SignResponse();
OEMCryptoResult LoadResponse() override { return LoadResponse(session_); }
OEMCryptoResult LoadResponse(Session* session) override;
void VerifyLoadFailed();
const std::vector<uint8_t>& encoded_rsa_key() { return encoded_rsa_key_; }
const std::vector<uint8_t>& wrapped_rsa_key() { return wrapped_rsa_key_; }
void set_allowed_schemes(uint32_t allowed_schemes) {
allowed_schemes_ = allowed_schemes;
}
// Used for OEMCrypto Fuzzing: Function to convert fuzzer data to valid
// provisioning response data that can be parsed. Calculates signature for
// data generated by fuzzer, so that signature validation passes when parsing
// provisioning response.
void InjectFuzzedResponseData(const uint8_t* data, size_t size);
protected:
bool RequestHasNonce() override { return true; }
void VerifyRequestSignature(const vector<uint8_t>& data,
const vector<uint8_t>& generated_signature,
size_t core_message_length) override;
// Verify the values of the core response.
virtual void FillAndVerifyCoreRequest(
const std::string& core_message_string) override;
// Load the response, without the retry. Called by LoadResponse.
OEMCryptoResult LoadResponseNoRetry(Session* session,
size_t* wrapped_key_length);
// This takes a pointer in the response_data_ and remaps it to the same
// pointer within the encrypted message. This is used for backwards
// compatibliity testing, so that a v15 oemcrypto will accept range checks.
template <typename T>
const T* RemapPointer(const T* response_pointer) const;
uint32_t allowed_schemes_;
Encryptor encryptor_;
// The message key used for Prov 3.0.
std::vector<uint8_t> message_key_;
std::vector<uint8_t> encrypted_message_key_;
std::vector<uint8_t> encoded_rsa_key_;
std::vector<uint8_t> wrapped_rsa_key_;
};
class LicenseRoundTrip
: public RoundTrip<
/* CoreRequest */ oemcrypto_core_message::ODK_LicenseRequest,
OEMCrypto_PrepAndSignLicenseRequest,
/* CoreResponse */ ODK_ParsedLicense,
/* ResponseData */ MessageData> {
public:
LicenseRoundTrip(Session* session)
: RoundTrip(session),
control_(wvoec::kControlNonceEnabled),
num_keys_(4),
pst_(""),
minimum_srm_version_(0),
update_mac_keys_(true),
api_version_(kCurrentAPI),
expect_request_has_correct_nonce_(true),
license_type_(OEMCrypto_ContentLicense),
request_hash_() {}
void CreateDefaultResponse() override;
// Used for OEMCrypto Fuzzing: Function to inject fuzzed timer limits
// into timer_limits field from core_response. We need to fuzz timer
// limits in order to efficiently fuzz load renewal response API.
void InjectFuzzedTimerLimits(OEMCrypto_Renewal_Response_Fuzz& fuzzed_data);
// Used for OEMCrypto Fuzzing: Function to convert fuzzer data to valid
// License response data that can be parsed. Calculates signature for data
// generated by fuzzer, so that signature validation passes when parsing
// license response.
void InjectFuzzedResponseData(const uint8_t* data, size_t size);
// Used for OEMCrypto Fuzzing: Convert boolean flags in parsed_license to
// valid bytes to avoid errors from msan.
void ConvertDataToValidBools(ODK_ParsedLicense* t);
// Create a license with four keys. Each key is responsible for one of generic
// encrypt (key 0), decrypt (key 1), sign (key 2) and verify (key 3). Each key
// is allowed only one type of operation.
void CreateResponseWithGenericCryptoKeys();
// Fill the |core_response| substrings.
virtual void FillCoreResponseSubstrings();
void EncryptAndSignResponse() override;
// Encrypt and sign license response created from a specific odk version.
void EncryptAndSignResponseWithCoreMessageFeatures(
const oemcrypto_core_message::features::CoreMessageFeatures& features,
bool force_clear_kcb);
// Encrypt license response. This is used in EncryptAndSignResponse().
void EncryptResponse(bool force_clear_kcb = false);
// Create core license response with a specific ODK version. This is used in
// EncryptAndSignResponse().
void CreateCoreLicenseResponseWithFeatures(
const oemcrypto_core_message::features::CoreMessageFeatures& features);
// Sign license response. This is used in EncryptAndSignResponse().
void SignEncryptedResponse();
OEMCryptoResult LoadResponse() override { return LoadResponse(session_); }
OEMCryptoResult LoadResponse(Session* session) override;
OEMCryptoResult LoadResponse(Session* session, bool verify_keys);
// Reload an offline license into a different session. This derives new mac
// keys and then calls LoadResponse.
OEMCryptoResult ReloadResponse(Session* session);
void VerifyTestKeys(Session* session);
// Set the default key control block for all keys. This is used in
// CreateDefaultResponse. The key control block determines the restrictions
// that OEMCrypto should place on a key's use. For example, it specifies the
// minimum HDCP requirement and whether the key can only be used with a secure
// video path. See the section "Key Control Block" in the document "Widevine
// Modular DRM Security Integration Guide for CENC".
void set_control(uint32_t control) { control_ = control; }
uint32_t control() const { return control_; }
// Set the number of keys to use in the license.
void set_num_keys(uint32_t num_keys) { num_keys_ = num_keys; }
uint32_t num_keys() const { return num_keys_; }
// Get/Set the pst for the license and usage table entry.
const std::string& pst() const { return pst_; }
void set_pst(const std::string& pst) { pst_ = pst; }
// Set the minimum SRM version for the license.
void set_minimum_srm_version(uint32_t minimum_srm_version) {
minimum_srm_version_ = minimum_srm_version;
}
// Change the hash of the core request. This should cause the response to be
// rejected.
void BreakRequestHash() { request_hash_[3] ^= 42; }
// Set the API version for the license itself. This will be used in
// CreateDefaultResponse.
void set_api_version(uint32_t api_version) { api_version_ = api_version; }
uint32_t api_version() const { return api_version_; }
void set_update_mac_keys(bool update_mac_keys) {
update_mac_keys_ = update_mac_keys;
}
void set_license_type(OEMCrypto_LicenseType license_type) {
license_type_ = license_type;
}
// Skip the nonce check when verifying the license request.
void skip_nonce_check() { expect_request_has_correct_nonce_ = false; }
// This sets the key id of the specified key to the specified string.
// This is used to test with different key id lengths.
void SetKeyId(size_t index, const string& key_id);
protected:
bool RequestHasNonce() override { return true; }
void VerifyRequestSignature(const vector<uint8_t>& data,
const vector<uint8_t>& generated_signature,
size_t core_message_length) override;
// Verify the values of the core response.
virtual void FillAndVerifyCoreRequest(
const std::string& core_message_string) override;
// The default key control bits used with CreateDefaultResponse.
uint32_t control_;
// The number of keys in the license response.
uint32_t num_keys_;
// If non-empty, the license's provider session token.
std::string pst_;
// If non-zero, the minimum SRM version.
uint32_t minimum_srm_version_;
// If true, the license contains new mac keys for signing renewals.
bool update_mac_keys_;
// API version for the license itself. If this is 0 when the license request
// is signed, it will be set to the same as OEMCrypto's API version. It may
// be set to a lower value in order to test backwards compatibility.
uint32_t api_version_;
// If true, then we expect the nonce in the core request to match that in
// session. This is usually true, but when we are testing how OEMCrypto
// handles a bad nonce, we don't want to.
bool expect_request_has_correct_nonce_;
// Whether this is a content license or an entitlement license. Used in
// CreateDefaultResponse.
OEMCrypto_LicenseType license_type_;
uint8_t request_hash_[ODK_SHA256_HASH_SIZE];
};
class RenewalRoundTrip
: public RoundTrip<
/* CoreRequest */ oemcrypto_core_message::ODK_RenewalRequest,
OEMCrypto_PrepAndSignRenewalRequest,
// Renewal response info is same as request:
/* CoreResponse */ oemcrypto_core_message::ODK_RenewalRequest,
/* ResponseData */ MessageData> {
public:
RenewalRoundTrip(LicenseRoundTrip* license_messages)
: RoundTrip(license_messages->session()),
license_messages_(license_messages),
refresh_object_(),
renewal_duration_seconds_(
license_messages->core_response()
.timer_limits.initial_renewal_duration_seconds),
is_release_(false) {}
void CreateDefaultResponse() override;
void EncryptAndSignResponse() override;
void InjectFuzzedResponseData(OEMCrypto_Renewal_Response_Fuzz& fuzzed_data,
const uint8_t* renewal_response,
const size_t renewal_response_size);
OEMCryptoResult LoadResponse() override { return LoadResponse(session_); }
OEMCryptoResult LoadResponse(Session* session) override;
uint64_t renewal_duration_seconds() const {
return renewal_duration_seconds_;
}
void set_renewal_duration_seconds(uint64_t renewal_duration_seconds) {
renewal_duration_seconds_ = renewal_duration_seconds;
}
void set_is_release(bool is_release) { is_release_ = is_release; }
protected:
bool RequestHasNonce() override { return false; }
void VerifyRequestSignature(const vector<uint8_t>& data,
const vector<uint8_t>& generated_signature,
size_t core_message_length) override;
// Verify the values of the core response.
virtual void FillAndVerifyCoreRequest(
const std::string& core_message_string) override;
LicenseRoundTrip* license_messages_;
OEMCrypto_KeyRefreshObject refresh_object_;
uint64_t renewal_duration_seconds_;
bool is_release_; // If this is a license release, and not a real renewal.
};
class EntitledMessage {
public:
EntitledMessage(LicenseRoundTrip* license_messages)
: license_messages_(license_messages), num_keys_() {}
void FillKeyArray();
void MakeOneKey(size_t entitlement_key_index);
void SetEntitledKeySession(uint32_t key_session) {
entitled_key_session_ = key_session;
}
void LoadKeys(OEMCryptoResult expected_sts);
OEMCryptoResult LoadKeys(const vector<uint8_t>& message);
OEMCryptoResult LoadKeys();
void EncryptContentKey();
void LoadCasKeys(bool load_even, bool load_odd, OEMCryptoResult expected_sts);
void set_num_keys(uint32_t num_keys) { num_keys_ = num_keys; }
uint32_t num_keys() const { return num_keys_; }
void SetEntitlementKeyId(unsigned int index, const std::string& key_id);
void SetContentKeyId(unsigned int index, const std::string& key_id);
OEMCrypto_EntitledContentKeyObject* entitled_key_array();
// Returns entitled_key_data_ which is used as input message buffer to
// load entitled content keys API.
EntitledContentKeyData* entitled_key_data();
size_t entitled_key_data_size();
// Verify that key control blocks of the loaded keys.
void VerifyEntitlementTestKeys();
void VerifyEntitlementTestKey(size_t index);
private:
// Find the offset of the give pointer, relative to |entitled_key_data_|.
OEMCrypto_Substring FindSubstring(const void* ptr, size_t size);
// Verify that key control blocks of the loaded keys matches their entitlement
// key.
void VerifyKCBs();
// Verify that decryption with the entitled keys works.
void VerifyDecrypt();
LicenseRoundTrip* license_messages_;
uint32_t num_keys_;
// Clear Entitlement key data. This is the backing data for
// |entitled_key_array_|.
EntitledContentKeyData entitled_key_data_[kMaxNumKeys];
// Entitled key object. Pointers are backed by |entitled_key_data_|.
OEMCrypto_EntitledContentKeyObject entitled_key_array_[kMaxNumKeys];
uint32_t entitled_key_session_;
};
class Session {
public:
Session();
~Session();
// Returns the most recently generated nonce.
// Valid after call to GenerateNonce.
uint32_t nonce() const { return nonce_; }
// The nonce can be overridden.
void set_nonce(uint32_t nonce) { nonce_ = nonce; }
// Valid after call to open().
uint32_t session_id() const { return (uint32_t)session_id_; }
// Call OEMCrypto_OpenSession, with GTest ASSERTs.
void open();
// Call OEMCrypto_CloseSession, with GTest ASSERTs.
void close();
// Artifically set session id without calling OEMCrypto_OpenSession. This is
// used in core/test/generic_crypto_unittest.cpp.
void SetSessionId(uint32_t session_id);
uint32_t GetOecSessionId() { return session_id_; }
// Generates one nonce. If error_counter is null, this will sleep 1 second
// and try again if a nonce flood has been detected. If error_counter is
// not null, it will be incremented when a nonce flood is detected.
void GenerateNonce(int* error_counter = nullptr);
// Fill the vectors with test context which generate known mac and enc keys.
void FillDefaultContext(vector<uint8_t>* mac_context,
vector<uint8_t>* enc_context);
// Generate known mac and enc keys using OEMCrypto_GenerateDerivedKeys and
// also fill out enc_key_, mac_key_server_, and mac_key_client_.
void GenerateDerivedKeysFromKeybox(const wvoec::WidevineKeybox& keybox);
// Generate known mac and enc keys using OEMCrypto_DeriveKeysFromSessionKey
// and also fill out enc_key_, mac_key_server_, and mac_key_client_.
void GenerateDerivedKeysFromSessionKey();
// Encrypt some data and pass to OEMCrypto_DecryptCENC to verify decryption.
void TestDecryptCTR(bool select_key_first = true,
OEMCryptoResult expected_result = OEMCrypto_SUCCESS,
size_t key_index = 0);
// Verify that an attempt to select an expired key either succeeds, or gives
// an actionable error code.
void TestSelectExpired(size_t key_index);
// Calls OEMCrypto_GetOEMPublicCertificate and OEMCrypto_LoadOEMPrivateKey and
// loads the OEM cert's public rsa key into public_rsa_.
void LoadOEMCert(bool verify_cert = false);
// Calls OEMCrypto_RewrapDeviceRSAKey with the given provisioning response
// message. If force is true, we assert that the key loads successfully.
void RewrapRSAKey(const struct RSAPrivateKeyMessage& encrypted,
size_t message_size, const std::vector<uint8_t>& signature,
vector<uint8_t>* wrapped_key, bool force);
// Loads the default test RSA public key into public_rsa_.
void SetTestRsaPublicKey();
// Loads the specified DRM public key into the appropriate key.
// The provided key is serialized as an ASN.1 DER encoded PrivateKeyInfo.
void SetPublicKeyFromPrivateKeyInfo(OEMCrypto_PrivateKeyType key_type,
const uint8_t* buffer, size_t length);
// Loads the specified RSA public key into public_rsa_.
// The provided key is serialized as an ASN.1 DER encoded PrivateKeyInfo.
void SetRsaPublicKeyFromPrivateKeyInfo(const uint8_t* buffer, size_t length);
// Loads the specified EC public key into public_ec_.
// The provided key is serialized as an ASN.1 DER encoded PrivateKeyInfo.
void SetEccPublicKeyFromPrivateKeyInfo(const uint8_t* buffer, size_t length);
// Loads the specified DRM public key into the appropriate key.
// The provided key is serialized as an ASN.1 DER encoded SubjectPublicKey.
void SetPublicKeyFromSubjectPublicKey(OEMCrypto_PrivateKeyType key_type,
const uint8_t* buffer, size_t length);
// Loads the specified RSA public key into public_rsa_.
// The provided key is serialized as an ASN.1 DER encoded SubjectPublicKey.
void SetRsaPublicKeyFromSubjectPublicKey(const uint8_t* buffer,
size_t length);
// Loads the specified EC public key into public_ec_.
// The provided key is serialized as an ASN.1 DER encoded SubjectPublicKey.
void SetEccPublicKeyFromSubjectPublicKey(const uint8_t* buffer,
size_t length);
// Verify that the message was signed by the private key associated with
// |public_rsa_| using the specified padding scheme.
void VerifyRsaSignature(const vector<uint8_t>& message,
const uint8_t* signature, size_t signature_length,
RSA_Padding_Scheme padding_scheme);
// Verify that the message was signed by the private key associated with
// |public_ecc_| using Widevine ECDSA.
void VerifyEccSignature(const vector<uint8_t>& message,
const uint8_t* signature, size_t signature_length);
// Verify RSA or ECC signature based on the key type installed. The
// padding_scheme will be ignored in case of ECC key.
void VerifySignature(const vector<uint8_t>& message, const uint8_t* signature,
size_t signature_length,
RSA_Padding_Scheme padding_scheme);
// Encrypts a known session key with public_rsa_ for use in future calls to
// OEMCrypto_DeriveKeysFromSessionKey or OEMCrypto_RewrapDeviceRSAKey30.
// The unencrypted session key is stored in session_key.
bool GenerateRsaSessionKey(vector<uint8_t>* session_key,
vector<uint8_t>* enc_session_key);
// Derives a session key with public_ec_ and a ephemeral "server" ECC key
// for use in future calls to OEMCrypto_DeriveKeysFromSessionKey.
// The unencrypted session key is stored in session_key.
bool GenerateEccSessionKey(vector<uint8_t>* session_key,
vector<uint8_t>* ecdh_public_key_data);
// Based on the key type installed, call GenerateRsaSessionKey or
// GenerateEccSessionKey.
bool GenerateSessionKey(vector<uint8_t>* session_key,
vector<uint8_t>* key_material);
// Calls OEMCrypto_RewrapDeviceRSAKey30 with the given provisioning response
// message. If force is true, we assert that the key loads successfully.
void RewrapRSAKey30(const struct RSAPrivateKeyMessage& encrypted,
const std::vector<uint8_t>& encrypted_message_key,
vector<uint8_t>* wrapped_key, bool force);
void LoadWrappedDrmKey(OEMCrypto_PrivateKeyType key_type,
const vector<uint8_t>& wrapped_drm_key);
// Loads the specified wrapped_rsa_key into OEMCrypto.
void LoadWrappedRsaDrmKey(const vector<uint8_t>& wrapped_rsa_key);
// Loads the specified wrapped_ecc_key into OEMCrypto.
void LoadWrappedEccDrmKey(const vector<uint8_t>& wrapped_ecc_key);
// Creates a new usage entry, and keeps track of the index.
// If status is null, we expect success, otherwise status is set to the
// return value.
void CreateNewUsageEntry(OEMCryptoResult* status = nullptr);
// Copy encrypted usage entry from other session, and then load it.
// This session must already be open.
void LoadUsageEntry(uint32_t index, const vector<uint8_t>& buffer);
// Copy encrypted usage entry from other session.
// This session must already be open.
void LoadUsageEntry(const Session& other) {
LoadUsageEntry(other.usage_entry_number(), other.encrypted_usage_entry());
}
// Reload previously used usage entry.
void ReloadUsageEntry() { LoadUsageEntry(*this); }
// Update the usage entry and save the header to the specified buffer.
void UpdateUsageEntry(std::vector<uint8_t>* header_buffer);
// The usage entry number for this session's usage entry.
uint32_t usage_entry_number() const { return usage_entry_number_; }
void set_usage_entry_number(uint32_t v) { usage_entry_number_ = v; }
// The encrypted buffer holding the recently updated and saved usage entry.
const vector<uint8_t>& encrypted_usage_entry() const {
return encrypted_usage_entry_;
}
// Generates a usage report for the specified pst. If there is success,
// the report's signature is verified, and several fields are given sanity
// checks. If |other| is not null, then the mac keys are copied from other in
// order to verify signatures.
void GenerateReport(const std::string& pst,
OEMCryptoResult expected_result = OEMCrypto_SUCCESS,
Session* other = nullptr);
// Move this usage entry to a new index.
void MoveUsageEntry(uint32_t new_index, std::vector<uint8_t>* header_buffer,
OEMCryptoResult expect_result = OEMCrypto_SUCCESS);
// PST used in FillSimpleMesage.
string pst() const { return pst_; }
// Returns a pointer-like thing to the usage report generated by the previous
// call to GenerateReport.
wvutil::Unpacked_PST_Report pst_report() {
return wvutil::Unpacked_PST_Report(&pst_report_buffer_[0]);
}
// Verify the values in the PST report. The signature should have been
// verified in GenerateReport, above.
void VerifyPST(const Test_PST_Report& report);
// Verify the Usage Report. If any time is greater than 10 minutes, it is
// assumed to be an absolute time, and time_since will be computed relative to
// now.
void VerifyReport(Test_PST_Report report, int64_t time_license_received = 0,
int64_t time_first_decrypt = 0,
int64_t time_last_decrypt = 0);
// Create an entry in the old usage table based on the given report.
void CreateOldEntry(const Test_PST_Report& report);
// Create a new entry and copy the old entry into it. Then very the report
// is right.
void CopyAndVerifyOldEntry(const Test_PST_Report& report,
std::vector<uint8_t>* header_buffer);
// The unencrypted license response or license renewal response.
MessageData& license() { return license_; }
void set_license(const MessageData& license) { license_ = license; }
const KeyDeriver& key_deriver() const { return key_deriver_; }
void set_mac_keys(const uint8_t* mac_keys) {
key_deriver_.set_mac_keys(mac_keys);
}
private:
// This compares the actual result with the expected result. If OEMCrypto is
// an older version, we allow it to report an equivalent error code.
void TestDecryptResult(OEMCryptoResult expected_result,
OEMCryptoResult actual_select_result,
OEMCryptoResult actual_decryt_result);
bool open_ = false;
bool forced_session_id_ = false;
OEMCrypto_SESSION session_id_ = 0;
KeyDeriver key_deriver_;
uint32_t nonce_ = 0;
// Only one of RSA or EC should be set.
std::unique_ptr<util::RsaPublicKey> public_rsa_;
std::unique_ptr<util::EccPublicKey> public_ec_;
vector<uint8_t> pst_report_buffer_;
MessageData license_ = {};
vector<uint8_t> encrypted_usage_entry_;
uint32_t usage_entry_number_ = 0;
string pst_;
}; // class Session
// Used for OEMCrypto Fuzzing: Convert byte to a valid boolean to avoid errors
// generated by msan.
bool ConvertByteToValidBoolean(const bool* in);
// Used for OEMCrypto Fuzzing: Generates corpus for request APIs.
template <class CoreRequest>
void WriteRequestApiCorpus(size_t signature_length, size_t core_message_length,
vector<uint8_t>& data);
template <PrepAndSignRequest_t PrepAndSignRequest>
void GetDefaultRequestSignatureAndCoreMessageLengths(
uint32_t& session_id, const size_t& small_size,
size_t* gen_signature_length, size_t* core_message_length);
} // namespace wvoec
#endif // CDM_OEC_SESSION_UTIL_H_