(This is a merge from the Widevine Repo of http://go/wvgerrit/134310.) This patch fixes code that would trigger -Wshorten-64-to-32 by implicitly narrowing a variable from 64 to 32 bits. Most of the time, it does this by making the implicit conversion explicit. The cause of most of these is that OpenSSL uses "int" for the length of things rather than size_t. (While BoringSSL sometimes uses int and sometimes uses size_t.) One exception is LogBoringSSLError(). We have a couple copies of this function around, and they varied slightly. This patch brings them all in-line, which conveniently also removes any code in them that would deal with integer variables. GetRandBytes() now takes a size_t and downcasts to BoringSSL's native int internally, so that callers can pass in a size_t value as they would expect. There's also an interesting case in oec_session_util.cpp. Because BoringSSL and OpenSSL disagree about the width of an error code, we have to use the "auto" type for a temporary variable that holds an error, in order to retain compatibility with both. Bug: 194971260 Test: x86-64 Test: x86-64-openssl Change-Id: I88bc62b4cda396f8a1eabd1a3cb7d1b03f47a33f
677 lines
30 KiB
C++
677 lines
30 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 <openssl/rsa.h>
|
|
#include <time.h>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "core_message_deserialize.h"
|
|
#include "core_message_serialize.h"
|
|
#include "odk.h"
|
|
#include "oec_device_features.h"
|
|
#include "oec_key_deriver.h"
|
|
#include "oemcrypto_fuzz_structs.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
|
|
|
|
typedef struct {
|
|
uint8_t verification[4];
|
|
uint32_t duration;
|
|
uint32_t nonce;
|
|
uint32_t control_bits;
|
|
} KeyControlBlock;
|
|
|
|
// 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:
|
|
// ----------------------------------------------------------------------
|
|
// 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:
|
|
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;
|
|
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:
|
|
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:
|
|
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 LoadKeys(OEMCryptoResult expected_sts);
|
|
OEMCryptoResult LoadKeys(const vector<uint8_t>& message);
|
|
OEMCryptoResult LoadKeys();
|
|
void EncryptContentKey();
|
|
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);
|
|
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();
|
|
|
|
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];
|
|
};
|
|
|
|
class Session {
|
|
public:
|
|
Session();
|
|
~Session();
|
|
|
|
// Returns the most recently generated nonce.
|
|
// Valid after call to GenerateNonce.
|
|
uint32_t nonce() const { return 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 specified RSA public key into public_rsa_. If rsa_key is null,
|
|
// the default test key is loaded.
|
|
void PreparePublicKey(const uint8_t* rsa_key = nullptr,
|
|
size_t rsa_key_length = 0);
|
|
// Verifies the given signature is from the given message and RSA key, pkey.
|
|
static bool VerifyPSSSignature(EVP_PKEY* pkey, const uint8_t* message,
|
|
size_t message_length,
|
|
const uint8_t* signature,
|
|
size_t signature_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);
|
|
// 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);
|
|
// 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);
|
|
// Loads the specified wrapped_rsa_key into OEMCrypto, and then runs
|
|
// GenerateDerivedKeysFromSessionKey to install known encryption and mac keys.
|
|
void InstallRSASessionTestKey(const vector<uint8_t>& wrapped_rsa_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 = 0);
|
|
// 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.
|
|
wvcdm::Unpacked_PST_Report pst_report() {
|
|
return wvcdm::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_;
|
|
bool forced_session_id_;
|
|
OEMCrypto_SESSION session_id_;
|
|
KeyDeriver key_deriver_;
|
|
uint32_t nonce_;
|
|
RSA* public_rsa_;
|
|
vector<uint8_t> pst_report_buffer_;
|
|
MessageData license_;
|
|
|
|
vector<uint8_t> encrypted_usage_entry_;
|
|
uint32_t usage_entry_number_;
|
|
string pst_;
|
|
};
|
|
|
|
// 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_
|