Files
android/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp
Fred Gylys-Colwell d7ee89bab0 Filter Cast Reciver tests
Merge from Widevine repo of http://go/wvgerrit/169070

This turns on the cast receiver tests for any device that
claims to support this feature. Previously, we had to
explicitly request these tests on the command line.

But since they do not pass for Prov 4.0, we fitler them out
in this case and reference a bug tracking that work.

We also switch to using GTEST_SKIP to skip the tests instead
of modifying the GTEST_FILTER.

Bug: 251240681
Bug: 269310676
Bug: 259455058
Bug: 259454969
Merged from https://widevine-internal-review.googlesource.com/166497

Change-Id: I1bcd749243a474b3f638547aa43c2805e86731af
2023-03-28 20:30:22 +00:00

3791 lines
154 KiB
C++

// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
/**
* @mainpage OEMCrypto Unit Tests
*
* The OEMCrypto unit tests are designed to verify that an implementation of
* OEMCrypto is correctly supporting the OEMCrypto API.
*
* @defgroup basic Basic Functionality Tests
* Basic functionality tests.
*
* @defgroup provision Provisioning Tests
* Test for provisioning and certificate key processing. These tests cover
* Provsioning 2.0, 3.0 and 4.0. Tests for the wrong provisioning scheme should
* be skipped.
*
* @defgroup license License Request Tests
* Test for requesting and loading licenses.
*
* @defgroup renewal License Renewal Tests
* Tests for renewing licenses.
*
* @defgroup decrypt Decrypt Tests
* Tests for decrypting content.
*
* @defgroup usage_table Usage Table Tests
* Tests that use the usage table.
*
* @defgroup entitle Entitlement License tests
* Tests for entitlement licenses.
*
* @defgroup cas Conditional Access System Tests
* Tests for OEMCrypto implementations that support MediaCAS.
*
* @defgroup cast Cast Test
* Tests for OEMCrypto implementations that support being a Cast receiver.
*
* @defgroup generic Generic Crypto Tests
* Tests for the Generic Crypto functionality.
*
* @defgroup security Security Tests
* Buffer overflow tests, off-by-one tests, and other security tests.
*/
#include <ctype.h>
#include <gtest/gtest.h>
#include <openssl/aes.h>
#include <openssl/err.h>
#include <openssl/hmac.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/sha.h>
#include <openssl/x509.h>
#include <stdint.h>
#include <algorithm>
#include <chrono>
#include <functional>
#include <iostream>
#include <map>
#include <string>
#include <utility>
#include <vector>
#include "OEMCryptoCENC.h"
#include "clock.h"
#include "log.h"
#include "oec_decrypt_fallback_chain.h"
#include "oec_device_features.h"
#include "oec_extra_test_keys.h"
#include "oec_session_util.h"
#include "oec_test_data.h"
#include "oemcrypto_basic_test.h"
#include "oemcrypto_corpus_generator_helper.h"
#include "oemcrypto_fuzz_structs.h"
#include "oemcrypto_license_test.h"
#include "oemcrypto_provisioning_test.h"
#include "oemcrypto_resource_test.h"
#include "oemcrypto_session_tests_helper.h"
#include "oemcrypto_types.h"
#include "oemcrypto_usage_table_test.h"
#include "platform.h"
#include "string_conversions.h"
#include "test_sleep.h"
#include "wvcrc32.h"
using ::testing::Bool;
using ::testing::Combine;
using ::testing::Range;
using ::testing::tuple;
using ::testing::Values;
using ::testing::WithParamInterface;
using namespace std;
namespace std { // GTest wants PrintTo to be in the std namespace.
void PrintTo(const tuple<OEMCrypto_CENCEncryptPatternDesc, OEMCryptoCipherMode,
wvoec::OutputType>& param,
ostream* os) {
OEMCrypto_CENCEncryptPatternDesc pattern = ::testing::get<0>(param);
OEMCryptoCipherMode mode = ::testing::get<1>(param);
wvoec::OutputType output = ::testing::get<2>(param);
bool decrypt_inplace = output.decrypt_inplace;
OEMCryptoBufferType type = output.type;
*os << ((mode == OEMCrypto_CipherMode_CENC) ? "CENC mode" : "CBCS mode")
<< ", pattern=(encrypt:" << pattern.encrypt << ", skip:" << pattern.skip
<< ")";
switch (type) {
case OEMCrypto_BufferType_Clear:
*os << ", BufferType = Clear";
break;
case OEMCrypto_BufferType_Secure:
*os << ", BufferType = Secure";
break;
case OEMCrypto_BufferType_Direct:
*os << ", BufferType = Direct";
break;
default:
*os << ", type = <bad type " << type << ">";
break;
}
if (decrypt_inplace) *os << " (in place)";
}
} // namespace std
namespace wvoec {
/// @addtogroup security
/// @{
class OEMCryptoLicenseOverflowTest : public OEMCryptoSessionTests,
public WithParamInterface<uint32_t> {
public:
OEMCryptoLicenseOverflowTest() : license_api_version_(kCurrentAPI) {}
void SetUp() override {
OEMCryptoSessionTests::SetUp();
license_api_version_ = GetParam();
}
void TearDown() override { OEMCryptoSessionTests::TearDown(); }
void TestLoadLicenseForHugeBufferLengths(
const std::function<void(size_t, LicenseRoundTrip*)> f, bool check_status,
bool update_core_message_substring_values) {
auto oemcrypto_function = [&](size_t message_length) {
Session s;
LicenseRoundTrip license_messages(&s);
license_messages.set_api_version(license_api_version_);
s.open();
InstallTestDrmKey(&s);
bool verify_keys_loaded = true;
license_messages.SignAndVerifyRequest();
license_messages.CreateDefaultResponse();
if (update_core_message_substring_values) {
// Make the license message big enough so that updated core message
// substring offset and length values from tests are still able to read
// data from license_message buffer rather than reading some garbage
// data.
license_messages.set_message_size(
sizeof(license_messages.response_data()) + message_length);
}
f(message_length, &license_messages);
if (update_core_message_substring_values) {
// We will be updating offset for these tests, which will cause verify
// keys to fail with an assertion. Hence skipping verification.
verify_keys_loaded = false;
}
license_messages.EncryptAndSignResponse();
OEMCryptoResult result =
license_messages.LoadResponse(&s, verify_keys_loaded);
s.close();
return result;
};
TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status);
}
void TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths(
const std::function<void(size_t, LicenseRoundTrip*)> f) {
Session s;
LicenseRoundTrip license_messages(&s);
license_messages.set_api_version(license_api_version_);
s.open();
InstallTestDrmKey(&s);
license_messages.SignAndVerifyRequest();
license_messages.CreateDefaultResponse();
size_t message_length = sizeof(license_messages.response_data());
f(message_length, &license_messages);
license_messages.EncryptAndSignResponse();
OEMCryptoResult result = license_messages.LoadResponse();
s.close();
// Verifying error is not due to signature failure which can be caused due
// to test code.
ASSERT_NE(OEMCrypto_ERROR_SIGNATURE_FAILURE, result);
ASSERT_NE(OEMCrypto_SUCCESS, result);
}
protected:
uint32_t license_api_version_;
};
// This class is for testing a single license with the default API version
// of 16. Used for buffer overflow tests.
class OEMCryptoMemoryLicenseTest : public OEMCryptoLicenseTestAPI16 {
public:
OEMCryptoMemoryLicenseTest() : entitled_message_(&license_messages_) {}
void SetUp() override {
OEMCryptoLicenseTestAPI16::SetUp();
SetUpEntitledMessage();
entitlement_response_length_ = entitled_message_.entitled_key_data_size();
}
void LoadLicense() {
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
}
void SetUpEntitledMessage() {
license_messages_.set_license_type(OEMCrypto_EntitlementLicense);
LoadLicense();
entitled_message_.FillKeyArray();
entitled_message_.EncryptContentKey();
uint32_t key_session_id = 0;
OEMCryptoResult sts = OEMCrypto_CreateEntitledKeySession(
session_.session_id(), &key_session_id);
if (sts == OEMCrypto_ERROR_NOT_IMPLEMENTED) {
return;
}
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
entitled_message_.SetEntitledKeySession(key_session_id);
}
void TearDown() override { OEMCryptoLicenseTestAPI16::TearDown(); }
protected:
EntitledMessage entitled_message_;
size_t entitlement_response_length_;
void TestLoadEntitledKeysForHugeBufferLengths(
const std::function<void(size_t, EntitledMessage*)> f,
bool check_status) {
size_t entitled_key_data_size = entitled_message_.entitled_key_data_size();
vector<uint8_t> message(entitled_key_data_size);
memcpy(message.data(), entitled_message_.entitled_key_data(),
entitled_key_data_size);
auto oemcrypto_function = [&](size_t length) {
// Make entitled message big enough so that updated substring offset and
// length fields by core message substring tests can still be able to read
// valid data from entitled message buffer rather than some garbage data.
message.resize(entitled_key_data_size + length);
f(length, &entitled_message_);
return entitled_message_.LoadKeys(message);
};
TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status);
}
};
/// @}
/// @addtogroup entitle
/// @{
class OEMCryptoEntitlementLicenseTest : public OEMCryptoLicenseTest {
protected:
void LoadEntitlementLicense() {
license_messages_.set_license_type(OEMCrypto_EntitlementLicense);
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
}
};
/** This verifies that entitlement keys and entitled content keys can be loaded.
*/
TEST_P(OEMCryptoEntitlementLicenseTest, LoadEntitlementKeysAPI17) {
LoadEntitlementLicense();
uint32_t key_session_id = 0;
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession(
session_.session_id(), &key_session_id));
EntitledMessage entitled_message_1(&license_messages_);
entitled_message_1.FillKeyArray();
entitled_message_1.SetEntitledKeySession(key_session_id);
ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(true));
EntitledMessage entitled_message_2(&license_messages_);
entitled_message_2.FillKeyArray();
entitled_message_2.SetEntitledKeySession(key_session_id);
ASSERT_NO_FATAL_FAILURE(entitled_message_2.LoadKeys(true));
}
TEST_P(OEMCryptoEntitlementLicenseTest, CasOnlyLoadCasKeysAPI17) {
LoadEntitlementLicense();
uint32_t key_session_id = 0;
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession(
session_.session_id(), &key_session_id));
EntitledMessage entitled_message_1(&license_messages_);
entitled_message_1.FillKeyArray();
entitled_message_1.SetEntitledKeySession(key_session_id);
ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadCasKeys(
/*load_even=*/true, /*load_odd=*/true, OEMCrypto_SUCCESS));
EntitledMessage entitled_message_2(&license_messages_);
entitled_message_2.FillKeyArray();
entitled_message_2.SetEntitledKeySession(key_session_id);
ASSERT_NO_FATAL_FAILURE(entitled_message_2.LoadCasKeys(
/*load_even=*/true, /*load_odd=*/false, OEMCrypto_SUCCESS));
EntitledMessage entitled_message_3(&license_messages_);
entitled_message_3.FillKeyArray();
entitled_message_3.SetEntitledKeySession(key_session_id);
ASSERT_NO_FATAL_FAILURE(entitled_message_3.LoadCasKeys(
/*load_even=*/false, /*load_odd=*/true, OEMCrypto_SUCCESS));
ASSERT_NO_FATAL_FAILURE(entitled_message_3.LoadCasKeys(
/*load_even=*/false, /*load_odd=*/false, OEMCrypto_SUCCESS));
}
/**
* This verifies that entitled content keys cannot be loaded if we have not yet
* loaded the entitlement keys.
*/
TEST_P(OEMCryptoEntitlementLicenseTest,
LoadEntitlementKeysNoEntitlementKeysAPI17) {
license_messages_.set_license_type(OEMCrypto_EntitlementLicense);
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
uint32_t key_session_id = 0;
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession(
session_.session_id(), &key_session_id));
EntitledMessage entitled_message_1(&license_messages_);
entitled_message_1.FillKeyArray();
entitled_message_1.SetEntitledKeySession(key_session_id);
ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(false));
}
/**
* This verifies that entitled content keys cannot be loaded if we have loaded
* the wrong entitlement keys.
*/
TEST_P(OEMCryptoEntitlementLicenseTest,
CasOnlyLoadCasKeysNoEntitlementKeysAPI17) {
license_messages_.set_license_type(OEMCrypto_EntitlementLicense);
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
uint32_t key_session_id = 0;
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession(
session_.session_id(), &key_session_id));
EntitledMessage entitled_message_1(&license_messages_);
entitled_message_1.FillKeyArray();
entitled_message_1.SetEntitledKeySession(key_session_id);
ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadCasKeys(
/*load_even=*/true, /*load_odd=*/true, OEMCrypto_ERROR_INVALID_CONTEXT));
}
/**
* This verifies that entitled content keys cannot be loaded if we have loaded
* the wrong entitlement keys.
*/
TEST_P(OEMCryptoEntitlementLicenseTest,
LoadEntitlementKeysWrongEntitlementKeysAPI17) {
LoadEntitlementLicense();
uint32_t key_session_id = 0;
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession(
session_.session_id(), &key_session_id));
EntitledMessage entitled_message_1(&license_messages_);
entitled_message_1.FillKeyArray();
const std::string key_id = "no_key";
entitled_message_1.SetEntitlementKeyId(0, key_id);
entitled_message_1.SetEntitledKeySession(key_session_id);
ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(false));
}
TEST_P(OEMCryptoEntitlementLicenseTest,
CasOnlyLoadCasKeysWrongEntitlementKeysAPI17) {
LoadEntitlementLicense();
uint32_t key_session_id = 0;
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession(
session_.session_id(), &key_session_id));
EntitledMessage entitled_message_1(&license_messages_);
entitled_message_1.FillKeyArray();
const std::string key_id = "no_key";
entitled_message_1.SetEntitlementKeyId(0, key_id);
entitled_message_1.SetEntitledKeySession(key_session_id);
ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadCasKeys(
/*load_even=*/true, /*load_odd=*/true, OEMCrypto_KEY_NOT_ENTITLED));
}
/**
* This verifies that entitled content keys cannot be loaded if we specify an
* entitled key session that has not been created.
*/
TEST_P(OEMCryptoEntitlementLicenseTest,
LoadEntitlementKeysWrongEntitledKeySessionAPI17) {
LoadEntitlementLicense();
uint32_t key_session_id = 0;
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession(
session_.session_id(), &key_session_id));
EntitledMessage entitled_message_1(&license_messages_);
entitled_message_1.FillKeyArray();
const uint32_t wrong_key_session_id = key_session_id == 0 ? 1 : 0;
entitled_message_1.SetEntitledKeySession(wrong_key_session_id);
ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(false));
}
TEST_P(OEMCryptoEntitlementLicenseTest,
CasOnlyLoadCasKeysWrongEntitledKeySessionAPI17) {
LoadEntitlementLicense();
uint32_t key_session_id = 0;
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession(
session_.session_id(), &key_session_id));
EntitledMessage entitled_message_1(&license_messages_);
entitled_message_1.FillKeyArray();
const uint32_t wrong_key_session_id = key_session_id == 0 ? 1 : 0;
entitled_message_1.SetEntitledKeySession(wrong_key_session_id);
ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadCasKeys(
/*load_even=*/true, /*load_odd=*/true,
OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION));
}
/**
* This verifies that entitled content keys cannot be loaded if we specify an
* entitled key session that is actually an oemcrypto session.
*/
TEST_P(OEMCryptoEntitlementLicenseTest,
LoadEntitlementKeysOemcryptoSessionAPI17) {
LoadEntitlementLicense();
uint32_t key_session_id = 0;
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession(
session_.session_id(), &key_session_id));
EntitledMessage entitled_message_1(&license_messages_);
entitled_message_1.FillKeyArray();
if (session_.session_id() == key_session_id) {
GTEST_SKIP()
<< "Skipping test because entitled and entitlement sessions are both "
<< key_session_id << ".";
}
entitled_message_1.SetEntitledKeySession(session_.session_id());
ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(false));
}
TEST_P(OEMCryptoEntitlementLicenseTest,
CasOnlyLoadCasKeysOemcryptoSessionAPI17) {
LoadEntitlementLicense();
uint32_t key_session_id = 0;
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession(
session_.session_id(), &key_session_id));
EntitledMessage entitled_message_1(&license_messages_);
entitled_message_1.FillKeyArray();
entitled_message_1.SetEntitledKeySession(session_.session_id());
ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadCasKeys(
/*load_even=*/true, /*load_odd=*/true,
OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION));
}
INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoEntitlementLicenseTest,
Range<uint32_t>(kCoreMessagesAPI, kCurrentAPI + 1));
/// @}
/// @addtogroup security
/// @{
TEST_F(OEMCryptoMemoryLicenseTest,
OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyIdLength) {
TestLoadEntitledKeysForHugeBufferLengths(
[](size_t key_id_length, EntitledMessage* entitled_message) {
entitled_message->entitled_key_array()[0].content_key_id.length =
key_id_length;
},
!kCheckStatus);
}
TEST_F(OEMCryptoMemoryLicenseTest,
OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyIdOffset) {
TestLoadEntitledKeysForHugeBufferLengths(
[](size_t key_id_offset, EntitledMessage* entitled_message) {
entitled_message->entitled_key_array()[0].content_key_id.offset =
key_id_offset;
},
!kCheckStatus);
}
TEST_F(
OEMCryptoMemoryLicenseTest,
OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyIdLength) {
auto& content_key_id =
entitled_message_.entitled_key_array()[0].content_key_id;
content_key_id.length =
entitlement_response_length_ - content_key_id.offset + 1;
ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys());
}
TEST_F(
OEMCryptoMemoryLicenseTest,
OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyIdOffset) {
auto& content_key_id =
entitled_message_.entitled_key_array()[0].content_key_id;
content_key_id.offset =
entitlement_response_length_ - content_key_id.length + 1;
ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys());
}
TEST_F(OEMCryptoMemoryLicenseTest,
OEMCryptoMemoryLoadEntitledKeysForHugeSubstringEntitlementKeyIdLength) {
TestLoadEntitledKeysForHugeBufferLengths(
[](size_t key_id_length, EntitledMessage* entitled_message) {
entitled_message->entitled_key_array()[0].entitlement_key_id.length =
key_id_length;
},
!kCheckStatus);
}
TEST_F(OEMCryptoMemoryLicenseTest,
OEMCryptoMemoryLoadEntitledKeysForHugeSubstringEntitlementKeyIdOffset) {
TestLoadEntitledKeysForHugeBufferLengths(
[](size_t key_id_offset, EntitledMessage* entitled_message) {
entitled_message->entitled_key_array()[0].entitlement_key_id.offset =
key_id_offset;
},
!kCheckStatus);
}
TEST_F(
OEMCryptoMemoryLicenseTest,
OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringEntitlementKeyIdLength) {
auto& entitlement_key_id =
entitled_message_.entitled_key_array()[0].entitlement_key_id;
entitlement_key_id.length =
entitlement_response_length_ - entitlement_key_id.offset + 1;
ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys());
}
TEST_F(
OEMCryptoMemoryLicenseTest,
OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringEntitlementKeyIdOffset) {
auto& entitlement_key_id =
entitled_message_.entitled_key_array()[0].entitlement_key_id;
entitlement_key_id.offset =
entitlement_response_length_ - entitlement_key_id.length + 1;
ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys());
}
TEST_F(OEMCryptoMemoryLicenseTest,
OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataIvLength) {
TestLoadEntitledKeysForHugeBufferLengths(
[](size_t content_key_data_iv_length, EntitledMessage* entitled_message) {
entitled_message->entitled_key_array()[0].content_key_data_iv.length =
content_key_data_iv_length;
},
!kCheckStatus);
}
TEST_F(OEMCryptoMemoryLicenseTest,
OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataIvOffset) {
TestLoadEntitledKeysForHugeBufferLengths(
[](size_t content_key_data_iv_offset, EntitledMessage* entitled_message) {
entitled_message->entitled_key_array()[0].content_key_data_iv.offset =
content_key_data_iv_offset;
},
!kCheckStatus);
}
TEST_F(
OEMCryptoMemoryLicenseTest,
OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataIvLength) {
auto& content_key_data_iv =
entitled_message_.entitled_key_array()[0].content_key_data_iv;
content_key_data_iv.length =
entitlement_response_length_ - content_key_data_iv.offset + 1;
ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys());
}
TEST_F(
OEMCryptoMemoryLicenseTest,
OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataIvOffset) {
auto& content_key_data_iv =
entitled_message_.entitled_key_array()[0].content_key_data_iv;
content_key_data_iv.offset =
entitlement_response_length_ - content_key_data_iv.length + 1;
ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys());
}
TEST_F(OEMCryptoMemoryLicenseTest,
OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataLength) {
TestLoadEntitledKeysForHugeBufferLengths(
[](size_t content_key_data_length, EntitledMessage* entitled_message) {
entitled_message->entitled_key_array()[0].content_key_data.length =
content_key_data_length;
},
!kCheckStatus);
}
TEST_F(OEMCryptoMemoryLicenseTest,
OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataOffset) {
TestLoadEntitledKeysForHugeBufferLengths(
[](size_t content_key_data_offset, EntitledMessage* entitled_message) {
entitled_message->entitled_key_array()[0].content_key_data.offset =
content_key_data_offset;
},
!kCheckStatus);
}
TEST_F(
OEMCryptoMemoryLicenseTest,
OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataLength) {
auto& content_key_data =
entitled_message_.entitled_key_array()[0].content_key_data;
content_key_data.length =
entitlement_response_length_ - content_key_data.offset + 1;
ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys());
}
TEST_F(
OEMCryptoMemoryLicenseTest,
OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataOffset) {
auto& content_key_data =
entitled_message_.entitled_key_array()[0].content_key_data;
content_key_data.offset =
entitlement_response_length_ - content_key_data.length + 1;
ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys());
}
TEST_F(OEMCryptoMemoryLicenseTest,
OEMCryptoMemoryLoadEntitledKeysForHugeEntitlementKeyIdLength) {
TestLoadEntitledKeysForHugeBufferLengths(
[](size_t key_id_length, EntitledMessage* entitled_message) {
entitled_message->entitled_key_data()->entitlement_key_id_length =
key_id_length;
},
!kCheckStatus);
}
TEST_F(OEMCryptoMemoryLicenseTest,
OEMCryptoMemoryLoadEntitledKeysForHugeContentKeyIdLength) {
TestLoadEntitledKeysForHugeBufferLengths(
[](size_t key_id_length, EntitledMessage* entitled_message) {
entitled_message->entitled_key_data()->content_key_id_length =
key_id_length;
},
!kCheckStatus);
}
/// @}
/// @addtogroup entitle
/// @{
TEST_P(OEMCryptoLicenseTest, GetKeyHandleEntitledKeyAPI17) {
license_messages_.set_license_type(OEMCrypto_EntitlementLicense);
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
uint32_t key_session_id;
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession(
session_.session_id(), &key_session_id));
EntitledMessage entitled_message_1(&license_messages_);
entitled_message_1.FillKeyArray();
entitled_message_1.SetEntitledKeySession(key_session_id);
const char* content_key_id = "content_key_id";
entitled_message_1.SetContentKeyId(0, content_key_id);
ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(true));
vector<uint8_t> key_handle;
ASSERT_EQ(
OEMCrypto_SUCCESS,
GetKeyHandleIntoVector(
key_session_id, reinterpret_cast<const uint8_t*>(content_key_id),
strlen(content_key_id), OEMCrypto_CipherMode_CENC, key_handle));
}
// SelectEntitledKey should fail if we attempt to select a key that has not been
// loaded. Also, the error should be NO_CONTENT_KEY.
TEST_P(OEMCryptoLicenseTest, SelectKeyEntitledKeyNotThereAPI17) {
license_messages_.set_license_type(OEMCrypto_EntitlementLicense);
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
uint32_t key_session_id;
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession(
session_.session_id(), &key_session_id));
EntitledMessage entitled_message_1(&license_messages_);
entitled_message_1.FillKeyArray();
entitled_message_1.SetEntitledKeySession(key_session_id);
ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(true));
const char* content_key_id = "no_key";
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled(
OEMCrypto_ERROR_INVALID_CONTEXT, key_session_id,
reinterpret_cast<const uint8_t*>(content_key_id),
strlen(content_key_id)));
}
/**
* Select key with entitlement license fails if the key id is entitlement key
* id.
*/
TEST_P(OEMCryptoLicenseTest, SelectKeyEntitlementKeyAPI17) {
license_messages_.set_license_type(OEMCrypto_EntitlementLicense);
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
uint32_t key_session_id;
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession(
session_.session_id(), &key_session_id));
EntitledMessage entitled_message_1(&license_messages_);
entitled_message_1.FillKeyArray();
entitled_message_1.SetEntitledKeySession(key_session_id);
ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(true));
if (session_.session_id() == key_session_id) {
GTEST_SKIP()
<< "Skipping test because entitled and entitlement sessions are both "
<< key_session_id << ".";
}
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled(
OEMCrypto_ERROR_INVALID_CONTEXT, session_.session_id(),
session_.license().keys[0].key_id,
session_.license().keys[0].key_id_length));
}
// This verifies that entitled key sessions can be created and removed.
TEST_P(OEMCryptoLicenseTest, EntitledKeySessionsAPI17) {
license_messages_.set_license_type(OEMCrypto_EntitlementLicense);
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
uint32_t key_session_id_1;
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession(
session_.session_id(), &key_session_id_1));
ASSERT_NE(key_session_id_1, 0u); // 0 is a reserved id number.
uint32_t key_session_id_2;
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession(
session_.session_id(), &key_session_id_2));
ASSERT_NE(key_session_id_2, 0u); // 0 is a reserved id number.
// Entitled key sessions should have unique ids.
ASSERT_NE(key_session_id_1, key_session_id_2);
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_RemoveEntitledKeySession(key_session_id_1));
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_RemoveEntitledKeySession(key_session_id_2));
}
TEST_P(OEMCryptoLicenseTest,
EntitledKeySessionsCloseWithOEMCryptoSessionAPI17) {
license_messages_.set_license_type(OEMCrypto_EntitlementLicense);
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
uint32_t key_session_id_1;
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession(
session_.session_id(), &key_session_id_1));
// Close the OEMCrypto session.
session_.close();
// All entitled key sessions associated with the OEMCrypto session should
// already be destroyed.
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_RemoveEntitledKeySession(key_session_id_1));
// Open a new session just for OEMCryptoLicenseTest TearDown.
session_.open();
}
// This verifies that multiple entitled key sessions can be created. They can
// load and select keys independently.
TEST_P(OEMCryptoLicenseTest, EntitledKeySessionMultipleKeySessionsAPI17) {
license_messages_.set_license_type(OEMCrypto_EntitlementLicense);
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
uint32_t key_session_id_1;
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession(
session_.session_id(), &key_session_id_1));
EntitledMessage entitled_message_1(&license_messages_);
entitled_message_1.FillKeyArray();
entitled_message_1.SetEntitledKeySession(key_session_id_1);
const char* content_key_id_1 = "content_key_id_1";
entitled_message_1.SetContentKeyId(0, content_key_id_1);
ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(true));
// We can select content key 1 in entitled key session 1.
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled(
OEMCrypto_SUCCESS, key_session_id_1,
reinterpret_cast<const uint8_t*>(content_key_id_1),
strlen(content_key_id_1)));
// Create another entitled key session.
uint32_t key_session_id_2;
OEMCryptoResult status = OEMCrypto_CreateEntitledKeySession(
session_.session_id(), &key_session_id_2);
// For DRM, but not for CAS, we allow there to be only a single entitled
// session.
if (!global_features.supports_cas &&
(key_session_id_2 == key_session_id_1 ||
status == OEMCrypto_ERROR_TOO_MANY_SESSIONS)) {
GTEST_SKIP()
<< "Skipping test because multiple entitled sessions not supported.";
}
ASSERT_EQ(OEMCrypto_SUCCESS, status);
// Entitled key sessions should have unique ids.
ASSERT_NE(key_session_id_1, key_session_id_2);
EntitledMessage entitled_message_2(&license_messages_);
entitled_message_2.FillKeyArray();
entitled_message_2.SetEntitledKeySession(key_session_id_2);
const char* content_key_id_2 = "content_key_id_2";
entitled_message_2.SetContentKeyId(0, content_key_id_2);
ASSERT_NO_FATAL_FAILURE(entitled_message_2.LoadKeys(true));
// We can select content key 2 in entitled key session 2.
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled(
OEMCrypto_SUCCESS, key_session_id_2,
reinterpret_cast<const uint8_t*>(content_key_id_2),
strlen(content_key_id_2)));
// Content key id 1 is not in entitled key session 2.
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled(
OEMCrypto_ERROR_NO_CONTENT_KEY, key_session_id_2,
reinterpret_cast<const uint8_t*>(content_key_id_1),
strlen(content_key_id_1)));
// Content key id 2 is not in entitled key session 1.
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled(
OEMCrypto_ERROR_NO_CONTENT_KEY, key_session_id_1,
reinterpret_cast<const uint8_t*>(content_key_id_2),
strlen(content_key_id_2)));
}
// This verifies that within an entitled key session, each entitlement key can
// corresponds to only one content key at most.
TEST_P(OEMCryptoLicenseTest,
EntitledKeySessionOneContentKeyPerEntitlementAPI17) {
license_messages_.set_license_type(OEMCrypto_EntitlementLicense);
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
uint32_t key_session_id;
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession(
session_.session_id(), &key_session_id));
// Construct and load content keys to entitled key session.
EntitledMessage entitled_message_1(&license_messages_);
entitled_message_1.FillKeyArray();
entitled_message_1.SetEntitledKeySession(key_session_id);
const char* content_key_id_1 = "content_key_id_1";
entitled_message_1.SetContentKeyId(0, content_key_id_1);
ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(true));
// We can select content key 1 in entitled key session.
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled(
OEMCrypto_SUCCESS, key_session_id,
reinterpret_cast<const uint8_t*>(content_key_id_1),
strlen(content_key_id_1)));
// Load content key with new content id.
const char* content_key_id_2 = "content_key_id_2";
entitled_message_1.SetContentKeyId(0, content_key_id_2);
ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(true));
// We can select content key 2 in entitled key session.
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled(
OEMCrypto_SUCCESS, key_session_id,
reinterpret_cast<const uint8_t*>(content_key_id_2),
strlen(content_key_id_2)));
// Content key one is no longer in the entitled key session as they use the
// same entitlement key.
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled(
OEMCrypto_ERROR_NO_CONTENT_KEY, key_session_id,
reinterpret_cast<const uint8_t*>(content_key_id_1),
strlen(content_key_id_1)));
}
// Decrypt should fail if the license is entitlement license, and the key handle
// is requested from the oemcrypto session (should use entitled key session id
// instead).
TEST_P(OEMCryptoLicenseTest,
RejectOecSessionDecryptWithEntitlementLicenseAPI17) {
license_messages_.set_license_type(OEMCrypto_EntitlementLicense);
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
uint32_t key_session_id;
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession(
session_.session_id(), &key_session_id));
// Skip the rest of this test on platforms that do not support separate
// entitlement and entitled sessions.
if (global_features.supports_cas || session_.session_id() != key_session_id) {
// Construct and load content keys to entitled key session.
EntitledMessage entitled_message(&license_messages_);
entitled_message.FillKeyArray();
entitled_message.SetEntitledKeySession(key_session_id);
constexpr char kContentKeyId[] = "content_key_id";
const size_t content_key_id_length = strlen(kContentKeyId);
entitled_message.SetContentKeyId(0, kContentKeyId);
ASSERT_NO_FATAL_FAILURE(entitled_message.LoadKeys(true));
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptEntitled(
OEMCrypto_SUCCESS, key_session_id,
reinterpret_cast<const uint8_t*>(kContentKeyId),
content_key_id_length));
// Try to get a key handle with the oemcrypto session id.
vector<uint8_t> key_handle;
EXPECT_NE(GetKeyHandleIntoVector(
session_.session_id(),
reinterpret_cast<const uint8_t*>(kContentKeyId),
content_key_id_length, OEMCrypto_CipherMode_CENC, key_handle),
OEMCrypto_SUCCESS);
}
}
// This verifies that an entitled key session can be reassociated to an
// OEMCrypto session.
TEST_P(OEMCryptoEntitlementLicenseTest, ReassociateEntitledKeySessionAPI17) {
license_messages_.set_license_type(OEMCrypto_EntitlementLicense);
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
// Setup another session.
Session session2;
ASSERT_NO_FATAL_FAILURE(session2.open());
ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&session2));
ASSERT_NO_FATAL_FAILURE(session2.GenerateDerivedKeysFromSessionKey());
// Setup an entitled key session in the first OEMCrypto session.
uint32_t key_session_id;
OEMCryptoResult sts = OEMCrypto_CreateEntitledKeySession(
session_.session_id(), &key_session_id);
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
EntitledMessage entitled_message(&license_messages_);
entitled_message.FillKeyArray();
entitled_message.SetEntitledKeySession(key_session_id);
ASSERT_NO_FATAL_FAILURE(entitled_message.LoadKeys(true));
// Now reassociate the entitled key session to the second OEMCrypto session.
OEMCryptoResult status = OEMCrypto_ReassociateEntitledKeySession(
key_session_id, session2.session_id());
if (status == OEMCrypto_ERROR_NOT_IMPLEMENTED &&
!global_features.supports_cas) {
GTEST_SKIP() << "Skipping test because "
"OEMCrypto_ReassociateEntitledKeySession not implemented.";
}
ASSERT_EQ(OEMCrypto_SUCCESS, status);
// session2 does not have entitlement keys.
ASSERT_NO_FATAL_FAILURE(entitled_message.LoadKeys(false));
// Now reassociate the entitled key session back to the first OEMCrypto
// session.
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_ReassociateEntitledKeySession(
key_session_id, session_.session_id()));
ASSERT_NO_FATAL_FAILURE(entitled_message.LoadKeys(true));
}
/// @}
/// @addtogroup security
/// @{
TEST_P(OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyIdLength) {
TestLoadLicenseForHugeBufferLengths(
[](size_t length, LicenseRoundTrip* license_messages) {
license_messages->core_response().key_array[0].key_id.length = length;
license_messages->response_data().keys[0].key_id_length = length;
},
!kCheckStatus, kUpdateCoreMessageSubstringValues);
}
TEST_P(OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyIdOffset) {
TestLoadLicenseForHugeBufferLengths(
[](size_t offset, LicenseRoundTrip* license_messages) {
license_messages->core_response().key_array[0].key_id.offset = offset;
},
!kCheckStatus, kUpdateCoreMessageSubstringValues);
}
TEST_P(OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyIdLength) {
TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths(
[](size_t response_message_length, LicenseRoundTrip* license_messages) {
auto& key_id = license_messages->core_response().key_array[0].key_id;
key_id.length = response_message_length - key_id.offset + 1;
});
}
TEST_P(OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyIdOffset) {
TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths(
[](size_t response_message_length, LicenseRoundTrip* license_messages) {
auto& key_id = license_messages->core_response().key_array[0].key_id;
key_id.offset = response_message_length - key_id.length + 1;
});
}
TEST_P(OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataIvLength) {
TestLoadLicenseForHugeBufferLengths(
[](size_t length, LicenseRoundTrip* license_messages) {
license_messages->core_response().key_array[0].key_data_iv.length =
length;
},
!kCheckStatus, kUpdateCoreMessageSubstringValues);
}
TEST_P(OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataIvOffset) {
TestLoadLicenseForHugeBufferLengths(
[](size_t offset, LicenseRoundTrip* license_messages) {
license_messages->core_response().key_array[0].key_data_iv.offset =
offset;
},
!kCheckStatus, kUpdateCoreMessageSubstringValues);
}
TEST_P(
OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyDataIvLength) {
TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths(
[](size_t response_message_length, LicenseRoundTrip* license_messages) {
auto& key_data_iv =
license_messages->core_response().key_array[0].key_data_iv;
key_data_iv.length = response_message_length - key_data_iv.offset + 1;
});
}
TEST_P(
OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyDataIvOffset) {
TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths(
[](size_t response_message_length, LicenseRoundTrip* license_messages) {
auto& key_data_iv =
license_messages->core_response().key_array[0].key_data_iv;
key_data_iv.offset = response_message_length - key_data_iv.length + 1;
});
}
TEST_P(OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataLength) {
TestLoadLicenseForHugeBufferLengths(
[](size_t length, LicenseRoundTrip* license_messages) {
license_messages->core_response().key_array[0].key_data.length = length;
license_messages->response_data().keys[0].key_data_length = length;
},
!kCheckStatus, kUpdateCoreMessageSubstringValues);
}
TEST_P(OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataOffset) {
TestLoadLicenseForHugeBufferLengths(
[](size_t offset, LicenseRoundTrip* license_messages) {
license_messages->core_response().key_array[0].key_data.offset = offset;
},
!kCheckStatus, kUpdateCoreMessageSubstringValues);
}
TEST_P(
OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyDataLength) {
TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths(
[](size_t response_message_length, LicenseRoundTrip* license_messages) {
auto& key_data =
license_messages->core_response().key_array[0].key_data;
key_data.length = response_message_length - key_data.offset + 1;
});
}
TEST_P(
OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyDataOffset) {
TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths(
[](size_t response_message_length, LicenseRoundTrip* license_messages) {
auto& key_data =
license_messages->core_response().key_array[0].key_data;
key_data.offset = response_message_length - key_data.length + 1;
});
}
TEST_P(
OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlIvLength) {
TestLoadLicenseForHugeBufferLengths(
[](size_t length, LicenseRoundTrip* license_messages) {
license_messages->core_response().key_array[0].key_control_iv.length =
length;
},
!kCheckStatus, kUpdateCoreMessageSubstringValues);
}
TEST_P(
OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlIvOffset) {
TestLoadLicenseForHugeBufferLengths(
[](size_t offset, LicenseRoundTrip* license_messages) {
license_messages->core_response().key_array[0].key_control_iv.offset =
offset;
},
!kCheckStatus, kUpdateCoreMessageSubstringValues);
}
TEST_P(
OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlIvLengthAPI16) {
TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths(
[](size_t response_message_length, LicenseRoundTrip* license_messages) {
auto& key_control_iv =
license_messages->core_response().key_array[0].key_control_iv;
key_control_iv.length =
response_message_length - key_control_iv.offset + 1;
});
}
TEST_P(
OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlIvOffset) {
TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths(
[](size_t response_message_length, LicenseRoundTrip* license_messages) {
auto& key_control_iv =
license_messages->core_response().key_array[0].key_control_iv;
key_control_iv.offset =
response_message_length - key_control_iv.length + 1;
});
}
TEST_P(OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlLength) {
TestLoadLicenseForHugeBufferLengths(
[](size_t length, LicenseRoundTrip* license_messages) {
license_messages->core_response().key_array[0].key_control.length =
length;
},
!kCheckStatus, kUpdateCoreMessageSubstringValues);
}
TEST_P(OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlOffset) {
TestLoadLicenseForHugeBufferLengths(
[](size_t offset, LicenseRoundTrip* license_messages) {
license_messages->core_response().key_array[0].key_control.offset =
offset;
},
!kCheckStatus, kUpdateCoreMessageSubstringValues);
}
TEST_P(
OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlLengthAPI16) {
TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths(
[](size_t response_message_length, LicenseRoundTrip* license_messages) {
auto& key_control =
license_messages->core_response().key_array[0].key_control;
key_control.length = response_message_length - key_control.offset + 1;
});
}
TEST_P(
OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlOffset) {
TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths(
[](size_t response_message_length, LicenseRoundTrip* license_messages) {
auto& key_control =
license_messages->core_response().key_array[0].key_control;
key_control.offset = response_message_length - key_control.length + 1;
});
}
TEST_P(OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyIvLength) {
TestLoadLicenseForHugeBufferLengths(
[](size_t length, LicenseRoundTrip* license_messages) {
license_messages->core_response().enc_mac_keys_iv.length = length;
},
!kCheckStatus, kUpdateCoreMessageSubstringValues);
}
TEST_P(OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyIvOffset) {
TestLoadLicenseForHugeBufferLengths(
[](size_t offset, LicenseRoundTrip* license_messages) {
license_messages->core_response().enc_mac_keys_iv.offset = offset;
},
!kCheckStatus, kUpdateCoreMessageSubstringValues);
}
TEST_P(
OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringEncMacKeyIvLength) {
TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths(
[](size_t response_message_length, LicenseRoundTrip* license_messages) {
auto& enc_mac_keys_iv =
license_messages->core_response().enc_mac_keys_iv;
enc_mac_keys_iv.length =
response_message_length - enc_mac_keys_iv.offset + 1;
});
}
TEST_P(
OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringEncMacKeyIvOffset) {
TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths(
[](size_t response_message_length, LicenseRoundTrip* license_messages) {
auto& enc_mac_keys_iv =
license_messages->core_response().enc_mac_keys_iv;
enc_mac_keys_iv.offset =
response_message_length - enc_mac_keys_iv.length + 1;
});
}
TEST_P(OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyLength) {
TestLoadLicenseForHugeBufferLengths(
[](size_t length, LicenseRoundTrip* license_messages) {
license_messages->core_response().enc_mac_keys.length = length;
},
!kCheckStatus, kUpdateCoreMessageSubstringValues);
}
TEST_P(OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyOffset) {
TestLoadLicenseForHugeBufferLengths(
[](size_t offset, LicenseRoundTrip* license_messages) {
license_messages->core_response().enc_mac_keys.offset = offset;
},
!kCheckStatus, kUpdateCoreMessageSubstringValues);
}
TEST_P(
OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringEncMacKeyLength) {
TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths(
[](size_t response_message_length, LicenseRoundTrip* license_messages) {
auto& enc_mac_keys = license_messages->core_response().enc_mac_keys;
enc_mac_keys.length = response_message_length - enc_mac_keys.offset + 1;
});
}
TEST_P(
OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringEncMacKeyOffset) {
TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths(
[](size_t response_message_length, LicenseRoundTrip* license_messages) {
auto& enc_mac_keys = license_messages->core_response().enc_mac_keys;
enc_mac_keys.offset = response_message_length - enc_mac_keys.length + 1;
});
}
TEST_P(OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringPstLength) {
TestLoadLicenseForHugeBufferLengths(
[](size_t length, LicenseRoundTrip* license_messages) {
license_messages->core_response().pst.length = length;
},
!kCheckStatus, kUpdateCoreMessageSubstringValues);
}
TEST_P(OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringPstOffset) {
TestLoadLicenseForHugeBufferLengths(
[](size_t offset, LicenseRoundTrip* license_messages) {
license_messages->core_response().pst.offset = offset;
},
!kCheckStatus, kUpdateCoreMessageSubstringValues);
}
TEST_P(OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringPstLength) {
TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths(
[](size_t response_message_length, LicenseRoundTrip* license_messages) {
auto& pst = license_messages->core_response().pst;
pst.length = response_message_length - pst.offset + 1;
});
}
TEST_P(OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringPstOffset) {
TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths(
[](size_t response_message_length, LicenseRoundTrip* license_messages) {
auto& pst = license_messages->core_response().pst;
pst.offset = response_message_length;
if (pst.length == 0) pst.length = 1;
});
}
TEST_P(
OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringSrmRestrictionDataLength) {
TestLoadLicenseForHugeBufferLengths(
[](size_t length, LicenseRoundTrip* license_messages) {
license_messages->core_response().srm_restriction_data.length = length;
},
!kCheckStatus, kUpdateCoreMessageSubstringValues);
}
TEST_P(
OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringSrmRestrictionDataOffset) {
TestLoadLicenseForHugeBufferLengths(
[](size_t offset, LicenseRoundTrip* license_messages) {
license_messages->core_response().srm_restriction_data.offset = offset;
},
!kCheckStatus, kUpdateCoreMessageSubstringValues);
}
TEST_P(
OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringSrmRestrictionDataLength) {
TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths(
[](size_t response_message_length, LicenseRoundTrip* license_messages) {
auto& srm_restriction_data =
license_messages->core_response().srm_restriction_data;
srm_restriction_data.length =
response_message_length - srm_restriction_data.offset + 1;
});
}
TEST_P(
OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringSrmRestrictionDataOffset) {
TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths(
[](size_t response_message_length, LicenseRoundTrip* license_messages) {
auto& srm_restriction_data =
license_messages->core_response().srm_restriction_data;
srm_restriction_data.offset = response_message_length;
if (srm_restriction_data.length == 0) srm_restriction_data.length = 1;
});
}
TEST_P(OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForHugeResponseLength) {
TestLoadLicenseForHugeBufferLengths(
[](size_t message_size, LicenseRoundTrip* license_messages) {
license_messages->set_message_size(message_size);
},
!kCheckStatus, !kUpdateCoreMessageSubstringValues);
}
TEST_P(OEMCryptoLicenseOverflowTest,
OEMCryptoMemoryLoadLicenseForHugeCoreMessageLength) {
TestLoadLicenseForHugeBufferLengths(
[](size_t message_size, LicenseRoundTrip* license_messages) {
license_messages->set_core_message_size(message_size);
},
!kCheckStatus, !kUpdateCoreMessageSubstringValues);
}
INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoLicenseOverflowTest,
Range<uint32_t>(kCurrentAPI - 1, kCurrentAPI + 1));
/// @}
/// @addtogroup cas
/// @{
// Used to test the different HDCP versions. This test is parameterized by the
// required HDCP version in the key control block.
class OEMCryptoSessionTestLoadCasKeysWithHDCP : public OEMCryptoSessionTests,
public WithParamInterface<int> {
protected:
void LoadCasKeysWithHDCP(OEMCrypto_HDCP_Capability version) {
OEMCryptoResult sts;
OEMCrypto_HDCP_Capability current, maximum;
sts = OEMCrypto_GetHDCPCapability(&current, &maximum);
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s));
LicenseRoundTrip license_messages(&s);
license_messages.set_control((version << wvoec::kControlHDCPVersionShift) |
wvoec::kControlObserveHDCP |
wvoec::kControlHDCPRequired);
license_messages.set_license_type(OEMCrypto_EntitlementLicense);
ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest());
ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(license_messages.EncryptAndSignResponse());
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages.LoadResponse());
uint32_t key_session_id;
sts = OEMCrypto_CreateEntitledKeySession(s.session_id(), &key_session_id);
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
EntitledMessage entitled_message_1(&license_messages);
entitled_message_1.FillKeyArray();
entitled_message_1.SetEntitledKeySession(key_session_id);
if (((version <= HDCP_V2_3 || current >= HDCP_V1_0) && version > current) ||
(current == HDCP_V1 && version >= HDCP_V1_0)) {
ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadCasKeys(
/*load_even=*/true, /*load_odd=*/true,
OEMCrypto_ERROR_INSUFFICIENT_HDCP))
<< "Failed when current HDCP = " << HDCPCapabilityAsString(current)
<< ", maximum HDCP = " << HDCPCapabilityAsString(maximum)
<< ", license HDCP = " << HDCPCapabilityAsString(version);
} else {
ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadCasKeys(
/*load_even=*/true, /*load_odd=*/true, OEMCrypto_SUCCESS))
<< "Failed when current HDCP = " << HDCPCapabilityAsString(current)
<< ", maximum HDCP = " << HDCPCapabilityAsString(maximum)
<< ", license HDCP = " << HDCPCapabilityAsString(version);
}
}
};
TEST_P(OEMCryptoSessionTestLoadCasKeysWithHDCP, CasOnlyLoadCasKeysAPI17) {
// Test parameterized by HDCP version.
LoadCasKeysWithHDCP(static_cast<OEMCrypto_HDCP_Capability>(GetParam()));
}
INSTANTIATE_TEST_SUITE_P(TestHDCP, OEMCryptoSessionTestLoadCasKeysWithHDCP,
Range(1, 6));
/// @}
/// @addtogroup renewal
/// @{
//
// Load, Refresh Keys Test
//
// This class is for the refresh tests that should only be run on licenses with
// a core message.
class OEMCryptoRefreshTestAPI16 : public OEMCryptoRefreshTest {};
// Refresh keys should work if the license uses a nonce.
TEST_P(OEMCryptoRefreshTest, RefreshWithNonce) {
LoadLicense();
RenewalRoundTrip renewal_messages(&license_messages_);
MakeRenewalRequest(&renewal_messages);
LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS);
}
// Refresh keys should work if the license does not use a nonce.
TEST_P(OEMCryptoRefreshTest, RefreshNoNonce) {
license_messages_.set_control(0);
LoadLicense();
RenewalRoundTrip renewal_messages(&license_messages_);
MakeRenewalRequest(&renewal_messages);
LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS);
}
// Refresh keys should NOT work if a license has not been loaded.
TEST_P(OEMCryptoRefreshTestAPI16, RefreshNoLicense) {
Session s;
s.open();
constexpr size_t message_size = kMaxCoreMessage + 42;
std::vector<uint8_t> data(message_size);
for (size_t i = 0; i < data.size(); i++) data[i] = i & 0xFF;
size_t gen_signature_length = 0;
size_t core_message_length = 0;
OEMCryptoResult sts = OEMCrypto_PrepAndSignRenewalRequest(
s.session_id(), data.data(), data.size(), &core_message_length, nullptr,
&gen_signature_length);
ASSERT_LT(core_message_length, message_size);
if (sts == OEMCrypto_ERROR_SHORT_BUFFER) {
vector<uint8_t> gen_signature(gen_signature_length);
sts = OEMCrypto_PrepAndSignRenewalRequest(
s.session_id(), data.data(), data.size(), &core_message_length,
gen_signature.data(), &gen_signature_length);
}
ASSERT_NE(OEMCrypto_SUCCESS, sts);
}
// Refresh keys should fail if the nonce is not in the session.
TEST_P(OEMCryptoRefreshTestAPI16, RefreshBadNonce) {
LoadLicense();
RenewalRoundTrip renewal_messages(&license_messages_);
MakeRenewalRequest(&renewal_messages);
renewal_messages.core_request().nonce ^= 42;
LoadRenewal(&renewal_messages, OEMCrypto_ERROR_INVALID_NONCE);
}
// Refresh keys should fail if the session_id does not match the license.
TEST_P(OEMCryptoRefreshTestAPI16, RefreshBadSessionID) {
LoadLicense();
RenewalRoundTrip renewal_messages(&license_messages_);
MakeRenewalRequest(&renewal_messages);
renewal_messages.core_request().session_id += 1;
LoadRenewal(&renewal_messages, OEMCrypto_ERROR_INVALID_NONCE);
}
// Refresh keys should handle the maximum message size.
TEST_P(OEMCryptoRefreshTest, RefreshLargeBuffer) {
LoadLicense();
RenewalRoundTrip renewal_messages(&license_messages_);
const size_t max_size = GetResourceValue(kLargeMessageSize);
renewal_messages.set_message_size(max_size);
MakeRenewalRequest(&renewal_messages);
LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS);
}
// This situation would occur if an app only uses one key in the license. When
// that happens, SelectKey would be called before the first decrypt, and then
// would not need to be called again, even if the license is refreshed.
TEST_P(OEMCryptoRefreshTest, RefreshWithNoSelectKey) {
LoadLicense();
// Call select key before the refresh. No calls below to TestDecryptCTR with
// select key set to true.
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(true));
// This should still be valid key, even if the refresh failed, because this
// is before the original license duration.
wvutil::TestSleep::Sleep(kShortSleep);
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(false));
// This should be after duration of the original license, but before the
// expiration of the refresh message. This should fail until we have loaded
// the renewal.
wvutil::TestSleep::Sleep(kShortSleep + kLongSleep);
ASSERT_NO_FATAL_FAILURE(
session_.TestDecryptCTR(false, OEMCrypto_ERROR_KEY_EXPIRED));
RenewalRoundTrip renewal_messages(&license_messages_);
MakeRenewalRequest(&renewal_messages);
LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS);
// After we've loaded the renewal, decrypt should succeed again.
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(false));
}
// Test that playback clock is correctly started and that the license can be
// renewed.
TEST_P(OEMCryptoRefreshTest, RenewLicenseLoadSuccess) {
license_messages_.core_response().renewal_delay_base = OEMCrypto_License_Load;
timer_limits_.rental_duration_seconds = kDuration; // 2 seconds.
timer_limits_.initial_renewal_duration_seconds = kLongDuration; // 5 seconds.
// First version to support Renew on Load.
constexpr uint32_t kFeatureVersion = 18;
// Loading the license should start the playback clock.
LoadLicense();
// Sleep until just after rental window is over.
wvutil::TestSleep::Sleep(kDuration + kShortSleep);
if (license_api_version_ < kFeatureVersion ||
global_features.api_version < kFeatureVersion) {
// If the feature is not supported, then we expect failure because the
// playback clock was not started and we are outside the rental window.
ASSERT_NO_FATAL_FAILURE(
session_.TestDecryptCTR(true, OEMCrypto_ERROR_KEY_EXPIRED));
return;
} else {
// If the feature is supported, we expect decrypt to work because we are
// still within the initial renewal window, and the playback clock should
// have started.
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(true, OEMCrypto_SUCCESS));
}
// This is after the initial renewal duration, so we expect failure before
// loading the renewal.
wvutil::TestSleep::Sleep(kShortSleep + kLongSleep);
ASSERT_NO_FATAL_FAILURE(
session_.TestDecryptCTR(false, OEMCrypto_ERROR_KEY_EXPIRED));
RenewalRoundTrip renewal_messages(&license_messages_);
MakeRenewalRequest(&renewal_messages);
LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS);
// After we've loaded the renewal, decrypt should succeed again.
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(false));
}
TEST_P(OEMCryptoRefreshTest, RenewLicenseLoadOutsideRentalDuration) {
license_messages_.core_response().renewal_delay_base = OEMCrypto_License_Load;
timer_limits_.rental_duration_seconds = kDuration; // 2 seconds.
timer_limits_.initial_renewal_duration_seconds = kLongDuration; // 5 seconds.
// Sleep until just after rental window is over.
wvutil::TestSleep::Sleep(kDuration + kShortSleep);
// Loading the license should start the playback clock.
LoadLicense();
// If the license is loaded after the rental duration window, we expect
// failure.
ASSERT_NO_FATAL_FAILURE(
session_.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE));
return;
}
INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoRefreshTest,
Range<uint32_t>(kCurrentAPI - 1, kCurrentAPI + 1));
// These tests only work when the license has a core message.
INSTANTIATE_TEST_SUITE_P(TestAPI16, OEMCryptoRefreshTestAPI16,
Range<uint32_t>(kCoreMessagesAPI, kCurrentAPI + 1));
/// @}
/// @addtogroup security
/// @{
TEST_F(OEMCryptoLoadsCertificate,
OEMCryptoMemoryLoadProvisioningForHugeResponseLength) {
TestLoadProvisioningForHugeBufferLengths(
[](size_t message_size, ProvisioningRoundTrip* provisioning_messages) {
provisioning_messages->set_message_size(message_size);
},
!kCheckStatus, !kUpdateCoreMessageSubstringValues);
}
TEST_F(OEMCryptoLoadsCertificate,
OEMCryptoMemoryLoadProvisioningForHugeCoreMessageLength) {
TestLoadProvisioningForHugeBufferLengths(
[](size_t message_size, ProvisioningRoundTrip* provisioning_messages) {
provisioning_messages->set_core_message_size(message_size);
},
!kCheckStatus, !kUpdateCoreMessageSubstringValues);
}
TEST_F(OEMCryptoLoadsCertificate,
OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyLength) {
TestLoadProvisioningForHugeBufferLengths(
[](size_t length, ProvisioningRoundTrip* provisioning_messages) {
provisioning_messages->core_response().enc_private_key.length = length;
},
!kCheckStatus, kUpdateCoreMessageSubstringValues);
}
TEST_F(OEMCryptoLoadsCertificate,
OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyOffset) {
TestLoadProvisioningForHugeBufferLengths(
[](size_t offset, ProvisioningRoundTrip* provisioning_messages) {
provisioning_messages->core_response().enc_private_key.offset = offset;
},
!kCheckStatus, kUpdateCoreMessageSubstringValues);
}
TEST_F(
OEMCryptoLoadsCertificate,
OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyLength) {
TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths(
[](size_t response_message_length,
ProvisioningRoundTrip* provisioning_messages) {
auto& enc_private_key =
provisioning_messages->core_response().enc_private_key;
enc_private_key.length =
response_message_length - enc_private_key.offset + 1;
});
}
TEST_F(
OEMCryptoLoadsCertificate,
OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyOffset) {
TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths(
[](size_t response_message_length,
ProvisioningRoundTrip* provisioning_messages) {
auto& enc_private_key =
provisioning_messages->core_response().enc_private_key;
enc_private_key.offset =
response_message_length - enc_private_key.length + 1;
});
}
TEST_F(OEMCryptoLoadsCertificate,
OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyIvLength) {
TestLoadProvisioningForHugeBufferLengths(
[](size_t length, ProvisioningRoundTrip* provisioning_messages) {
provisioning_messages->core_response().enc_private_key_iv.length =
length;
},
!kCheckStatus, kUpdateCoreMessageSubstringValues);
}
TEST_F(OEMCryptoLoadsCertificate,
OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyIvOffset) {
TestLoadProvisioningForHugeBufferLengths(
[](size_t offset, ProvisioningRoundTrip* provisioning_messages) {
provisioning_messages->core_response().enc_private_key_iv.offset =
offset;
},
!kCheckStatus, kUpdateCoreMessageSubstringValues);
}
TEST_F(
OEMCryptoLoadsCertificate,
OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyIvLengthAPI16) {
TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths(
[](size_t response_message_length,
ProvisioningRoundTrip* provisioning_messages) {
auto& enc_private_key_iv =
provisioning_messages->core_response().enc_private_key_iv;
enc_private_key_iv.length =
response_message_length - enc_private_key_iv.offset + 1;
});
}
TEST_F(
OEMCryptoLoadsCertificate,
OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyIvOffset) {
TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths(
[](size_t response_message_length,
ProvisioningRoundTrip* provisioning_messages) {
auto& enc_private_key_iv =
provisioning_messages->core_response().enc_private_key_iv;
enc_private_key_iv.offset =
response_message_length - enc_private_key_iv.length + 1;
});
}
TEST_F(OEMCryptoLoadsCertificate,
OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncMessageKeyLength) {
TestLoadProvisioningForHugeBufferLengths(
[](size_t length, ProvisioningRoundTrip* provisioning_messages) {
provisioning_messages->core_response().encrypted_message_key.length =
length;
},
!kCheckStatus, kUpdateCoreMessageSubstringValues);
}
TEST_F(OEMCryptoLoadsCertificate,
OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncMessageKeyOffset) {
TestLoadProvisioningForHugeBufferLengths(
[](size_t offset, ProvisioningRoundTrip* provisioning_messages) {
provisioning_messages->core_response().encrypted_message_key.offset =
offset;
},
!kCheckStatus, kUpdateCoreMessageSubstringValues);
}
TEST_F(
OEMCryptoLoadsCertificate,
OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncMessageKeyLengthProv30) {
if (global_features.provisioning_method != OEMCrypto_OEMCertificate) {
GTEST_SKIP() << "Test for Prov 3.0 devices only.";
}
TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths(
[](size_t response_message_length,
ProvisioningRoundTrip* provisioning_messages) {
auto& encrypted_message_key =
provisioning_messages->core_response().encrypted_message_key;
encrypted_message_key.length =
response_message_length - encrypted_message_key.offset + 1;
});
}
TEST_F(
OEMCryptoLoadsCertificate,
OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncMessageKeyOffsetProv30) {
if (global_features.provisioning_method != OEMCrypto_OEMCertificate) {
GTEST_SKIP() << "Test for Prov 3.0 devices only.";
}
TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths(
[](size_t response_message_length,
ProvisioningRoundTrip* provisioning_messages) {
auto& encrypted_message_key =
provisioning_messages->core_response().encrypted_message_key;
encrypted_message_key.offset =
response_message_length - encrypted_message_key.length + 1;
});
}
/// @}
/// @addtogroup provision
/// @{
// Test that a wrapped RSA key can be loaded.
TEST_F(OEMCryptoLoadsCertificate, LoadWrappedRSAKey) {
ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey());
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_));
}
class OEMCryptoLoadsCertVariousKeys : public OEMCryptoLoadsCertificate {
public:
void TestKey(const uint8_t* key, size_t key_length) {
encoded_rsa_key_.assign(key, key + key_length);
ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey());
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(s.SetRsaPublicKeyFromPrivateKeyInfo(
encoded_rsa_key_.data(), encoded_rsa_key_.size()));
ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_));
LicenseRoundTrip license_messages(&s);
ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest());
ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(license_messages.EncryptAndSignResponse());
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages.LoadResponse());
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR());
}
};
// Test a 3072 bit RSA key certificate.
TEST_F(OEMCryptoLoadsCertVariousKeys, TestLargeRSAKey3072) {
TestKey(kTestRSAPKCS8PrivateKeyInfo3_3072,
sizeof(kTestRSAPKCS8PrivateKeyInfo3_3072));
}
// Test an RSA key certificate which has a private key generated using the
// Carmichael totient.
TEST_F(OEMCryptoLoadsCertVariousKeys, TestCarmichaelRSAKey) {
TestKey(kTestKeyRSACarmichael_2048, sizeof(kTestKeyRSACarmichael_2048));
}
TEST_F(OEMCryptoLoadsCertVariousKeys, TestCarmichaelNonZeroNormalDer) {
TestKey(kCarmichaelNonZeroNormalDer, kCarmichaelNonZeroNormalDerLen);
}
TEST_F(OEMCryptoLoadsCertVariousKeys, TestCarmichaelNonZeroShortDer) {
TestKey(kCarmichaelNonZeroShortDer, kCarmichaelNonZeroShortDerLen);
}
TEST_F(OEMCryptoLoadsCertVariousKeys, TestCarmichaelZeroNormalDer) {
TestKey(kCarmichaelZeroNormalDer, kCarmichaelZeroNormalDerLen);
}
TEST_F(OEMCryptoLoadsCertVariousKeys, TestCarmichaelZeroShortDer) {
TestKey(kCarmichaelZeroShortDer, kCarmichaelZeroShortDerLen);
}
TEST_F(OEMCryptoLoadsCertVariousKeys, TestDualNonZeroNormalDer) {
TestKey(kDualNonZeroNormalDer, kDualNonZeroNormalDerLen);
}
TEST_F(OEMCryptoLoadsCertVariousKeys, TestDualNonZeroShortDer) {
TestKey(kDualNonZeroShortDer, kDualNonZeroShortDerLen);
}
TEST_F(OEMCryptoLoadsCertVariousKeys, TestDualZeroNormalDer) {
TestKey(kDualZeroNormalDer, kDualZeroNormalDerLen);
}
TEST_F(OEMCryptoLoadsCertVariousKeys, TestDualZeroShortDer) {
TestKey(kDualZeroShortDer, kDualZeroShortDerLen);
}
TEST_F(OEMCryptoLoadsCertVariousKeys, TestEulerNonZeroNormalDer) {
TestKey(kEulerNonZeroNormalDer, kEulerNonZeroNormalDerLen);
}
TEST_F(OEMCryptoLoadsCertVariousKeys, TestEulerZeroNormalDer) {
TestKey(kEulerZeroNormalDer, kEulerZeroNormalDerLen);
}
// This tests that two sessions can use different RSA keys simultaneously.
TEST_F(OEMCryptoLoadsCertificate, TestMultipleRSAKeys) {
ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey());
Session s1; // Session s1 loads the default rsa key, but doesn't use it
// until after s2 uses its key.
ASSERT_NO_FATAL_FAILURE(s1.open());
ASSERT_NO_FATAL_FAILURE(s1.SetRsaPublicKeyFromPrivateKeyInfo(
encoded_rsa_key_.data(), encoded_rsa_key_.size()));
ASSERT_NO_FATAL_FAILURE(s1.LoadWrappedRsaDrmKey(wrapped_drm_key_));
Session s2; // Session s2 uses a different rsa key.
encoded_rsa_key_.assign(kTestRSAPKCS8PrivateKeyInfo4_2048,
kTestRSAPKCS8PrivateKeyInfo4_2048 +
sizeof(kTestRSAPKCS8PrivateKeyInfo4_2048));
ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey());
ASSERT_NO_FATAL_FAILURE(s2.open());
ASSERT_NO_FATAL_FAILURE(s2.SetRsaPublicKeyFromPrivateKeyInfo(
encoded_rsa_key_.data(), encoded_rsa_key_.size()));
ASSERT_NO_FATAL_FAILURE(s2.LoadWrappedRsaDrmKey(wrapped_drm_key_));
LicenseRoundTrip license_messages2(&s2);
ASSERT_NO_FATAL_FAILURE(license_messages2.SignAndVerifyRequest());
ASSERT_NO_FATAL_FAILURE(license_messages2.CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(license_messages2.EncryptAndSignResponse());
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages2.LoadResponse());
ASSERT_NO_FATAL_FAILURE(s2.TestDecryptCTR());
s2.close();
// After s2 has loaded its rsa key, we continue using s1's key.
LicenseRoundTrip license_messages1(&s1);
ASSERT_NO_FATAL_FAILURE(license_messages1.SignAndVerifyRequest());
ASSERT_NO_FATAL_FAILURE(license_messages1.CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(license_messages1.EncryptAndSignResponse());
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages1.LoadResponse());
ASSERT_NO_FATAL_FAILURE(s1.TestDecryptCTR());
}
// This tests the maximum number of DRM private keys that OEMCrypto can load
TEST_F(OEMCryptoLoadsCertificate, TestMaxDRMKeys) {
const size_t max_total_keys = GetResourceValue(kMaxTotalDRMPrivateKeys);
std::vector<std::unique_ptr<Session>> sessions;
std::vector<std::unique_ptr<LicenseRoundTrip>> licenses;
// It should be able to load up to kMaxTotalDRMPrivateKeys keys
for (size_t i = 0; i < max_total_keys; i++) {
sessions.push_back(std::unique_ptr<Session>(new Session()));
licenses.push_back(std::unique_ptr<LicenseRoundTrip>(
new LicenseRoundTrip(sessions[i].get())));
const size_t key_index = i % kTestRSAPKCS8PrivateKeys_2048.size();
encoded_rsa_key_.assign(kTestRSAPKCS8PrivateKeys_2048[key_index].begin(),
kTestRSAPKCS8PrivateKeys_2048[key_index].end());
ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey());
ASSERT_NO_FATAL_FAILURE(sessions[i]->open());
ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(sessions[i].get()));
}
// Attempts to load one more key than the kMaxTotalDRMPrivateKeys
if (global_features.provisioning_method == OEMCrypto_BootCertificateChain) {
Session s;
const size_t buffer_size = 5000; // Make sure it is large enough.
std::vector<uint8_t> public_key(buffer_size);
size_t public_key_size = buffer_size;
std::vector<uint8_t> public_key_signature(buffer_size);
size_t public_key_signature_size = buffer_size;
std::vector<uint8_t> wrapped_private_key(buffer_size);
size_t wrapped_private_key_size = buffer_size;
OEMCrypto_PrivateKeyType key_type;
OEMCryptoResult result = OEMCrypto_GenerateCertificateKeyPair(
s.session_id(), public_key.data(), &public_key_size,
public_key_signature.data(), &public_key_signature_size,
wrapped_private_key.data(), &wrapped_private_key_size, &key_type);
// Key creation is allowed to fail due to resource restriction
if (result != OEMCrypto_SUCCESS) {
ASSERT_TRUE(result == OEMCrypto_ERROR_INSUFFICIENT_RESOURCES ||
result == OEMCrypto_ERROR_TOO_MANY_KEYS);
}
} else {
Session s;
encoded_rsa_key_.assign(kTestRSAPKCS8PrivateKeyInfo2_2048,
kTestRSAPKCS8PrivateKeyInfo2_2048 +
sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048));
Session ps;
ProvisioningRoundTrip provisioning_messages(&ps, encoded_rsa_key_);
provisioning_messages.PrepareSession(keybox_);
ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest());
ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse());
OEMCryptoResult result = provisioning_messages.LoadResponse();
// Key loading is allowed to fail due to resource restriction
if (result != OEMCrypto_SUCCESS) {
ASSERT_TRUE(result == OEMCrypto_ERROR_INSUFFICIENT_RESOURCES ||
result == OEMCrypto_ERROR_TOO_MANY_KEYS);
}
}
// Verifies that the DRM keys which are already loaded should still function
for (size_t i = 0; i < licenses.size(); i++) {
ASSERT_NO_FATAL_FAILURE(licenses[i]->SignAndVerifyRequest());
ASSERT_NO_FATAL_FAILURE(licenses[i]->CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(licenses[i]->EncryptAndSignResponse());
ASSERT_EQ(OEMCrypto_SUCCESS, licenses[i]->LoadResponse());
ASSERT_NO_FATAL_FAILURE(sessions[i]->TestDecryptCTR());
}
}
// Devices that load certificates, should at least support RSA 2048 keys.
TEST_F(OEMCryptoLoadsCertificate, SupportsCertificatesAPI13) {
ASSERT_NE(0u,
OEMCrypto_Supports_RSA_2048bit & OEMCrypto_SupportedCertificates())
<< "Supported certificates is only " << OEMCrypto_SupportedCertificates();
}
/// @}
/// @addtogroup security
/// @{
TEST_F(OEMCryptoLoadsCertificate,
OEMCryptoMemoryPrepareProvisioningRequestForHugeRequestMessageLength) {
TestPrepareProvisioningRequestForHugeBufferLengths(
[](size_t message_size, ProvisioningRoundTrip* provisioning_messages) {
provisioning_messages->set_message_size(message_size);
},
kCheckStatus);
}
TEST_F(OEMCryptoLoadsCertificate,
OEMCryptoMemoryPrepareProvisioningRequestForHugeSignatureLength) {
TestPrepareProvisioningRequestForHugeBufferLengths(
[](size_t message_size, ProvisioningRoundTrip* provisioning_messages) {
provisioning_messages->set_request_signature_size(message_size);
},
!kCheckStatus);
}
TEST_F(OEMCryptoLoadsCertificate,
OEMCryptoMemoryPrepareProvisioningRequestForHugeCoreMessageLength) {
TestPrepareProvisioningRequestForHugeBufferLengths(
[](size_t message_size, ProvisioningRoundTrip* provisioning_messages) {
provisioning_messages->set_core_message_size(message_size);
},
kCheckStatus);
}
/// @}
/// @addtogroup provision
/// @{
// These tests are run by all L1 devices that load and use certificates. It is
// also run by a few L3 devices that use a baked in certificate, but cannot load
// a certificate.
class OEMCryptoUsesCertificate : public OEMCryptoLoadsCertificate {
protected:
void SetUp() override {
OEMCryptoLoadsCertificate::SetUp();
ASSERT_NO_FATAL_FAILURE(session_.open());
if (global_features.derive_key_method ==
DeviceFeatures::LOAD_TEST_RSA_KEY) {
ASSERT_NO_FATAL_FAILURE(session_.SetRsaPublicKeyFromPrivateKeyInfo(
encoded_rsa_key_.data(), encoded_rsa_key_.size()));
} else {
InstallTestDrmKey(&session_);
}
}
void TearDown() override {
ASSERT_NO_FATAL_FAILURE(session_.close());
OEMCryptoLoadsCertificate::TearDown();
}
Session session_;
};
// This test is not run by default, because it takes a long time and
// is used to measure RSA performance, not test functionality.
TEST_F(OEMCryptoLoadsCertificate, RSAPerformance) {
const std::chrono::milliseconds kTestDuration(5000);
OEMCryptoResult sts;
std::chrono::steady_clock clock;
wvutil::TestSleep::Sleep(kShortSleep); // Make sure we are not nonce limited.
auto start_time = clock.now();
int count = 15;
for (int i = 0; i < count; i++) { // Only 20 nonce available.
ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey());
}
auto delta_time = clock.now() - start_time;
const double provision_time =
delta_time / std::chrono::milliseconds(1) / count;
Session session;
ASSERT_NO_FATAL_FAILURE(CreateWrappedDRMKey());
start_time = clock.now();
count = 0;
while (clock.now() - start_time < kTestDuration) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_));
const size_t size = 50;
vector<uint8_t> licenseRequest(size);
GetRandBytes(licenseRequest.data(), licenseRequest.size());
size_t signature_length = 0;
sts = OEMCrypto_GenerateRSASignature(s.session_id(), licenseRequest.data(),
licenseRequest.size(), nullptr,
&signature_length, kSign_RSASSA_PSS);
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
ASSERT_NE(static_cast<size_t>(0), signature_length);
if (ShouldGenerateCorpus()) {
const std::string file_name =
GetFileName("oemcrypto_generate_rsa_signature_fuzz_seed_corpus");
OEMCrypto_Generate_RSA_Signature_Fuzz fuzzed_structure;
fuzzed_structure.padding_scheme = kSign_RSASSA_PSS;
fuzzed_structure.signature_length = signature_length;
// Cipher mode and algorithm.
AppendToFile(file_name, reinterpret_cast<const char*>(&fuzzed_structure),
sizeof(fuzzed_structure));
AppendToFile(file_name,
reinterpret_cast<const char*>(licenseRequest.data()),
licenseRequest.size());
}
std::vector<uint8_t> signature(signature_length, 0);
sts = OEMCrypto_GenerateRSASignature(
s.session_id(), licenseRequest.data(), licenseRequest.size(),
signature.data(), &signature_length, kSign_RSASSA_PSS);
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
count++;
}
delta_time = clock.now() - start_time;
const double license_request_time =
delta_time / std::chrono::milliseconds(1) / count;
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_));
vector<uint8_t> session_key;
vector<uint8_t> enc_session_key;
ASSERT_NO_FATAL_FAILURE(s.SetRsaPublicKeyFromPrivateKeyInfo(
encoded_rsa_key_.data(), encoded_rsa_key_.size()));
ASSERT_TRUE(s.GenerateRsaSessionKey(&session_key, &enc_session_key));
vector<uint8_t> mac_context;
vector<uint8_t> enc_context;
s.FillDefaultContext(&mac_context, &enc_context);
enc_session_key = wvutil::a2b_hex(
"7789c619aa3b9fa3c0a53f57a4abc6"
"02157c8aa57e3c6fb450b0bea22667fb"
"0c3200f9d9d618e397837c720dc2dadf"
"486f33590744b2a4e54ca134ae7dbf74"
"434c2fcf6b525f3e132262f05ea3b3c1"
"198595c0e52b573335b2e8a3debd0d0d"
"d0306f8fcdde4e76476be71342957251"
"e1688c9ca6c1c34ed056d3b989394160"
"cf6937e5ce4d39cc73d11a2e93da21a2"
"fa019d246c852fe960095b32f120c3c2"
"7085f7b64aac344a68d607c0768676ce"
"d4c5b2d057f7601921b453a451e1dea0"
"843ebfef628d9af2784d68e86b730476"
"e136dfe19989de4be30a4e7878efcde5"
"ad2b1254f80c0c5dd3cf111b56572217"
"b9f58fc1dacbf74b59d354a1e62cfa0e"
"bf");
start_time = clock.now();
while (clock.now() - start_time < kTestDuration) {
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_DeriveKeysFromSessionKey(
s.session_id(), enc_session_key.data(),
enc_session_key.size(), mac_context.data(),
mac_context.size(), enc_context.data(), enc_context.size()));
count++;
}
delta_time = clock.now() - start_time;
const double derive_keys_time =
delta_time / std::chrono::milliseconds(1) / count;
OEMCrypto_Security_Level level = OEMCrypto_SecurityLevel();
printf("PERF:head, security, provision (ms), lic req(ms), derive keys(ms)\n");
printf("PERF:stat, %u, %8.3f, %8.3f, %8.3f\n",
static_cast<unsigned int>(level), provision_time, license_request_time,
derive_keys_time);
}
// Test DeriveKeysFromSessionKey using the maximum size for the HMAC context.
TEST_F(OEMCryptoUsesCertificate, GenerateDerivedKeysLargeBuffer) {
vector<uint8_t> session_key;
vector<uint8_t> enc_session_key;
ASSERT_TRUE(session_.GenerateSessionKey(&session_key, &enc_session_key));
const size_t max_size = GetResourceValue(kLargeMessageSize);
vector<uint8_t> mac_context(max_size);
vector<uint8_t> enc_context(max_size);
// Stripe the data so the two vectors are not identical, and not all zeroes.
for (size_t i = 0; i < max_size; i++) {
mac_context[i] = i % 0x100;
enc_context[i] = (3 * i) % 0x100;
}
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_DeriveKeysFromSessionKey(
session_.session_id(), enc_session_key.data(),
enc_session_key.size(), mac_context.data(), mac_context.size(),
enc_context.data(), enc_context.size()));
}
/// @}
/// @addtogroup cast
/// @{
// This test attempts to use alternate algorithms for loaded device certs.
class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate {
protected:
void DisallowForbiddenPadding(RSA_Padding_Scheme scheme, size_t size) {
OEMCryptoResult sts;
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_));
// Sign a Message
vector<uint8_t> licenseRequest(size);
GetRandBytes(licenseRequest.data(), licenseRequest.size());
size_t signature_length = 256;
vector<uint8_t> signature(signature_length);
sts = OEMCrypto_GenerateRSASignature(
s.session_id(), licenseRequest.data(), licenseRequest.size(),
signature.data(), &signature_length, scheme);
// Allow OEMCrypto to request a full buffer.
if (sts == OEMCrypto_ERROR_SHORT_BUFFER) {
ASSERT_NE(static_cast<size_t>(0), signature_length);
signature.assign(signature_length, 0);
sts = OEMCrypto_GenerateRSASignature(
s.session_id(), licenseRequest.data(), licenseRequest.size(),
signature.data(), &signature_length, scheme);
}
EXPECT_NE(OEMCrypto_SUCCESS, sts)
<< "Signed with forbidden padding scheme=" << (int)scheme
<< ", size=" << (int)size;
const vector<uint8_t> zero(signature.size(), 0);
ASSERT_EQ(zero, signature); // signature should not be computed.
}
void TestSignature(RSA_Padding_Scheme scheme, size_t size) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_));
vector<uint8_t> licenseRequest(size);
GetRandBytes(licenseRequest.data(), licenseRequest.size());
size_t signature_length = 0;
OEMCryptoResult sts = OEMCrypto_GenerateRSASignature(
s.session_id(), licenseRequest.data(), licenseRequest.size(), nullptr,
&signature_length, scheme);
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
ASSERT_NE(static_cast<size_t>(0), signature_length);
std::vector<uint8_t> signature(signature_length, 0);
sts = OEMCrypto_GenerateRSASignature(
s.session_id(), licenseRequest.data(), licenseRequest.size(),
signature.data(), &signature_length, scheme);
ASSERT_EQ(OEMCrypto_SUCCESS, sts)
<< "Failed to sign with padding scheme=" << (int)scheme
<< ", size=" << size;
signature.resize(signature_length);
ASSERT_NO_FATAL_FAILURE(s.SetRsaPublicKeyFromPrivateKeyInfo(
encoded_rsa_key_.data(), encoded_rsa_key_.size()));
ASSERT_NO_FATAL_FAILURE(s.VerifyRsaSignature(
licenseRequest, signature.data(), signature_length, scheme));
}
void DisallowDeriveKeys() {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_));
s.GenerateNonce();
vector<uint8_t> session_key;
vector<uint8_t> enc_session_key;
ASSERT_NO_FATAL_FAILURE(s.SetRsaPublicKeyFromPrivateKeyInfo(
encoded_rsa_key_.data(), encoded_rsa_key_.size()));
ASSERT_TRUE(s.GenerateRsaSessionKey(&session_key, &enc_session_key));
vector<uint8_t> mac_context;
vector<uint8_t> enc_context;
s.FillDefaultContext(&mac_context, &enc_context);
ASSERT_NE(OEMCrypto_SUCCESS,
OEMCrypto_DeriveKeysFromSessionKey(
s.session_id(), enc_session_key.data(),
enc_session_key.size(), mac_context.data(),
mac_context.size(), enc_context.data(), enc_context.size()));
}
// If force is true, we assert that the key loads successfully.
void LoadWithAllowedSchemes(uint32_t schemes, bool force) {
Session s;
ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_);
provisioning_messages.set_allowed_schemes(schemes);
provisioning_messages.PrepareSession(keybox_);
ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest());
ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse());
OEMCryptoResult sts = provisioning_messages.LoadResponse();
key_loaded_ = (OEMCrypto_SUCCESS == sts);
if (key_loaded_) {
uint8_t* ptr = provisioning_messages.response_data().rsa_key;
size_t len = provisioning_messages.response_data().rsa_key_length;
encoded_rsa_key_ = std::vector<uint8_t>(ptr, ptr + len);
wrapped_drm_key_ = provisioning_messages.wrapped_rsa_key();
drm_key_type_ = OEMCrypto_RSA_Private_Key;
EXPECT_GT(wrapped_drm_key_.size(), 0u);
EXPECT_EQ(nullptr, find(wrapped_drm_key_, encoded_rsa_key_));
}
if (force) {
EXPECT_EQ(OEMCrypto_SUCCESS, sts);
}
}
bool key_loaded_ = false;
};
// The alternate padding is only required for cast receivers, but all devices
// should forbid the alternate padding for regular certificates.
TEST_F(OEMCryptoLoadsCertificateAlternates, DisallowForbiddenPaddingAPI09) {
LoadWithAllowedSchemes(kSign_RSASSA_PSS, true); // Use default padding scheme
DisallowForbiddenPadding(kSign_PKCS1_Block1, 50);
}
// The alternate padding is only required for cast receivers, but if a device
// does load an alternate certificate, it should NOT use it for generating
// a license request signature.
TEST_F(OEMCryptoLoadsCertificateAlternates, TestSignaturePKCS1) {
// Try to load an RSA key with alternative padding schemes. This signing
// scheme is used by cast receivers.
LoadWithAllowedSchemes(kSign_PKCS1_Block1, false);
// If the device is a cast receiver, then this scheme is required.
if (global_features.cast_receiver) {
ASSERT_TRUE(key_loaded_);
}
// If the key loaded with no error, then we will verify that it is not used
// for forbidden padding schemes.
if (key_loaded_) {
// The other padding scheme should fail.
DisallowForbiddenPadding(kSign_RSASSA_PSS, 83);
DisallowDeriveKeys();
if (global_features.cast_receiver) {
// A signature with a valid size should succeed.
TestSignature(kSign_PKCS1_Block1, 83);
TestSignature(kSign_PKCS1_Block1, 50);
}
// A signature with padding that is too big should fail.
DisallowForbiddenPadding(kSign_PKCS1_Block1, 84); // too big.
}
}
// This test verifies RSA signing with the alternate padding scheme used by
// Android cast receivers, PKCS1 Block 1. These tests are not required for
// other devices, and should be filtered out by DeviceFeatures::Initialize for
// those devices.
class OEMCryptoCastReceiverTest : public OEMCryptoLoadsCertificateAlternates {
protected:
void SetUp() override {
OEMCryptoLoadsCertificateAlternates::SetUp();
if (!global_features.cast_receiver) {
GTEST_SKIP() << "OEMCrypto does not support CAST Receiver functionality";
}
}
vector<uint8_t> encode(uint8_t type, const vector<uint8_t>& substring) {
vector<uint8_t> result;
result.push_back(type);
if (substring.size() < 0x80) {
uint8_t length = substring.size();
result.push_back(length);
} else if (substring.size() < 0x100) {
result.push_back(0x81);
uint8_t length = substring.size();
result.push_back(length);
} else {
result.push_back(0x82);
uint16_t length = substring.size();
result.push_back(length >> 8);
result.push_back(length & 0xFF);
}
result.insert(result.end(), substring.begin(), substring.end());
return result;
}
vector<uint8_t> concat(const vector<uint8_t>& a, const vector<uint8_t>& b) {
vector<uint8_t> result = a;
result.insert(result.end(), b.begin(), b.end());
return result;
}
// This encodes the RSA key used in the PKCS#1 signing tests below.
void BuildRSAKey() {
vector<uint8_t> field_n =
encode(0x02, wvutil::a2b_hex("00"
"df271fd25f8644496b0c81be4bd50297"
"ef099b002a6fd67727eb449cea566ed6"
"a3981a71312a141cabc9815c1209e320"
"a25b32464e9999f18ca13a9fd3892558"
"f9e0adefdd3650dd23a3f036d60fe398"
"843706a40b0b8462c8bee3bce12f1f28"
"60c2444cdc6a44476a75ff4aa24273cc"
"be3bf80248465f8ff8c3a7f3367dfc0d"
"f5b6509a4f82811cedd81cdaaa73c491"
"da412170d544d4ba96b97f0afc806549"
"8d3a49fd910992a1f0725be24f465cfe"
"7e0eabf678996c50bc5e7524abf73f15"
"e5bef7d518394e3138ce4944506aaaaf"
"3f9b236dcab8fc00f87af596fdc3d9d6"
"c75cd508362fae2cbeddcc4c7450b17b"
"776c079ecca1f256351a43b97dbe2153"));
vector<uint8_t> field_e = encode(0x02, wvutil::a2b_hex("010001"));
vector<uint8_t> field_d =
encode(0x02, wvutil::a2b_hex("5bd910257830dce17520b03441a51a8c"
"ab94020ac6ecc252c808f3743c95b7c8"
"3b8c8af1a5014346ebc4242cdfb5d718"
"e30a733e71f291e4d473b61bfba6daca"
"ed0a77bd1f0950ae3c91a8f901118825"
"89e1d62765ee671e7baeea309f64d447"
"bbcfa9ea12dce05e9ea8939bc5fe6108"
"581279c982b308794b3448e7f7b95229"
"2df88c80cb40142c4b5cf5f8ddaa0891"
"678d610e582fcb880f0d707caf47d09a"
"84e14ca65841e5a3abc5e9dba94075a9"
"084341f0edad9b68e3b8e082b80b6e6e"
"8a0547b44fb5061b6a9131603a5537dd"
"abd01d8e863d8922e9aa3e4bfaea0b39"
"d79283ad2cbc8a59cce7a6ecf4e4c81e"
"d4c6591c807defd71ab06866bb5e7745"));
vector<uint8_t> field_p =
encode(0x02, wvutil::a2b_hex("00"
"f44f5e4246391f482b2f5296e3602eb3"
"4aa136427710f7c0416d403fd69d4b29"
"130cfebef34e885abdb1a8a0a5f0e9b5"
"c33e1fc3bfc285b1ae17e40cc67a1913"
"dd563719815ebaf8514c2a7aa0018e63"
"b6c631dc315a46235716423d11ff5803"
"4e610645703606919f5c7ce2660cd148"
"bd9efc123d9c54b6705590d006cfcf3f"));
vector<uint8_t> field_q =
encode(0x02, wvutil::a2b_hex("00"
"e9d49841e0e0a6ad0d517857133e36dc"
"72c1bdd90f9174b52e26570f373640f1"
"c185e7ea8e2ed7f1e4ebb951f70a5802"
"3633b0097aec67c6dcb800fc1a67f9bb"
"0563610f08ebc8746ad129772136eb1d"
"daf46436450d318332a84982fe5d28db"
"e5b3e912407c3e0e03100d87d436ee40"
"9eec1cf85e80aba079b2e6106b97bced"));
vector<uint8_t> field_exp1 =
encode(0x02, wvutil::a2b_hex("00"
"ed102acdb26871534d1c414ecad9a4d7"
"32fe95b10eea370da62f05de2c393b1a"
"633303ea741b6b3269c97f704b352702"
"c9ae79922f7be8d10db67f026a8145de"
"41b30c0a42bf923bac5f7504c248604b"
"9faa57ed6b3246c6ba158e36c644f8b9"
"548fcf4f07e054a56f768674054440bc"
"0dcbbc9b528f64a01706e05b0b91106f"));
vector<uint8_t> field_exp2 =
encode(0x02, wvutil::a2b_hex("6827924a85e88b55ba00f8219128bd37"
"24c6b7d1dfe5629ef197925fecaff5ed"
"b9cdf3a7befd8ea2e8dd3707138b3ff8"
"7c3c39c57f439e562e2aa805a39d7cd7"
"9966d2ece7845f1dbc16bee99999e4d0"
"bf9eeca45fcda8a8500035fe6b5f03bc"
"2f6d1bfc4d4d0a3723961af0cdce4a01"
"eec82d7f5458ec19e71b90eeef7dff61"));
vector<uint8_t> field_invq =
encode(0x02, wvutil::a2b_hex("57b73888d183a99a6307422277551a3d"
"9e18adf06a91e8b55ceffef9077c8496"
"948ecb3b16b78155cb2a3a57c119d379"
"951c010aa635edcf62d84c5a122a8d67"
"ab5fa9e5a4a8772a1e943bafc70ae3a4"
"c1f0f3a4ddffaefd1892c8cb33bb0d0b"
"9590e963a69110fb34db7b906fc4ba28"
"36995aac7e527490ac952a02268a4f18"));
// Header of rsa key is constant.
encoded_rsa_key_ = wvutil::a2b_hex(
// 0x02 0x01 0x00 == integer, size 1 byte, value = 0 (field=version)
"020100"
// 0x30, sequence, size = d = 13 (field=pkeyalg) AlgorithmIdentifier
"300d"
// 0x06 = object identifier. length = 9
// (this should be 1.2.840.113549.1.1.1) (field=algorithm)
"0609"
"2a" // 1*0x40 + 2 = 42 = 0x2a.
"8648" // 840 = 0x348, 0x03 *2 + 0x80 + (0x48>>15) = 0x86.
// 0x48 -> 0x48
"86f70d" // 113549 = 0x1668d -> (110 , 1110111, 0001101)
// -> (0x80+0x06, 0x80+0x77, 0x0d)
"01" // 1
"01" // 1
"01" // 1
"05" // null object. (field=parameter?)
"00" // size of null object
);
vector<uint8_t> pkey = wvutil::a2b_hex("020100"); // integer, version = 0.
pkey = concat(pkey, field_n);
pkey = concat(pkey, field_e);
pkey = concat(pkey, field_d);
pkey = concat(pkey, field_p);
pkey = concat(pkey, field_q);
pkey = concat(pkey, field_exp1);
pkey = concat(pkey, field_exp2);
pkey = concat(pkey, field_invq);
pkey = encode(0x30, pkey);
pkey = encode(0x04, pkey);
encoded_rsa_key_ = concat(encoded_rsa_key_, pkey);
encoded_rsa_key_ = encode(0x30, encoded_rsa_key_); // 0x30=sequence
}
// This is used to test a signature from the file pkcs1v15sign-vectors.txt.
void TestSignature(RSA_Padding_Scheme scheme, const vector<uint8_t>& message,
const vector<uint8_t>& correct_signature) {
OEMCryptoResult sts;
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_));
// The application will compute the SHA-1 Hash of the message, so this
// test must do that also.
uint8_t hash[SHA_DIGEST_LENGTH];
if (!SHA1(message.data(), message.size(), hash)) {
dump_boringssl_error();
FAIL() << "boringssl error creating SHA1 hash.";
}
// The application will prepend the digest info to the hash.
// SHA-1 digest info prefix = 0x30 0x21 0x30 ...
vector<uint8_t> digest = wvutil::a2b_hex("3021300906052b0e03021a05000414");
digest.insert(digest.end(), hash, hash + SHA_DIGEST_LENGTH);
// OEMCrypto will apply the padding, and encrypt to generate the signature.
size_t signature_length = 0;
sts = OEMCrypto_GenerateRSASignature(s.session_id(), digest.data(),
digest.size(), nullptr,
&signature_length, scheme);
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
ASSERT_NE(static_cast<size_t>(0), signature_length);
vector<uint8_t> signature(signature_length);
sts = OEMCrypto_GenerateRSASignature(s.session_id(), digest.data(),
digest.size(), signature.data(),
&signature_length, scheme);
ASSERT_EQ(OEMCrypto_SUCCESS, sts)
<< "Failed to sign with padding scheme=" << (int)scheme
<< ", size=" << message.size();
signature.resize(signature_length);
ASSERT_NO_FATAL_FAILURE(s.SetRsaPublicKeyFromPrivateKeyInfo(
encoded_rsa_key_.data(), encoded_rsa_key_.size()));
// Verify that the signature matches the official test vector.
ASSERT_EQ(correct_signature.size(), signature_length);
signature.resize(signature_length);
ASSERT_EQ(correct_signature, signature);
// Also verify that our verification algorithm agrees. This is not needed
// to test OEMCrypto, but it does verify that this test is valid.
ASSERT_NO_FATAL_FAILURE(s.VerifyRsaSignature(digest, signature.data(),
signature_length, scheme));
ASSERT_NO_FATAL_FAILURE(s.VerifyRsaSignature(
digest, correct_signature.data(), correct_signature.size(), scheme));
}
};
// CAST Receivers should report that they support cast certificates.
TEST_F(OEMCryptoCastReceiverTest, SupportsCertificatesAPI13) {
ASSERT_NE(0u,
OEMCrypto_Supports_RSA_CAST & OEMCrypto_SupportedCertificates());
}
// # PKCS#1 v1.5 Signature Example 15.1
TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_1) {
BuildRSAKey();
LoadWithAllowedSchemes(kSign_PKCS1_Block1, true);
vector<uint8_t> message = wvutil::a2b_hex(
"f45d55f35551e975d6a8dc7ea9f48859"
"3940cc75694a278f27e578a163d839b3"
"4040841808cf9c58c9b8728bf5f9ce8e"
"e811ea91714f47bab92d0f6d5a26fcfe"
"ea6cd93b910c0a2c963e64eb1823f102"
"753d41f0335910ad3a977104f1aaf6c3"
"742716a9755d11b8eed690477f445c5d"
"27208b2e284330fa3d301423fa7f2d08"
"6e0ad0b892b9db544e456d3f0dab85d9"
"53c12d340aa873eda727c8a649db7fa6"
"3740e25e9af1533b307e61329993110e"
"95194e039399c3824d24c51f22b26bde"
"1024cd395958a2dfeb4816a6e8adedb5"
"0b1f6b56d0b3060ff0f1c4cb0d0e001d"
"d59d73be12");
vector<uint8_t> signature = wvutil::a2b_hex(
"b75a5466b65d0f300ef53833f2175c8a"
"347a3804fc63451dc902f0b71f908345"
"9ed37a5179a3b723a53f1051642d7737"
"4c4c6c8dbb1ca20525f5c9f32db77695"
"3556da31290e22197482ceb69906c46a"
"758fb0e7409ba801077d2a0a20eae7d1"
"d6d392ab4957e86b76f0652d68b83988"
"a78f26e11172ea609bf849fbbd78ad7e"
"dce21de662a081368c040607cee29db0"
"627227f44963ad171d2293b633a392e3"
"31dca54fe3082752f43f63c161b447a4"
"c65a6875670d5f6600fcc860a1caeb0a"
"88f8fdec4e564398a5c46c87f68ce070"
"01f6213abe0ab5625f87d19025f08d81"
"dac7bd4586bc9382191f6d2880f6227e"
"5df3eed21e7792d249480487f3655261");
TestSignature(kSign_PKCS1_Block1, message, signature);
}
// # PKCS#1 v1.5 Signature Example 15.2
TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_2) {
BuildRSAKey();
LoadWithAllowedSchemes(kSign_PKCS1_Block1, true);
vector<uint8_t> message = wvutil::a2b_hex(
"c14b4c6075b2f9aad661def4ecfd3cb9"
"33c623f4e63bf53410d2f016d1ab98e2"
"729eccf8006cd8e08050737d95fdbf29"
"6b66f5b9792a902936c4f7ac69f51453"
"ce4369452dc22d96f037748114662000"
"dd9cd3a5e179f4e0f81fa6a0311ca1ae"
"e6519a0f63cec78d27bb726393fb7f1f"
"88cde7c97f8a66cd66301281dac3f3a4"
"33248c75d6c2dcd708b6a97b0a3f325e"
"0b2964f8a5819e479b");
vector<uint8_t> signature = wvutil::a2b_hex(
"afa7343462bea122cc149fca70abdae7"
"9446677db5373666af7dc313015f4de7"
"86e6e394946fad3cc0e2b02bedba5047"
"fe9e2d7d099705e4a39f28683279cf0a"
"c85c1530412242c0e918953be000e939"
"cf3bf182525e199370fa7907eba69d5d"
"b4631017c0e36df70379b5db8d4c695a"
"979a8e6173224065d7dc15132ef28cd8"
"22795163063b54c651141be86d36e367"
"35bc61f31fca574e5309f3a3bbdf91ef"
"f12b99e9cc1744f1ee9a1bd22c5bad96"
"ad481929251f0343fd36bcf0acde7f11"
"e5ad60977721202796fe061f9ada1fc4"
"c8e00d6022a8357585ffe9fdd59331a2"
"8c4aa3121588fb6cf68396d8ac054659"
"9500c9708500a5972bd54f72cf8db0c8");
TestSignature(kSign_PKCS1_Block1, message, signature);
}
// # PKCS#1 v1.5 Signature Example 15.3
TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_3) {
BuildRSAKey();
LoadWithAllowedSchemes(kSign_PKCS1_Block1, true);
vector<uint8_t> message = wvutil::a2b_hex(
"d02371ad7ee48bbfdb2763de7a843b94"
"08ce5eb5abf847ca3d735986df84e906"
"0bdbcdd3a55ba55dde20d4761e1a21d2"
"25c1a186f4ac4b3019d3adf78fe63346"
"67f56f70c901a0a2700c6f0d56add719"
"592dc88f6d2306c7009f6e7a635b4cb3"
"a502dfe68ddc58d03be10a1170004fe7"
"4dd3e46b82591ff75414f0c4a03e605e"
"20524f2416f12eca589f111b75d639c6"
"1baa80cafd05cf3500244a219ed9ced9"
"f0b10297182b653b526f400f2953ba21"
"4d5bcd47884132872ae90d4d6b1f4215"
"39f9f34662a56dc0e7b4b923b6231e30"
"d2676797817f7c337b5ac824ba93143b"
"3381fa3dce0e6aebd38e67735187b1eb"
"d95c02");
vector<uint8_t> signature = wvutil::a2b_hex(
"3bac63f86e3b70271203106b9c79aabd"
"9f477c56e4ee58a4fce5baf2cab4960f"
"88391c9c23698be75c99aedf9e1abf17"
"05be1dac33140adb48eb31f450bb9efe"
"83b7b90db7f1576d33f40c1cba4b8d6b"
"1d3323564b0f1774114fa7c08e6d1e20"
"dd8fbba9b6ac7ad41e26b4568f4a8aac"
"bfd178a8f8d2c9d5f5b88112935a8bc9"
"ae32cda40b8d20375510735096536818"
"ce2b2db71a9772c9b0dda09ae10152fa"
"11466218d091b53d92543061b7294a55"
"be82ff35d5c32fa233f05aaac7585030"
"7ecf81383c111674397b1a1b9d3bf761"
"2ccbe5bacd2b38f0a98397b24c83658f"
"b6c0b4140ef11970c4630d44344e76ea"
"ed74dcbee811dbf6575941f08a6523b8");
TestSignature(kSign_PKCS1_Block1, message, signature);
};
// # PKCS#1 v1.5 Signature Example 15.4
TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_4) {
BuildRSAKey();
LoadWithAllowedSchemes(kSign_PKCS1_Block1, true);
vector<uint8_t> message = wvutil::a2b_hex(
"29035584ab7e0226a9ec4b02e8dcf127"
"2dc9a41d73e2820007b0f6e21feccd5b"
"d9dbb9ef88cd6758769ee1f956da7ad1"
"8441de6fab8386dbc693");
vector<uint8_t> signature = wvutil::a2b_hex(
"28d8e3fcd5dddb21ffbd8df1630d7377"
"aa2651e14cad1c0e43ccc52f907f946d"
"66de7254e27a6c190eb022ee89ecf622"
"4b097b71068cd60728a1aed64b80e545"
"7bd3106dd91706c937c9795f2b36367f"
"f153dc2519a8db9bdf2c807430c451de"
"17bbcd0ce782b3e8f1024d90624dea7f"
"1eedc7420b7e7caa6577cef43141a726"
"4206580e44a167df5e41eea0e69a8054"
"54c40eefc13f48e423d7a32d02ed42c0"
"ab03d0a7cf70c5860ac92e03ee005b60"
"ff3503424b98cc894568c7c56a023355"
"1cebe588cf8b0167b7df13adcad82867"
"6810499c704da7ae23414d69e3c0d2db"
"5dcbc2613bc120421f9e3653c5a87672"
"97643c7e0740de016355453d6c95ae72");
TestSignature(kSign_PKCS1_Block1, message, signature);
}
// # PKCS#1 v1.5 Signature Example 15.5
TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_5) {
BuildRSAKey();
LoadWithAllowedSchemes(kSign_PKCS1_Block1, true);
vector<uint8_t> message = wvutil::a2b_hex("bda3a1c79059eae598308d3df609");
vector<uint8_t> signature = wvutil::a2b_hex(
"a156176cb96777c7fb96105dbd913bc4"
"f74054f6807c6008a1a956ea92c1f81c"
"b897dc4b92ef9f4e40668dc7c556901a"
"cb6cf269fe615b0fb72b30a513386923"
"14b0e5878a88c2c7774bd16939b5abd8"
"2b4429d67bd7ac8e5ea7fe924e20a6ec"
"662291f2548d734f6634868b039aa5f9"
"d4d906b2d0cb8585bf428547afc91c6e"
"2052ddcd001c3ef8c8eefc3b6b2a82b6"
"f9c88c56f2e2c3cb0be4b80da95eba37"
"1d8b5f60f92538743ddbb5da2972c71f"
"e7b9f1b790268a0e770fc5eb4d5dd852"
"47d48ae2ec3f26255a3985520206a1f2"
"68e483e9dbb1d5cab190917606de31e7"
"c5182d8f151bf41dfeccaed7cde690b2"
"1647106b490c729d54a8fe2802a6d126");
TestSignature(kSign_PKCS1_Block1, message, signature);
}
// # PKCS#1 v1.5 Signature Example 15.6
TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_6) {
BuildRSAKey();
LoadWithAllowedSchemes(kSign_PKCS1_Block1, true);
vector<uint8_t> message = wvutil::a2b_hex(
"c187915e4e87da81c08ed4356a0cceac"
"1c4fb5c046b45281b387ec28f1abfd56"
"7e546b236b37d01ae71d3b2834365d3d"
"f380b75061b736b0130b070be58ae8a4"
"6d12166361b613dbc47dfaeb4ca74645"
"6c2e888385525cca9dd1c3c7a9ada76d"
"6c");
vector<uint8_t> signature = wvutil::a2b_hex(
"9cab74163608669f7555a333cf196fe3"
"a0e9e5eb1a32d34bb5c85ff689aaab0e"
"3e65668ed3b1153f94eb3d8be379b8ee"
"f007c4a02c7071ce30d8bb341e58c620"
"f73d37b4ecbf48be294f6c9e0ecb5e63"
"fec41f120e5553dfa0ebebbb72640a95"
"37badcb451330229d9f710f62e3ed8ec"
"784e50ee1d9262b42671340011d7d098"
"c6f2557b2131fa9bd0254636597e88ec"
"b35a240ef0fd85957124df8080fee1e1"
"49af939989e86b26c85a5881fae8673d"
"9fd40800dd134eb9bdb6410f420b0aa9"
"7b20efcf2eb0c807faeb83a3ccd9b51d"
"4553e41dfc0df6ca80a1e81dc234bb83"
"89dd195a38b42de4edc49d346478b9f1"
"1f0557205f5b0bd7ffe9c850f396d7c4");
TestSignature(kSign_PKCS1_Block1, message, signature);
}
// # PKCS#1 v1.5 Signature Example 15.7
TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_7) {
BuildRSAKey();
LoadWithAllowedSchemes(kSign_PKCS1_Block1, true);
vector<uint8_t> message = wvutil::a2b_hex(
"abfa2ecb7d29bd5bcb9931ce2bad2f74"
"383e95683cee11022f08e8e7d0b8fa05"
"8bf9eb7eb5f98868b5bb1fb5c31ceda3"
"a64f1a12cdf20fcd0e5a246d7a1773d8"
"dba0e3b277545babe58f2b96e3f4edc1"
"8eabf5cd2a560fca75fe96e07d859def"
"b2564f3a34f16f11e91b3a717b41af53"
"f6605323001aa406c6");
vector<uint8_t> signature = wvutil::a2b_hex(
"c4b437bcf703f352e1faf74eb9622039"
"426b5672caf2a7b381c6c4f0191e7e4a"
"98f0eebcd6f41784c2537ff0f99e7498"
"2c87201bfbc65eae832db71d16dacadb"
"0977e5c504679e40be0f9db06ffd848d"
"d2e5c38a7ec021e7f68c47dfd38cc354"
"493d5339b4595a5bf31e3f8f13816807"
"373df6ad0dc7e731e51ad19eb4754b13"
"4485842fe709d378444d8e36b1724a4f"
"da21cafee653ab80747f7952ee804dea"
"b1039d84139945bbf4be82008753f3c5"
"4c7821a1d241f42179c794ef7042bbf9"
"955656222e45c34369a384697b6ae742"
"e18fa5ca7abad27d9fe71052e3310d0f"
"52c8d12ea33bf053a300f4afc4f098df"
"4e6d886779d64594d369158fdbc1f694");
TestSignature(kSign_PKCS1_Block1, message, signature);
}
// # PKCS#1 v1.5 Signature Example 15.8
TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_8) {
BuildRSAKey();
LoadWithAllowedSchemes(kSign_PKCS1_Block1, true);
vector<uint8_t> message = wvutil::a2b_hex(
"df4044a89a83e9fcbf1262540ae3038b"
"bc90f2b2628bf2a4467ac67722d8546b"
"3a71cb0ea41669d5b4d61859c1b4e47c"
"ecc5933f757ec86db0644e311812d00f"
"b802f03400639c0e364dae5aebc5791b"
"c655762361bc43c53d3c7886768f7968"
"c1c544c6f79f7be820c7e2bd2f9d73e6"
"2ded6d2e937e6a6daef90ee37a1a52a5"
"4f00e31addd64894cf4c02e16099e29f"
"9eb7f1a7bb7f84c47a2b594813be02a1"
"7b7fc43b34c22c91925264126c89f86b"
"b4d87f3ef131296c53a308e0331dac8b"
"af3b63422266ecef2b90781535dbda41"
"cbd0cf22a8cbfb532ec68fc6afb2ac06");
vector<uint8_t> signature = wvutil::a2b_hex(
"1414b38567ae6d973ede4a06842dcc0e"
"0559b19e65a4889bdbabd0fd02806829"
"13bacd5dc2f01b30bb19eb810b7d9ded"
"32b284f147bbe771c930c6052aa73413"
"90a849f81da9cd11e5eccf246dbae95f"
"a95828e9ae0ca3550325326deef9f495"
"30ba441bed4ac29c029c9a2736b1a419"
"0b85084ad150426b46d7f85bd702f48d"
"ac5f71330bc423a766c65cc1dcab20d3"
"d3bba72b63b3ef8244d42f157cb7e3a8"
"ba5c05272c64cc1ad21a13493c3911f6"
"0b4e9f4ecc9900eb056ee59d6fe4b8ff"
"6e8048ccc0f38f2836fd3dfe91bf4a38"
"6e1ecc2c32839f0ca4d1b27a568fa940"
"dd64ad16bd0125d0348e383085f08894"
"861ca18987227d37b42b584a8357cb04");
TestSignature(kSign_PKCS1_Block1, message, signature);
}
// # PKCS#1 v1.5 Signature Example 15.9
TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_9) {
BuildRSAKey();
LoadWithAllowedSchemes(kSign_PKCS1_Block1, true);
vector<uint8_t> message = wvutil::a2b_hex(
"ea941ff06f86c226927fcf0e3b11b087"
"2676170c1bfc33bda8e265c77771f9d0"
"850164a5eecbcc5ce827fbfa07c85214"
"796d8127e8caa81894ea61ceb1449e72"
"fea0a4c943b2da6d9b105fe053b9039a"
"9cc53d420b7539fab2239c6b51d17e69"
"4c957d4b0f0984461879a0759c4401be"
"ecd4c606a0afbd7a076f50a2dfc2807f"
"24f1919baa7746d3a64e268ed3f5f8e6"
"da83a2a5c9152f837cb07812bd5ba7d3"
"a07985de88113c1796e9b466ec299c5a"
"c1059e27f09415");
vector<uint8_t> signature = wvutil::a2b_hex(
"ceeb84ccb4e9099265650721eea0e8ec"
"89ca25bd354d4f64564967be9d4b08b3"
"f1c018539c9d371cf8961f2291fbe0dc"
"2f2f95fea47b639f1e12f4bc381cef0c"
"2b7a7b95c3adf27605b7f63998c3cbad"
"542808c3822e064d4ad14093679e6e01"
"418a6d5c059684cd56e34ed65ab605b8"
"de4fcfa640474a54a8251bbb7326a42d"
"08585cfcfc956769b15b6d7fdf7da84f"
"81976eaa41d692380ff10eaecfe0a579"
"682909b5521fade854d797b8a0345b9a"
"864e0588f6caddbf65f177998e180d1f"
"102443e6dca53a94823caa9c3b35f322"
"583c703af67476159ec7ec93d1769b30"
"0af0e7157dc298c6cd2dee2262f8cddc"
"10f11e01741471bbfd6518a175734575");
TestSignature(kSign_PKCS1_Block1, message, signature);
}
// # PKCS#1 v1.5 Signature Example 15.10
TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_10) {
BuildRSAKey();
LoadWithAllowedSchemes(kSign_PKCS1_Block1, true);
vector<uint8_t> message = wvutil::a2b_hex(
"d8b81645c13cd7ecf5d00ed2c91b9acd"
"46c15568e5303c4a9775ede76b48403d"
"6be56c05b6b1cf77c6e75de096c5cb35"
"51cb6fa964f3c879cf589d28e1da2f9d"
"ec");
vector<uint8_t> signature = wvutil::a2b_hex(
"2745074ca97175d992e2b44791c323c5"
"7167165cdd8da579cdef4686b9bb404b"
"d36a56504eb1fd770f60bfa188a7b24b"
"0c91e881c24e35b04dc4dd4ce38566bc"
"c9ce54f49a175fc9d0b22522d9579047"
"f9ed42eca83f764a10163997947e7d2b"
"52ff08980e7e7c2257937b23f3d279d4"
"cd17d6f495546373d983d536efd7d1b6"
"7181ca2cb50ac616c5c7abfbb9260b91"
"b1a38e47242001ff452f8de10ca6eaea"
"dcaf9edc28956f28a711291fc9a80878"
"b8ba4cfe25b8281cb80bc9cd6d2bd182"
"5246eebe252d9957ef93707352084e6d"
"36d423551bf266a85340fb4a6af37088"
"0aab07153d01f48d086df0bfbec05e7b"
"443b97e71718970e2f4bf62023e95b67");
TestSignature(kSign_PKCS1_Block1, message, signature);
}
// # PKCS#1 v1.5 Signature Example 15.11
TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_11) {
BuildRSAKey();
LoadWithAllowedSchemes(kSign_PKCS1_Block1, true);
vector<uint8_t> message = wvutil::a2b_hex(
"e5739b6c14c92d510d95b826933337ff"
"0d24ef721ac4ef64c2bad264be8b44ef"
"a1516e08a27eb6b611d3301df0062dae"
"fc73a8c0d92e2c521facbc7b26473876"
"7ea6fc97d588a0baf6ce50adf79e600b"
"d29e345fcb1dba71ac5c0289023fe4a8"
"2b46a5407719197d2e958e3531fd54ae"
"f903aabb4355f88318994ed3c3dd62f4"
"20a7");
vector<uint8_t> signature = wvutil::a2b_hex(
"be40a5fb94f113e1b3eff6b6a33986f2"
"02e363f07483b792e68dfa5554df0466"
"cc32150950783b4d968b639a04fd2fb9"
"7f6eb967021f5adccb9fca95acc8f2cd"
"885a380b0a4e82bc760764dbab88c1e6"
"c0255caa94f232199d6f597cc9145b00"
"e3d4ba346b559a8833ad1516ad5163f0"
"16af6a59831c82ea13c8224d84d0765a"
"9d12384da460a8531b4c407e04f4f350"
"709eb9f08f5b220ffb45abf6b75d1579"
"fd3f1eb55fc75b00af8ba3b087827fe9"
"ae9fb4f6c5fa63031fe582852fe2834f"
"9c89bff53e2552216bc7c1d4a3d5dc2b"
"a6955cd9b17d1363e7fee8ed7629753f"
"f3125edd48521ae3b9b03217f4496d0d"
"8ede57acbc5bd4deae74a56f86671de2");
TestSignature(kSign_PKCS1_Block1, message, signature);
}
// # PKCS#1 v1.5 Signature Example 15.12
TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_12) {
BuildRSAKey();
LoadWithAllowedSchemes(kSign_PKCS1_Block1, true);
vector<uint8_t> message = wvutil::a2b_hex(
"7af42835917a88d6b3c6716ba2f5b0d5"
"b20bd4e2e6e574e06af1eef7c81131be"
"22bf8128b9cbc6ec00275ba80294a5d1"
"172d0824a79e8fdd830183e4c00b9678"
"2867b1227fea249aad32ffc5fe007bc5"
"1f21792f728deda8b5708aa99cabab20"
"a4aa783ed86f0f27b5d563f42e07158c"
"ea72d097aa6887ec411dd012912a5e03"
"2bbfa678507144bcc95f39b58be7bfd1"
"759adb9a91fa1d6d8226a8343a8b849d"
"ae76f7b98224d59e28f781f13ece605f"
"84f6c90bae5f8cf378816f4020a7dda1"
"bed90c92a23634d203fac3fcd86d68d3"
"182a7d9ccabe7b0795f5c655e9acc4e3"
"ec185140d10cef053464ab175c83bd83"
"935e3dabaf3462eebe63d15f573d269a");
vector<uint8_t> signature = wvutil::a2b_hex(
"4e78c5902b807914d12fa537ae6871c8"
"6db8021e55d1adb8eb0ccf1b8f36ab7d"
"ad1f682e947a627072f03e627371781d"
"33221d174abe460dbd88560c22f69011"
"6e2fbbe6e964363a3e5283bb5d946ef1"
"c0047eba038c756c40be7923055809b0"
"e9f34a03a58815ebdde767931f018f6f"
"1878f2ef4f47dd374051dd48685ded6e"
"fb3ea8021f44be1d7d149398f98ea9c0"
"8d62888ebb56192d17747b6b8e170954"
"31f125a8a8e9962aa31c285264e08fb2"
"1aac336ce6c38aa375e42bc92ab0ab91"
"038431e1f92c39d2af5ded7e43bc151e"
"6ebea4c3e2583af3437e82c43c5e3b5b"
"07cf0359683d2298e35948ed806c063c"
"606ea178150b1efc15856934c7255cfe");
TestSignature(kSign_PKCS1_Block1, message, signature);
}
// # PKCS#1 v1.5 Signature Example 15.13
TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_13) {
BuildRSAKey();
LoadWithAllowedSchemes(kSign_PKCS1_Block1, true);
vector<uint8_t> message = wvutil::a2b_hex(
"ebaef3f9f23bdfe5fa6b8af4c208c189"
"f2251bf32f5f137b9de4406378686b3f"
"0721f62d24cb8688d6fc41a27cbae21d"
"30e429feacc7111941c277");
vector<uint8_t> signature = wvutil::a2b_hex(
"c48dbef507114f03c95fafbeb4df1bfa"
"88e0184a33cc4f8a9a1035ff7f822a5e"
"38cda18723915ff078244429e0f6081c"
"14fd83331fa65c6ba7bb9a12dbf66223"
"74cd0ca57de3774e2bd7ae823677d061"
"d53ae9c4040d2da7ef7014f3bbdc95a3"
"61a43855c8ce9b97ecabce174d926285"
"142b534a3087f9f4ef74511ec742b0d5"
"685603faf403b5072b985df46adf2d25"
"29a02d40711e2190917052371b79b749"
"b83abf0ae29486c3f2f62477b2bd362b"
"039c013c0c5076ef520dbb405f42cee9"
"5425c373a975e1cdd032c49622c85079"
"b09e88dab2b13969ef7a723973781040"
"459f57d5013638483de2d91cb3c490da"
"81c46de6cd76ea8a0c8f6fe331712d24");
TestSignature(kSign_PKCS1_Block1, message, signature);
}
// # PKCS#1 v1.5 Signature Example 15.14
TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_14) {
BuildRSAKey();
LoadWithAllowedSchemes(kSign_PKCS1_Block1, true);
vector<uint8_t> message = wvutil::a2b_hex(
"c5a2711278761dfcdd4f0c99e6f5619d"
"6c48b5d4c1a80982faa6b4cf1cf7a60f"
"f327abef93c801429efde08640858146"
"1056acc33f3d04f5ada21216cacd5fd1"
"f9ed83203e0e2fe6138e3eae8424e591"
"5a083f3f7ab76052c8be55ae882d6ec1"
"482b1e45c5dae9f41015405327022ec3"
"2f0ea2429763b255043b1958ee3cf6d6"
"3983596eb385844f8528cc9a9865835d"
"c5113c02b80d0fca68aa25e72bcaaeb3"
"cf9d79d84f984fd417");
vector<uint8_t> signature = wvutil::a2b_hex(
"6bd5257aa06611fb4660087cb4bc4a9e"
"449159d31652bd980844daf3b1c7b353"
"f8e56142f7ea9857433b18573b4deede"
"818a93b0290297783f1a2f23cbc72797"
"a672537f01f62484cd4162c3214b9ac6"
"28224c5de01f32bb9b76b27354f2b151"
"d0e8c4213e4615ad0bc71f515e300d6a"
"64c6743411fffde8e5ff190e54923043"
"126ecfc4c4539022668fb675f25c07e2"
"0099ee315b98d6afec4b1a9a93dc3349"
"6a15bd6fde1663a7d49b9f1e639d3866"
"4b37a010b1f35e658682d9cd63e57de0"
"f15e8bdd096558f07ec0caa218a8c06f"
"4788453940287c9d34b6d40a3f09bf77"
"99fe98ae4eb49f3ff41c5040a50cefc9"
"bdf2394b749cf164480df1ab6880273b");
TestSignature(kSign_PKCS1_Block1, message, signature);
}
// # PKCS#1 v1.5 Signature Example 15.15
TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_15) {
BuildRSAKey();
LoadWithAllowedSchemes(kSign_PKCS1_Block1, true);
vector<uint8_t> message = wvutil::a2b_hex(
"9bf8aa253b872ea77a7e23476be26b23"
"29578cf6ac9ea2805b357f6fc3ad130d"
"baeb3d869a13cce7a808bbbbc969857e"
"03945c7bb61df1b5c2589b8e046c2a5d"
"7e4057b1a74f24c711216364288529ec"
"9570f25197213be1f5c2e596f8bf8b2c"
"f3cb38aa56ffe5e31df7395820e94ecf"
"3b1189a965dcf9a9cb4298d3c88b2923"
"c19fc6bc34aacecad4e0931a7c4e5d73"
"dc86dfa798a8476d82463eefaa90a8a9"
"192ab08b23088dd58e1280f7d72e4548"
"396baac112252dd5c5346adb2004a2f7"
"101ccc899cc7fafae8bbe295738896a5"
"b2012285014ef6");
vector<uint8_t> signature = wvutil::a2b_hex(
"27f7f4da9bd610106ef57d32383a448a"
"8a6245c83dc1309c6d770d357ba89e73"
"f2ad0832062eb0fe0ac915575bcd6b8b"
"cadb4e2ba6fa9da73a59175152b2d4fe"
"72b070c9b7379e50000e55e6c269f665"
"8c937972797d3add69f130e34b85bdec"
"9f3a9b392202d6f3e430d09caca82277"
"59ab825f7012d2ff4b5b62c8504dbad8"
"55c05edd5cab5a4cccdc67f01dd6517c"
"7d41c43e2a4957aff19db6f18b17859a"
"f0bc84ab67146ec1a4a60a17d7e05f8b"
"4f9ced6ad10908d8d78f7fc88b76adc8"
"290f87daf2a7be10ae408521395d54ed"
"2556fb7661854a730ce3d82c71a8d493"
"ec49a378ac8a3c74439f7cc555ba13f8"
"59070890ee18ff658fa4d741969d70a5");
TestSignature(kSign_PKCS1_Block1, message, signature);
}
// # PKCS#1 v1.5 Signature Example 15.16
TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_16) {
BuildRSAKey();
LoadWithAllowedSchemes(kSign_PKCS1_Block1, true);
vector<uint8_t> message = wvutil::a2b_hex(
"32474830e2203754c8bf0681dc4f842a"
"fe360930378616c108e833656e5640c8"
"6856885bb05d1eb9438efede679263de"
"07cb39553f6a25e006b0a52311a063ca"
"088266d2564ff6490c46b5609818548f"
"88764dad34a25e3a85d575023f0b9e66"
"5048a03c350579a9d32446c7bb96cc92"
"e065ab94d3c8952e8df68ef0d9fa456b"
"3a06bb80e3bbc4b28e6a94b6d0ff7696"
"a64efe05e735fea025d7bdbc4139f3a3"
"b546075cba7efa947374d3f0ac80a68d"
"765f5df6210bca069a2d88647af7ea04"
"2dac690cb57378ec0777614fb8b65ff4"
"53ca6b7dce6098451a2f8c0da9bfecf1"
"fdf391bbaa4e2a91ca18a1121a7523a2"
"abd42514f489e8");
vector<uint8_t> signature = wvutil::a2b_hex(
"6917437257c22ccb5403290c3dee82d9"
"cf7550b31bd31c51bd57bfd35d452ab4"
"db7c4be6b2e25ac9a59a1d2a7feb627f"
"0afd4976b3003cc9cffd8896505ec382"
"f265104d4cf8c932fa9fe86e00870795"
"9912389da4b2d6b369b36a5e72e29d24"
"c9a98c9d31a3ab44e643e6941266a47a"
"45e3446ce8776abe241a8f5fc6423b24"
"b1ff250dc2c3a8172353561077e850a7"
"69b25f0325dac88965a3b9b472c494e9"
"5f719b4eac332caa7a65c7dfe46d9aa7"
"e6e00f525f303dd63ab7919218901868"
"f9337f8cd26aafe6f33b7fb2c98810af"
"19f7fcb282ba1577912c1d368975fd5d"
"440b86e10c199715fa0b6f4250b53373"
"2d0befe1545150fc47b876de09b00a94");
TestSignature(kSign_PKCS1_Block1, message, signature);
}
// # PKCS#1 v1.5 Signature Example 15.17
TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_17) {
BuildRSAKey();
LoadWithAllowedSchemes(kSign_PKCS1_Block1, true);
vector<uint8_t> message = wvutil::a2b_hex(
"008e59505eafb550aae5e845584cebb0"
"0b6de1733e9f95d42c882a5bbeb5ce1c"
"57e119e7c0d4daca9f1ff7870217f7cf"
"d8a6b373977cac9cab8e71e420");
vector<uint8_t> signature = wvutil::a2b_hex(
"922503b673ee5f3e691e1ca85e9ff417"
"3cf72b05ac2c131da5603593e3bc259c"
"94c1f7d3a06a5b9891bf113fa39e59ff"
"7c1ed6465e908049cb89e4e125cd37d2"
"ffd9227a41b4a0a19c0a44fbbf3de55b"
"ab802087a3bb8d4ff668ee6bbb8ad89e"
"6857a79a9c72781990dfcf92cd519404"
"c950f13d1143c3184f1d250c90e17ac6"
"ce36163b9895627ad6ffec1422441f55"
"e4499dba9be89546ae8bc63cca01dd08"
"463ae7f1fce3d893996938778c1812e6"
"74ad9c309c5acca3fde44e7dd8695993"
"e9c1fa87acda99ece5c8499e468957ad"
"66359bf12a51adbe78d3a213b449bf0b"
"5f8d4d496acf03d3033b7ccd196bc22f"
"68fb7bef4f697c5ea2b35062f48a36dd");
TestSignature(kSign_PKCS1_Block1, message, signature);
}
// # PKCS#1 v1.5 Signature Example 15.18
TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_18) {
BuildRSAKey();
LoadWithAllowedSchemes(kSign_PKCS1_Block1, true);
vector<uint8_t> message = wvutil::a2b_hex(
"6abc54cf8d1dff1f53b17d8160368878"
"a8788cc6d22fa5c2258c88e660b09a89"
"33f9f2c0504ddadc21f6e75e0b833beb"
"555229dee656b9047b92f62e76b8ffcc"
"60dab06b80");
vector<uint8_t> signature = wvutil::a2b_hex(
"0b6daf42f7a862147e417493c2c401ef"
"ae32636ab4cbd44192bbf5f195b50ae0"
"96a475a1614f0a9fa8f7a026cb46c650"
"6e518e33d83e56477a875aca8c7e714c"
"e1bdbd61ef5d535239b33f2bfdd61771"
"bab62776d78171a1423cea8731f82e60"
"766d6454265620b15f5c5a584f55f95b"
"802fe78c574ed5dacfc831f3cf2b0502"
"c0b298f25ccf11f973b31f85e4744219"
"85f3cff702df3946ef0a6605682111b2"
"f55b1f8ab0d2ea3a683c69985ead93ed"
"449ea48f0358ddf70802cb41de2fd83f"
"3c808082d84936948e0c84a131b49278"
"27460527bb5cd24bfab7b48e071b2417"
"1930f99763272f9797bcb76f1d248157"
"5558fcf260b1f0e554ebb3df3cfcb958");
TestSignature(kSign_PKCS1_Block1, message, signature);
}
// # PKCS#1 v1.5 Signature Example 15.19
TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_19) {
BuildRSAKey();
LoadWithAllowedSchemes(kSign_PKCS1_Block1, true);
vector<uint8_t> message = wvutil::a2b_hex(
"af2d78152cf10efe01d274f217b177f6"
"b01b5e749f1567715da324859cd3dd88"
"db848ec79f48dbba7b6f1d33111ef31b"
"64899e7391c2bffd69f49025cf201fc5"
"85dbd1542c1c778a2ce7a7ee108a309f"
"eca26d133a5ffedc4e869dcd7656596a"
"c8427ea3ef6e3fd78fe99d8ddc71d839"
"f6786e0da6e786bd62b3a4f19b891a56"
"157a554ec2a2b39e25a1d7c7d37321c7"
"a1d946cf4fbe758d9276f08563449d67"
"414a2c030f4251cfe2213d04a5410637"
"87");
vector<uint8_t> signature = wvutil::a2b_hex(
"209c61157857387b71e24bf3dd564145"
"50503bec180ff53bdd9bac062a2d4995"
"09bf991281b79527df9136615b7a6d9d"
"b3a103b535e0202a2caca197a7b74e53"
"56f3dd595b49acfd9d30049a98ca88f6"
"25bca1d5f22a392d8a749efb6eed9b78"
"21d3110ac0d244199ecb4aa3d735a83a"
"2e8893c6bf8581383ccaee834635b7fa"
"1faffa45b13d15c1da33af71e89303d6"
"8090ff62ee615fdf5a84d120711da53c"
"2889198ab38317a9734ab27d67924cea"
"74156ff99bef9876bb5c339e93745283"
"e1b34e072226b88045e017e9f05b2a8c"
"416740258e223b2690027491732273f3"
"229d9ef2b1b3807e321018920ad3e53d"
"ae47e6d9395c184b93a374c671faa2ce");
TestSignature(kSign_PKCS1_Block1, message, signature);
}
// # PKCS#1 v1.5 Signature Example 15.20
TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_20) {
BuildRSAKey();
LoadWithAllowedSchemes(kSign_PKCS1_Block1, true);
vector<uint8_t> message = wvutil::a2b_hex(
"40ee992458d6f61486d25676a96dd2cb"
"93a37f04b178482f2b186cf88215270d"
"ba29d786d774b0c5e78c7f6e56a956e7"
"f73950a2b0c0c10a08dbcd67e5b210bb"
"21c58e2767d44f7dd4014e3966143bf7"
"e3d66ff0c09be4c55f93b39994b8518d"
"9c1d76d5b47374dea08f157d57d70634"
"978f3856e0e5b481afbbdb5a3ac48d48"
"4be92c93de229178354c2de526e9c65a"
"31ede1ef68cb6398d7911684fec0babc"
"3a781a66660783506974d0e14825101c"
"3bfaea");
vector<uint8_t> signature = wvutil::a2b_hex(
"927502b824afc42513ca6570de338b8a"
"64c3a85eb828d3193624f27e8b1029c5"
"5c119c9733b18f5849b3500918bcc005"
"51d9a8fdf53a97749fa8dc480d6fe974"
"2a5871f973926528972a1af49e3925b0"
"adf14a842719b4a5a2d89fa9c0b6605d"
"212bed1e6723b93406ad30e86829a5c7"
"19b890b389306dc5506486ee2f36a8df"
"e0a96af678c9cbd6aff397ca200e3edc"
"1e36bd2f08b31d540c0cb282a9559e4a"
"dd4fc9e6492eed0ccbd3a6982e5faa2d"
"dd17be47417c80b4e5452d31f72401a0"
"42325109544d954c01939079d409a5c3"
"78d7512dfc2d2a71efcc3432a765d1c6"
"a52cfce899cd79b15b4fc3723641ef6b"
"d00acc10407e5df58dd1c3c5c559a506");
TestSignature(kSign_PKCS1_Block1, message, signature);
}
/// @}
/// @addtogroup generic
/// @{
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyLoad) { EncryptAndLoadKeys(); }
// Test that the Generic_Encrypt function works correctly.
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyEncrypt) {
EncryptAndLoadKeys();
unsigned int key_index = 0;
vector<uint8_t> expected_encrypted;
EncryptBuffer(key_index, clear_buffer_, &expected_encrypted);
vector<uint8_t> key_handle;
ASSERT_EQ(
OEMCrypto_SUCCESS,
GetKeyHandleIntoVector(session_.session_id(),
session_.license().keys[key_index].key_id,
session_.license().keys[key_index].key_id_length,
OEMCrypto_CipherMode_CENC, key_handle));
vector<uint8_t> encrypted(clear_buffer_.size());
ASSERT_EQ(OEMCrypto_SUCCESS,
GenericEncrypt(key_handle.data(), key_handle.size(),
clear_buffer_.data(), clear_buffer_.size(), iv_,
OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data()));
ASSERT_EQ(expected_encrypted, encrypted);
}
// Test that the Generic_Encrypt function fails when not allowed.
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyBadEncrypt) {
EncryptAndLoadKeys();
BadEncrypt(0, OEMCrypto_HMAC_SHA256, buffer_size_);
// The buffer size must be a multiple of 16, so subtracting 10 is bad.
BadEncrypt(0, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_ - 10);
BadEncrypt(1, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_);
BadEncrypt(2, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_);
BadEncrypt(3, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_);
}
// Test that the Generic_Encrypt works if the input and output buffers are the
// same.
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyEncryptSameBufferAPI12) {
EncryptAndLoadKeys();
unsigned int key_index = 0;
vector<uint8_t> expected_encrypted;
EncryptBuffer(key_index, clear_buffer_, &expected_encrypted);
vector<uint8_t> key_handle;
ASSERT_EQ(
OEMCrypto_SUCCESS,
GetKeyHandleIntoVector(session_.session_id(),
session_.license().keys[key_index].key_id,
session_.license().keys[key_index].key_id_length,
OEMCrypto_CipherMode_CENC, key_handle));
// Input and output are same buffer:
vector<uint8_t> buffer = clear_buffer_;
ASSERT_EQ(OEMCrypto_SUCCESS,
GenericEncrypt(key_handle.data(), key_handle.size(), buffer.data(),
buffer.size(), iv_, OEMCrypto_AES_CBC_128_NO_PADDING,
buffer.data()));
ASSERT_EQ(expected_encrypted, buffer);
}
TEST_P(
OEMCryptoGenericCryptoTest,
OEMCryptoMemoryGenericKeyEncryptForHugeBufferWithBufferLengthNotMultipleOf16) {
EncryptAndLoadKeys();
unsigned int key_index = 0;
vector<uint8_t> expected_encrypted;
vector<uint8_t> key_handle;
ASSERT_EQ(
OEMCrypto_SUCCESS,
GetKeyHandleIntoVector(session_.session_id(),
session_.license().keys[key_index].key_id,
session_.license().keys[key_index].key_id_length,
OEMCrypto_CipherMode_CENC, key_handle));
vector<uint8_t> buffer(17);
ASSERT_NO_FATAL_FAILURE(OEMCrypto_Generic_Encrypt(
key_handle.data(), key_handle.size(), buffer.data(), buffer.size(), iv_,
OEMCrypto_AES_CBC_128_NO_PADDING, buffer.data()));
}
// Test Generic_Decrypt works correctly.
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyDecrypt) {
EncryptAndLoadKeys();
unsigned int key_index = 1;
vector<uint8_t> encrypted;
EncryptBuffer(key_index, clear_buffer_, &encrypted);
vector<uint8_t> key_handle;
ASSERT_EQ(
OEMCrypto_SUCCESS,
GetKeyHandleIntoVector(session_.session_id(),
session_.license().keys[key_index].key_id,
session_.license().keys[key_index].key_id_length,
OEMCrypto_CipherMode_CENC, key_handle));
vector<uint8_t> resultant(encrypted.size());
ASSERT_EQ(OEMCrypto_SUCCESS,
GenericDecrypt(key_handle.data(), key_handle.size(),
encrypted.data(), encrypted.size(), iv_,
OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data()));
ASSERT_EQ(clear_buffer_, resultant);
}
// Test that Generic_Decrypt works correctly when the input and output buffers
// are the same.
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyDecryptSameBufferAPI12) {
EncryptAndLoadKeys();
unsigned int key_index = 1;
vector<uint8_t> encrypted;
EncryptBuffer(key_index, clear_buffer_, &encrypted);
vector<uint8_t> key_handle;
ASSERT_EQ(
OEMCrypto_SUCCESS,
GetKeyHandleIntoVector(session_.session_id(),
session_.license().keys[key_index].key_id,
session_.license().keys[key_index].key_id_length,
OEMCrypto_CipherMode_CENC, key_handle));
vector<uint8_t> buffer = encrypted;
ASSERT_EQ(OEMCrypto_SUCCESS,
GenericDecrypt(key_handle.data(), key_handle.size(), buffer.data(),
buffer.size(), iv_, OEMCrypto_AES_CBC_128_NO_PADDING,
buffer.data()));
ASSERT_EQ(clear_buffer_, buffer);
}
// Test that Generic_Decrypt fails to decrypt to an insecure buffer if the key
// requires a secure data path.
TEST_P(OEMCryptoGenericCryptoTest, GenericSecureToClear) {
license_messages_.set_control(wvoec::kControlObserveDataPath |
wvoec::kControlDataPathSecure);
license_messages_.CreateResponseWithGenericCryptoKeys();
EncryptAndLoadKeys();
unsigned int key_index = 1;
vector<uint8_t> encrypted;
EncryptBuffer(key_index, clear_buffer_, &encrypted);
vector<uint8_t> key_handle;
ASSERT_EQ(
OEMCrypto_SUCCESS,
GetKeyHandleIntoVector(session_.session_id(),
session_.license().keys[key_index].key_id,
session_.license().keys[key_index].key_id_length,
OEMCrypto_CipherMode_CENC, key_handle));
vector<uint8_t> resultant(encrypted.size());
ASSERT_NE(OEMCrypto_SUCCESS,
GenericDecrypt(key_handle.data(), key_handle.size(),
encrypted.data(), encrypted.size(), iv_,
OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data()));
ASSERT_NE(clear_buffer_, resultant);
}
// Test that the Generic_Decrypt function fails when not allowed.
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyBadDecrypt) {
EncryptAndLoadKeys();
BadDecrypt(1, OEMCrypto_HMAC_SHA256, buffer_size_);
// The buffer size must be a multiple of 16, so subtracting 10 is bad.
BadDecrypt(1, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_ - 10);
BadDecrypt(0, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_);
BadDecrypt(2, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_);
BadDecrypt(3, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_);
}
TEST_P(OEMCryptoGenericCryptoTest, GenericKeySign) {
EncryptAndLoadKeys();
unsigned int key_index = 2;
vector<uint8_t> expected_signature;
SignBuffer(key_index, clear_buffer_, &expected_signature);
vector<uint8_t> key_handle;
ASSERT_EQ(
OEMCrypto_SUCCESS,
GetKeyHandleIntoVector(session_.session_id(),
session_.license().keys[key_index].key_id,
session_.license().keys[key_index].key_id_length,
OEMCrypto_CipherMode_CENC, key_handle));
size_t gen_signature_length = 0;
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
GenericSign(key_handle.data(), key_handle.size(),
clear_buffer_.data(), clear_buffer_.size(),
OEMCrypto_HMAC_SHA256, nullptr, &gen_signature_length));
ASSERT_EQ(static_cast<size_t>(SHA256_DIGEST_LENGTH), gen_signature_length);
vector<uint8_t> signature(SHA256_DIGEST_LENGTH);
ASSERT_EQ(
OEMCrypto_SUCCESS,
GenericSign(key_handle.data(), key_handle.size(), clear_buffer_.data(),
clear_buffer_.size(), OEMCrypto_HMAC_SHA256, signature.data(),
&gen_signature_length));
ASSERT_EQ(expected_signature, signature);
}
// Test that the Generic_Sign function fails when not allowed.
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyBadSign) {
EncryptAndLoadKeys();
BadSign(0, OEMCrypto_HMAC_SHA256); // Can't sign with encrypt key.
BadSign(1, OEMCrypto_HMAC_SHA256); // Can't sign with decrypt key.
BadSign(3, OEMCrypto_HMAC_SHA256); // Can't sign with verify key.
BadSign(2, OEMCrypto_AES_CBC_128_NO_PADDING); // Bad signing algorithm.
}
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyVerify) {
EncryptAndLoadKeys();
unsigned int key_index = 3;
vector<uint8_t> signature;
SignBuffer(key_index, clear_buffer_, &signature);
vector<uint8_t> key_handle;
ASSERT_EQ(
OEMCrypto_SUCCESS,
GetKeyHandleIntoVector(session_.session_id(),
session_.license().keys[key_index].key_id,
session_.license().keys[key_index].key_id_length,
OEMCrypto_CipherMode_CENC, key_handle));
ASSERT_EQ(
OEMCrypto_SUCCESS,
GenericVerify(key_handle.data(), key_handle.size(), clear_buffer_.data(),
clear_buffer_.size(), OEMCrypto_HMAC_SHA256,
signature.data(), signature.size()));
}
// Test that the Generic_Verify function fails when not allowed.
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyBadVerify) {
EncryptAndLoadKeys();
BadVerify(0, OEMCrypto_HMAC_SHA256, SHA256_DIGEST_LENGTH, false);
BadVerify(1, OEMCrypto_HMAC_SHA256, SHA256_DIGEST_LENGTH, false);
BadVerify(2, OEMCrypto_HMAC_SHA256, SHA256_DIGEST_LENGTH, false);
BadVerify(3, OEMCrypto_HMAC_SHA256, SHA256_DIGEST_LENGTH, true);
BadVerify(3, OEMCrypto_HMAC_SHA256, SHA256_DIGEST_LENGTH - 1, false);
BadVerify(3, OEMCrypto_HMAC_SHA256, SHA256_DIGEST_LENGTH + 1, false);
BadVerify(3, OEMCrypto_AES_CBC_128_NO_PADDING, SHA256_DIGEST_LENGTH, false);
}
// Test Generic_Encrypt with the maximum buffer size.
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyEncryptLargeBuffer) {
ResizeBuffer(GetResourceValue(kMaxGenericBuffer));
EncryptAndLoadKeys();
unsigned int key_index = 0;
vector<uint8_t> expected_encrypted;
EncryptBuffer(key_index, clear_buffer_, &expected_encrypted);
vector<uint8_t> key_handle;
ASSERT_EQ(
OEMCrypto_SUCCESS,
GetKeyHandleIntoVector(session_.session_id(),
session_.license().keys[key_index].key_id,
session_.license().keys[key_index].key_id_length,
OEMCrypto_CipherMode_CENC, key_handle));
vector<uint8_t> encrypted(clear_buffer_.size());
ASSERT_EQ(OEMCrypto_SUCCESS,
GenericEncrypt(key_handle.data(), key_handle.size(),
clear_buffer_.data(), clear_buffer_.size(), iv_,
OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data()));
ASSERT_EQ(expected_encrypted, encrypted);
}
// Test Generic_Decrypt with the maximum buffer size.
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyDecryptLargeBuffer) {
// Some applications are known to pass in a block that is almost 400k.
ResizeBuffer(GetResourceValue(kMaxGenericBuffer));
EncryptAndLoadKeys();
unsigned int key_index = 1;
vector<uint8_t> encrypted;
EncryptBuffer(key_index, clear_buffer_, &encrypted);
vector<uint8_t> key_handle;
ASSERT_EQ(
OEMCrypto_SUCCESS,
GetKeyHandleIntoVector(session_.session_id(),
session_.license().keys[key_index].key_id,
session_.license().keys[key_index].key_id_length,
OEMCrypto_CipherMode_CENC, key_handle));
vector<uint8_t> resultant(encrypted.size());
ASSERT_EQ(OEMCrypto_SUCCESS,
GenericDecrypt(key_handle.data(), key_handle.size(),
encrypted.data(), encrypted.size(), iv_,
OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data()));
ASSERT_EQ(clear_buffer_, resultant);
}
// Test Generic_Sign with the maximum buffer size.
TEST_P(OEMCryptoGenericCryptoTest, GenericKeySignLargeBuffer) {
ResizeBuffer(GetResourceValue(kMaxGenericBuffer));
EncryptAndLoadKeys();
unsigned int key_index = 2;
vector<uint8_t> expected_signature;
SignBuffer(key_index, clear_buffer_, &expected_signature);
vector<uint8_t> key_handle;
ASSERT_EQ(
OEMCrypto_SUCCESS,
GetKeyHandleIntoVector(session_.session_id(),
session_.license().keys[key_index].key_id,
session_.license().keys[key_index].key_id_length,
OEMCrypto_CipherMode_CENC, key_handle));
size_t gen_signature_length = 0;
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
GenericSign(key_handle.data(), key_handle.size(),
clear_buffer_.data(), clear_buffer_.size(),
OEMCrypto_HMAC_SHA256, nullptr, &gen_signature_length));
ASSERT_EQ(static_cast<size_t>(SHA256_DIGEST_LENGTH), gen_signature_length);
vector<uint8_t> signature(SHA256_DIGEST_LENGTH);
ASSERT_EQ(
OEMCrypto_SUCCESS,
GenericSign(key_handle.data(), key_handle.size(), clear_buffer_.data(),
clear_buffer_.size(), OEMCrypto_HMAC_SHA256, signature.data(),
&gen_signature_length));
ASSERT_EQ(expected_signature, signature);
}
// Test Generic_Verify with the maximum buffer size.
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyVerifyLargeBuffer) {
ResizeBuffer(GetResourceValue(kMaxGenericBuffer));
EncryptAndLoadKeys();
unsigned int key_index = 3;
vector<uint8_t> signature;
SignBuffer(key_index, clear_buffer_, &signature);
vector<uint8_t> key_handle;
ASSERT_EQ(
OEMCrypto_SUCCESS,
GetKeyHandleIntoVector(session_.session_id(),
session_.license().keys[key_index].key_id,
session_.license().keys[key_index].key_id_length,
OEMCrypto_CipherMode_CENC, key_handle));
ASSERT_EQ(
OEMCrypto_SUCCESS,
GenericVerify(key_handle.data(), key_handle.size(), clear_buffer_.data(),
clear_buffer_.size(), OEMCrypto_HMAC_SHA256,
signature.data(), signature.size()));
}
// Test Generic_Encrypt when the key duration has expired.
TEST_P(OEMCryptoGenericCryptoTest, KeyDurationEncrypt) {
license_messages_.core_response()
.timer_limits.total_playback_duration_seconds = kDuration;
license_messages_.CreateResponseWithGenericCryptoKeys();
EncryptAndLoadKeys();
vector<uint8_t> expected_encrypted;
EncryptBuffer(0, clear_buffer_, &expected_encrypted);
unsigned int key_index = 0;
vector<uint8_t> encrypted(clear_buffer_.size());
vector<uint8_t> key_handle;
// Should be valid key at the start.
ASSERT_EQ(
OEMCrypto_SUCCESS,
GetKeyHandleIntoVector(session_.session_id(),
session_.license().keys[key_index].key_id,
session_.license().keys[key_index].key_id_length,
OEMCrypto_CipherMode_CENC, key_handle));
ASSERT_EQ(OEMCrypto_SUCCESS,
GenericEncrypt(key_handle.data(), key_handle.size(),
clear_buffer_.data(), clear_buffer_.size(), iv_,
OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data()));
ASSERT_EQ(expected_encrypted, encrypted);
wvutil::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key.
encrypted.assign(clear_buffer_.size(), 0);
OEMCryptoResult status = OEMCrypto_Generic_Encrypt(
key_handle.data(), key_handle.size(), clear_buffer_.data(),
clear_buffer_.size(), iv_, OEMCrypto_AES_CBC_128_NO_PADDING,
encrypted.data());
ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status);
ASSERT_NE(encrypted, expected_encrypted);
ASSERT_NO_FATAL_FAILURE(session_.TestGetKeyHandleExpired(key_index));
}
// Test Generic_Decrypt when the key duration has expired.
TEST_P(OEMCryptoGenericCryptoTest, KeyDurationDecrypt) {
license_messages_.core_response()
.timer_limits.total_playback_duration_seconds = kDuration;
license_messages_.CreateResponseWithGenericCryptoKeys();
EncryptAndLoadKeys();
// Should be valid key at the start.
unsigned int key_index = 1;
vector<uint8_t> encrypted;
EncryptBuffer(key_index, clear_buffer_, &encrypted);
vector<uint8_t> key_handle;
ASSERT_EQ(
OEMCrypto_SUCCESS,
GetKeyHandleIntoVector(session_.session_id(),
session_.license().keys[key_index].key_id,
session_.license().keys[key_index].key_id_length,
OEMCrypto_CipherMode_CENC, key_handle));
vector<uint8_t> resultant(encrypted.size());
ASSERT_EQ(OEMCrypto_SUCCESS,
GenericDecrypt(key_handle.data(), key_handle.size(),
encrypted.data(), encrypted.size(), iv_,
OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data()));
ASSERT_EQ(clear_buffer_, resultant);
wvutil::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key.
resultant.assign(encrypted.size(), 0);
OEMCryptoResult status = GenericDecrypt(
key_handle.data(), key_handle.size(), encrypted.data(), encrypted.size(),
iv_, OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data());
ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status);
ASSERT_NE(clear_buffer_, resultant);
ASSERT_NO_FATAL_FAILURE(session_.TestGetKeyHandleExpired(key_index));
}
// Test Generic_Sign when the key duration has expired.
TEST_P(OEMCryptoGenericCryptoTest, KeyDurationSign) {
license_messages_.core_response()
.timer_limits.total_playback_duration_seconds = kDuration;
license_messages_.CreateResponseWithGenericCryptoKeys();
EncryptAndLoadKeys();
unsigned int key_index = 2;
vector<uint8_t> expected_signature;
vector<uint8_t> signature(SHA256_DIGEST_LENGTH);
size_t signature_length = signature.size();
SignBuffer(key_index, clear_buffer_, &expected_signature);
vector<uint8_t> key_handle;
// Should be valid key at the start.
ASSERT_EQ(
OEMCrypto_SUCCESS,
GetKeyHandleIntoVector(session_.session_id(),
session_.license().keys[key_index].key_id,
session_.license().keys[key_index].key_id_length,
OEMCrypto_CipherMode_CENC, key_handle));
ASSERT_EQ(
OEMCrypto_SUCCESS,
GenericSign(key_handle.data(), key_handle.size(), clear_buffer_.data(),
clear_buffer_.size(), OEMCrypto_HMAC_SHA256, signature.data(),
&signature_length));
ASSERT_EQ(expected_signature, signature);
wvutil::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key.
signature.assign(SHA256_DIGEST_LENGTH, 0);
OEMCryptoResult status =
GenericSign(key_handle.data(), key_handle.size(), clear_buffer_.data(),
clear_buffer_.size(), OEMCrypto_HMAC_SHA256, signature.data(),
&signature_length);
ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status);
ASSERT_NE(expected_signature, signature);
ASSERT_NO_FATAL_FAILURE(session_.TestGetKeyHandleExpired(key_index));
}
// Test Generic_Verify when the key duration has expired.
TEST_P(OEMCryptoGenericCryptoTest, KeyDurationVerify) {
license_messages_.core_response()
.timer_limits.total_playback_duration_seconds = kDuration;
license_messages_.CreateResponseWithGenericCryptoKeys();
EncryptAndLoadKeys();
unsigned int key_index = 3;
vector<uint8_t> signature;
SignBuffer(key_index, clear_buffer_, &signature);
vector<uint8_t> key_handle;
// Should be valid key at the start.
ASSERT_EQ(
OEMCrypto_SUCCESS,
GetKeyHandleIntoVector(session_.session_id(),
session_.license().keys[key_index].key_id,
session_.license().keys[key_index].key_id_length,
OEMCrypto_CipherMode_CENC, key_handle));
ASSERT_EQ(
OEMCrypto_SUCCESS,
GenericVerify(key_handle.data(), key_handle.size(), clear_buffer_.data(),
clear_buffer_.size(), OEMCrypto_HMAC_SHA256,
signature.data(), signature.size()));
wvutil::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key.
OEMCryptoResult status = OEMCrypto_Generic_Verify(
key_handle.data(), key_handle.size(), clear_buffer_.data(),
clear_buffer_.size(), OEMCrypto_HMAC_SHA256, signature.data(),
signature.size());
ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status);
ASSERT_NO_FATAL_FAILURE(session_.TestGetKeyHandleExpired(key_index));
}
const unsigned int kLongKeyId = 2;
// Test that short key ids are allowed.
class OEMCryptoGenericCryptoKeyIdLengthTest
: public OEMCryptoGenericCryptoTest {
protected:
void SetUp() override {
OEMCryptoGenericCryptoTest::SetUp();
license_messages_.set_num_keys(5);
license_messages_.set_control(wvoec::kControlAllowDecrypt);
license_messages_.core_response()
.timer_limits.total_playback_duration_seconds = kDuration;
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
SetUniformKeyIdLength(16); // Start with all key ids being 16 bytes.
// But, we are testing that the key ids do not have to have the same length.
// 12 bytes (common key id length).
license_messages_.SetKeyId(0, "123456789012");
license_messages_.SetKeyId(1, "12345"); // short key id.
// 16 byte key id. (default)
license_messages_.SetKeyId(2, "1234567890123456");
license_messages_.SetKeyId(3, "12345678901234"); // 14 byte. (uncommon)
license_messages_.SetKeyId(4, "1"); // very short key id.
ASSERT_EQ(2u, kLongKeyId);
ASSERT_NO_FATAL_FAILURE(license_messages_.FillCoreResponseSubstrings());
}
// Make all four keys have the same length.
void SetUniformKeyIdLength(size_t key_id_length) {
for (size_t i = 0; i < license_messages_.num_keys(); i++) {
string key_id;
key_id.resize(key_id_length, i + 'a');
license_messages_.SetKeyId(i, key_id);
}
ASSERT_NO_FATAL_FAILURE(license_messages_.FillCoreResponseSubstrings());
}
void TestWithKey(unsigned int key_index) {
ASSERT_LT(key_index, license_messages_.num_keys());
EncryptAndLoadKeys();
vector<uint8_t> encrypted;
// To make sure OEMCrypto is not expecting the key_id to be zero padded, we
// will create a buffer that is padded with 'Z'.
// Then, we use fill the buffer with the longer of the three keys. If
// OEMCrypto is paying attention to the key id length, it should pick out
// the correct key.
vector<uint8_t> key_id_buffer(
session_.license().keys[kLongKeyId].key_id_length + 5,
'Z'); // Fill a bigger buffer with letter 'Z'.
memcpy(key_id_buffer.data(), session_.license().keys[kLongKeyId].key_id,
session_.license().keys[kLongKeyId].key_id_length);
EncryptBuffer(key_index, clear_buffer_, &encrypted);
vector<uint8_t> key_handle;
ASSERT_EQ(
OEMCrypto_SUCCESS,
GetKeyHandleIntoVector(session_.session_id(), key_id_buffer.data(),
session_.license().keys[key_index].key_id_length,
OEMCrypto_CipherMode_CENC, key_handle));
vector<uint8_t> resultant(encrypted.size());
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_Generic_Decrypt(key_handle.data(), key_handle.size(),
encrypted.data(), encrypted.size(), iv_,
OEMCrypto_AES_CBC_128_NO_PADDING,
resultant.data()));
ASSERT_EQ(clear_buffer_, resultant);
}
};
TEST_P(OEMCryptoGenericCryptoKeyIdLengthTest, MediumKeyId) { TestWithKey(0); }
TEST_P(OEMCryptoGenericCryptoKeyIdLengthTest, ShortKeyId) { TestWithKey(1); }
TEST_P(OEMCryptoGenericCryptoKeyIdLengthTest, LongKeyId) { TestWithKey(2); }
TEST_P(OEMCryptoGenericCryptoKeyIdLengthTest, FourteenByteKeyId) {
TestWithKey(3);
}
TEST_P(OEMCryptoGenericCryptoKeyIdLengthTest, VeryShortKeyId) {
TestWithKey(4);
}
TEST_P(OEMCryptoGenericCryptoKeyIdLengthTest, UniformShortKeyId) {
SetUniformKeyIdLength(5);
TestWithKey(2);
}
TEST_P(OEMCryptoGenericCryptoKeyIdLengthTest, UniformLongKeyId) {
SetUniformKeyIdLength(kTestKeyIdMaxLength);
TestWithKey(2);
}
INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoGenericCryptoTest,
Range<uint32_t>(kCoreMessagesAPI, kCurrentAPI + 1));
INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoGenericCryptoKeyIdLengthTest,
Range<uint32_t>(kCoreMessagesAPI, kCurrentAPI + 1));
/// @}
} // namespace wvoec