Widevine MediaCas client code that works with Android R

This commit is contained in:
Lu Chen
2020-08-13 15:18:12 -07:00
parent ff9728aaa2
commit 0f6db6f751
243 changed files with 47012 additions and 0 deletions

38
oemcrypto/test/Android.bp Normal file
View File

@@ -0,0 +1,38 @@
cc_binary {
name: "oemcrypto_cas_test",
proprietary: true,
srcs: [
"oec_device_features.cpp",
"oec_decrypt_fallback_chain.cpp",
"oec_key_deriver.cpp",
"oec_session_util.cpp",
"oemcrypto_corpus_generator_helper.cpp",
"oemcrypto_session_tests_helper.cpp",
"oemcrypto_test.cpp",
"oemcrypto_test_android.cpp",
"oemcrypto_test_main.cpp",
"wvcrc.cpp",
"test_sleep.cpp",
],
header_libs: [
"//vendor/widevine/libwvmediacas/oemcrypto:oemcastroheaders",
"media_plugin_headers",
],
include_dirs: [
"vendor/widevine/libwvmediacas/oemcrypto/odk/include",
],
static_libs: [
"//vendor/widevine/libwvmediacas/wvutil:libcasutil",
"//vendor/widevine/libwvmediacas/plugin:libwvcasplugins",
"libgmock",
"libgtest",
"libwvcas_odk",
"libwvcas_kdo",
],
shared_libs: [
"//vendor/widevine/libwvmediacas/oemcrypto/ref:libcasoemcrypto",
"libcrypto",
"libutils",
"liblog",
],
}

23
oemcrypto/test/Android.mk Normal file
View File

@@ -0,0 +1,23 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_C_INCLUDES := \
vendor/widevine/libwvdrmengine/cdm/util/include \
LOCAL_MODULE:=oemcrypto_test
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE_OWNER := widevine
LOCAL_PROPRIETARY_MODULE := true
# When built, explicitly put it in the DATA/nativetest directory.
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest
ifneq ($(TARGET_ENABLE_MEDIADRM_64), true)
LOCAL_MODULE_TARGET_ARCH := arm x86 mips
endif
include $(LOCAL_PATH)/common.mk
include $(BUILD_EXECUTABLE)

13
oemcrypto/test/XtsTest.mk Normal file
View File

@@ -0,0 +1,13 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := XtsOEMCryptoTestCases
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)
LOCAL_XTS_TEST_PACKAGE := google.oemcrypto
include $(LOCAL_PATH)/common.mk
include $(BUILD_XTS_EXECUTABLE)

53
oemcrypto/test/common.mk Normal file
View File

@@ -0,0 +1,53 @@
LOCAL_PATH:= $(call my-dir)
ifeq ($(filter mips mips64, $(TARGET_ARCH)),)
# Tests need to be compatible with devices that do not support gnu hash-style
LOCAL_LDFLAGS+=-Wl,--hash-style=both
endif
# The unit tests can access v15 functions through the dynamic adapter:
LOCAL_CFLAGS += -DTEST_OEMCRYPTO_V15
LOCAL_SRC_FILES:= \
oec_device_features.cpp \
oec_decrypt_fallback_chain.cpp \
oec_key_deriver.cpp \
oec_session_util.cpp \
oemcrypto_corpus_generator_helper.cpp \
oemcrypto_session_tests_helper.cpp \
oemcrypto_test.cpp \
oemcrypto_test_android.cpp \
oemcrypto_test_main.cpp \
wvcrc.cpp \
../../cdm/util/test/test_sleep.cpp \
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/../include \
$(LOCAL_PATH)/../odk/include \
$(LOCAL_PATH)/../odk/kdo/include \
$(LOCAL_PATH)/../ref/src \
vendor/widevine/libwvdrmengine/cdm/core/include \
vendor/widevine/libwvdrmengine/cdm/util/include \
vendor/widevine/libwvdrmengine/cdm/util/test \
LOCAL_STATIC_LIBRARIES := \
libcdm \
libcdm_utils \
libcrypto_static \
libgtest \
libgtest_main \
libwvlevel3 \
libcdm_protos \
libcdm_utils \
libwv_kdo \
libwv_odk \
LOCAL_SHARED_LIBRARIES := \
libbase \
libdl \
liblog \
libmedia_omx \
libprotobuf-cpp-lite \
libstagefright_foundation \
libutils \
libz \

View File

@@ -0,0 +1 @@
(c020:0d112d7ea200;

View File

@@ -0,0 +1 @@
0a4c08001248000000020000101907d9ffde13aa95c122678053362136bdf8408f8276e4c2d87ec52b61aa1b9f646e58734930acebe899b3e464189a14a87202fb02570640bd22ef44b2d7e3912250a230a14080112100915007caa9b5931b76a3a85f046523e10011a09393837363534333231180120002a0c313838363738373430350000

View File

@@ -0,0 +1 @@
0a4c020:0d1190d79fef02570640bd22ef44b2d7e3912250a200

View File

@@ -0,0 +1 @@
0a(c020:0d112d7ea200;

View File

@@ -0,0 +1 @@
0a4c000000200:0101907d9ffde02570640bd22ef44b2d7e3912250a230a1407363534333231180120002a0c313838363738373430350000

View File

@@ -0,0 +1 @@
0a4c000000220:01019dd79fef02570640bd22ef44b2d7e3912250a200

View File

@@ -0,0 +1 @@
0a4c000000200:010197d9ffde02570640bd22ef44b2d7e3912250a230a1407363534333231180120002a0c313838363738373430350000

View File

@@ -0,0 +1 @@
0a4c00000020000101907d9ffde02570640bd22ef44b2d7e3912250a230a14080112100915007caa9b5931b76a3a85f046523e10011a09393837363534333231180120002a0c313838363738373430350000

View File

@@ -0,0 +1 @@
0a4c020:0d112d7e3912250a200;

View File

@@ -0,0 +1 @@
0a4c08001248000000020000101907d9ffde02570640bd22ef44b2d7e3912250a230a14080112100915007caa9b5931b76a3a85f046523e10011a09393837363534333231180120002a0c313838363738373430350000

View File

@@ -0,0 +1 @@
0a4c08001248000000020000101907d9ffde13aa95c122678053362136bdf8408f8276e4c2d87ec52b61aa1b9f646e58734930acebe899b3e464189a14a87202fb02574e70640bd22ef44b2d7e3912250a230a14080112100915007caa9b5931b76a3a85f046523e10011a09393837363534333231180120002a0c313838363738373430350000

View File

@@ -0,0 +1,50 @@
# OEMCRYPTO Fuzzing
## Objective
* Run fuzzing on OEMCrypto public APIs on linux using google
supported clusterfuzz infrastructure to find security vulnerabilities.
## Generate Corpus
* Once the fuzzer scripts are ready and running continuously using clusterfuzz
or android infrastructure, we can measure the efficiency of fuzzers by looking
at code coverage and number of new features that have been discovered by fuzzer
scripts here Fuzz script statistics.
A fuzzer which tries to start from random inputs and figure out intelligent
inputs to crash the libraries can be time consuming and not effective.
A way to make fuzzers more effective is by providing a set of valid
and invalid inputs of the library so that fuzzer can use those as a starting point.
These sets of valid and invalid inputs are called corpus.
The idea is to run OEMCrypto unit tests and read required data into binary corpus
files before calling into respective OEMCrypto APIs under test. Writing corpus data
to binary files is controlled by environment variable SHOULD_GENERATE_CORPUS.
### Get OEMCrypto and Build OEMCrypto unit tests to generate corpus:
* Install Pre-requisites
```shell
$ sudo apt-get install gyp ninja-build
```
* download cdm source code (including ODK & OEMCrypto unit tests):
```shell
$ git clone sso://widevine-internal/cdm
```
* Build OEMCrypto unit tests and run with --generate_corpus flag to
generate corpus files:
```shell
$ cd /path/to/cdm/repo
$ export CDM_DIR=/path/to/cdm/repo
$ export PATH_TO_CDM_DIR=.
$ gyp --format=ninja --depth=$(pwd) oemcrypto/oemcrypto_unittests.gyp
$ ninja -C out/Default/
$ ./out/Default/oemcrypto_unittests --generate_corpus
```

View File

@@ -0,0 +1,8 @@
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#include "oemcrypto_fuzz_helper.h"
namespace wvoec {
void RedirectStdoutToFile() { freopen("log.txt", "a", stdout); }
} // namespace wvoec

View File

@@ -0,0 +1,73 @@
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#ifndef OEMCRYPTO_FUZZ_HELPER_H_
#define OEMCRYPTO_FUZZ_HELPER_H_
#include <vector>
#include "OEMCryptoCAS.h"
#include "oec_device_features.h"
#include "oec_session_util.h"
#include "oemcrypto_corpus_generator_helper.h"
#include "oemcrypto_session_tests_helper.h"
namespace wvoec {
// Initial setup to create a valid OEMCrypto state such as initializing crypto
// firmware/hardware, installing golden key box etc. in order to fuzz
// OEMCrypto APIs.
class InitializeFuzz : public SessionUtil {
public:
InitializeFuzz() {
wvoec::global_features.Initialize();
OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox));
OEMCrypto_Initialize();
EnsureTestKeys();
}
~InitializeFuzz() { OEMCrypto_Terminate(); }
};
class OEMCryptoLicenseAPIFuzz : public InitializeFuzz {
public:
OEMCryptoLicenseAPIFuzz() : license_messages_(&session_) {
session_.open();
InstallTestRSAKey(&session_);
session_.GenerateNonce();
}
~OEMCryptoLicenseAPIFuzz() {
session_.close();
}
LicenseRoundTrip& license_messages() { return license_messages_; }
private:
Session session_;
LicenseRoundTrip license_messages_;
};
class OEMCryptoProvisioningAPIFuzz : public InitializeFuzz {
public:
OEMCryptoProvisioningAPIFuzz()
: provisioning_messages_(&session_, encoded_rsa_key_) {
// Opens a session and Generates Nonce.
provisioning_messages_.PrepareSession(keybox_);
}
~OEMCryptoProvisioningAPIFuzz() { session_.close(); }
ProvisioningRoundTrip& provisioning_messages() {
return provisioning_messages_;
}
private:
Session session_;
ProvisioningRoundTrip provisioning_messages_;
};
// Redirect printf and log statements from oemcrypto functions to a file to
// reduce noise
void RedirectStdoutToFile();
} // namespace wvoec
#endif // OEMCRYPTO_FUZZ_HELPER_H_

View File

@@ -0,0 +1,36 @@
#include "properties.h"
#include "oemcrypto_session_tests_helper.h"
using namespace wvoec;
static bool is_init = false;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
SessionUtil session_helper;
if (!is_init) {
wvoec::global_features.Initialize();
wvoec::global_features.RestrictFilter("*");
wvutil::Properties::Init();
is_init = true;
}
OEMCrypto_Initialize();
session_helper.EnsureTestKeys();
Session s;
s.open();
s.GenerateDerivedKeysFromKeybox(session_helper.keybox_);
static const uint32_t SignatureBufferMaxLength = size;
vector<uint8_t> signature(SignatureBufferMaxLength);
size_t signature_length = signature.size();
OEMCryptoResult sts;
sts = OEMCrypto_GenerateSignature(s.session_id(), data, size,
&signature[0], &signature_length);
s.close();
OEMCrypto_Terminate();
return 0;
}

View File

@@ -0,0 +1,24 @@
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#include "oemcrypto_fuzz_helper.h"
namespace wvoec {
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// Redirect printf and log statements from oemcrypto functions to a file to
// reduce noise
RedirectStdoutToFile();
if (size < sizeof(ODK_ParsedLicense) + sizeof(MessageData)) {
return 0;
}
OEMCryptoLicenseAPIFuzz license_api_fuzz;
license_api_fuzz.license_messages().SignAndVerifyRequest();
// Interpreting input fuzz data as unencrypted (core_response + license
// message data) from license server.
license_api_fuzz.license_messages().InjectFuzzedResponseData(data, size);
license_api_fuzz.license_messages().EncryptAndSignResponse();
license_api_fuzz.license_messages().LoadResponse();
return 0;
}
} // namespace wvoec

View File

@@ -0,0 +1,27 @@
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#include "oemcrypto_fuzz_helper.h"
namespace wvoec {
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// Redirect printf and log statements from oemcrypto functions to a file to
// reduce noise
RedirectStdoutToFile();
if (size < sizeof(ODK_ParsedProvisioning) + sizeof(RSAPrivateKeyMessage)) {
return 0;
}
OEMCryptoProvisioningAPIFuzz provisioning_api_fuzz;
provisioning_api_fuzz.provisioning_messages().SignAndVerifyRequest();
// Interpreting input fuzz data as unencrypted(core_response + provisioning
// message data) from provisioning server.
provisioning_api_fuzz.provisioning_messages().InjectFuzzedResponseData(data,
size);
provisioning_api_fuzz.provisioning_messages().EncryptAndSignResponse();
provisioning_api_fuzz.provisioning_messages().LoadResponse();
return 0;
}
} // namespace wvoec

View File

@@ -0,0 +1,10 @@
#include <stddef.h>
#include <stdint.h>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
if (size > 0 && data[0] == 'H')
if (size > 1 && data[1] == 'I')
if (size > 2 && data[2] == '!')
__builtin_trap();
return 0;
}

View File

@@ -0,0 +1,178 @@
// Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#include "oec_decrypt_fallback_chain.h"
#include <stdint.h>
#include <string.h>
#include "oemcrypto_types.h"
#include "string_conversions.h"
namespace {
void advance_dest_buffer(OEMCrypto_DestBufferDesc* dest_buffer, size_t bytes) {
switch (dest_buffer->type) {
case OEMCrypto_BufferType_Clear:
dest_buffer->buffer.clear.address += bytes;
dest_buffer->buffer.clear.address_length -= bytes;
break;
case OEMCrypto_BufferType_Secure:
dest_buffer->buffer.secure.offset += bytes;
break;
case OEMCrypto_BufferType_Direct:
// Nothing to do for this buffer type.
break;
}
}
void advance_iv_ctr(uint8_t (*subsample_iv)[wvoec::KEY_IV_SIZE], size_t bytes) {
uint64_t counter;
constexpr size_t half_iv_size = wvoec::KEY_IV_SIZE / 2;
memcpy(&counter, &(*subsample_iv)[half_iv_size], half_iv_size);
const size_t increment =
bytes / wvoec::AES_128_BLOCK_SIZE; // The truncation here is intentional
counter = wvutil::htonll64(wvutil::ntohll64(counter) + increment);
memcpy(&(*subsample_iv)[half_iv_size], &counter, half_iv_size);
}
} // namespace
namespace wvoec {
// Decrypts the given array of samples. Handles fallback behavior correctly if
// the OEMCrypto implementation does not accept multiple samples.
OEMCryptoResult DecryptFallbackChain::Decrypt(
OEMCrypto_SESSION session_id, const OEMCrypto_SampleDescription* samples,
size_t samples_length, OEMCryptoCipherMode cipher_mode,
const OEMCrypto_CENCEncryptPatternDesc* pattern) {
OEMCryptoResult sts =
OEMCrypto_DecryptCENC(session_id, samples, samples_length, pattern);
// No need for a fallback. Abort early.
if (sts != OEMCrypto_ERROR_BUFFER_TOO_LARGE) return sts;
// Fall back to decrypting individual samples.
for (size_t i = 0; i < samples_length; ++i) {
sts = DecryptSample(session_id, samples[i], cipher_mode, pattern);
if (sts != OEMCrypto_SUCCESS) return sts;
}
return sts;
}
// Decrypts the given sample. Handles fallback behavior correctly if the
// OEMCrypto implementation does not accept full samples.
OEMCryptoResult DecryptFallbackChain::DecryptSample(
OEMCrypto_SESSION session_id, const OEMCrypto_SampleDescription& sample,
OEMCryptoCipherMode cipher_mode,
const OEMCrypto_CENCEncryptPatternDesc* pattern) {
OEMCryptoResult sts = OEMCrypto_DecryptCENC(session_id, &sample, 1, pattern);
// No need for a fallback. Abort early.
if (sts != OEMCrypto_ERROR_BUFFER_TOO_LARGE) return sts;
// Fall back to decrypting individual subsamples.
OEMCrypto_SampleDescription fake_sample = sample;
for (size_t i = 0; i < sample.subsamples_length; ++i) {
const OEMCrypto_SubSampleDescription& subsample = sample.subsamples[i];
const size_t length =
subsample.num_bytes_clear + subsample.num_bytes_encrypted;
fake_sample.buffers.input_data_length = length;
fake_sample.subsamples = &subsample;
fake_sample.subsamples_length = 1;
sts = DecryptSubsample(session_id, fake_sample, pattern);
if (sts != OEMCrypto_SUCCESS) return sts;
fake_sample.buffers.input_data += length;
advance_dest_buffer(&fake_sample.buffers.output_descriptor, length);
if (cipher_mode == OEMCrypto_CipherMode_CTR) {
advance_iv_ctr(&fake_sample.iv,
subsample.block_offset + subsample.num_bytes_encrypted);
}
}
return sts;
}
// Decrypts the given subsample. Handles fallback behavior correctly if the
// OEMCrypto implementation does not accept full subsamples.
OEMCryptoResult DecryptFallbackChain::DecryptSubsample(
OEMCrypto_SESSION session_id, const OEMCrypto_SampleDescription& sample,
const OEMCrypto_CENCEncryptPatternDesc* pattern) {
OEMCryptoResult sts = OEMCrypto_DecryptCENC(session_id, &sample, 1, pattern);
// No need for a fallback. Abort early.
if (sts != OEMCrypto_ERROR_BUFFER_TOO_LARGE) return sts;
// Fall back to decrypting individual subsample halves.
const OEMCrypto_SubSampleDescription& subsample = sample.subsamples[0];
OEMCrypto_SampleDescription fake_sample = sample;
OEMCrypto_SubSampleDescription fake_subsample;
fake_sample.subsamples = &fake_subsample;
fake_sample.subsamples_length = 1;
if (subsample.num_bytes_clear > 0) {
fake_sample.buffers.input_data_length = subsample.num_bytes_clear;
fake_subsample.num_bytes_clear = subsample.num_bytes_clear;
fake_subsample.num_bytes_encrypted = 0;
fake_subsample.block_offset = 0;
fake_subsample.subsample_flags = 0;
if (subsample.subsample_flags & OEMCrypto_FirstSubsample)
fake_subsample.subsample_flags |= OEMCrypto_FirstSubsample;
if (subsample.subsample_flags & OEMCrypto_LastSubsample &&
subsample.num_bytes_encrypted == 0)
fake_subsample.subsample_flags |= OEMCrypto_LastSubsample;
sts = DecryptSubsampleHalf(session_id, fake_sample, pattern);
if (sts != OEMCrypto_SUCCESS) return sts;
// Advance the buffers for the other half, in case they're needed.
fake_sample.buffers.input_data += subsample.num_bytes_clear;
advance_dest_buffer(&fake_sample.buffers.output_descriptor,
subsample.num_bytes_clear);
}
if (subsample.num_bytes_encrypted > 0) {
fake_sample.buffers.input_data_length = subsample.num_bytes_encrypted;
fake_subsample.num_bytes_clear = 0;
fake_subsample.num_bytes_encrypted = subsample.num_bytes_encrypted;
fake_subsample.block_offset = subsample.block_offset;
fake_subsample.subsample_flags = 0;
if (subsample.subsample_flags & OEMCrypto_FirstSubsample &&
subsample.num_bytes_clear == 0)
fake_subsample.subsample_flags |= OEMCrypto_FirstSubsample;
if (subsample.subsample_flags & OEMCrypto_LastSubsample)
fake_subsample.subsample_flags |= OEMCrypto_LastSubsample;
sts = DecryptSubsampleHalf(session_id, fake_sample, pattern);
if (sts != OEMCrypto_SUCCESS) return sts;
}
return sts;
}
// Decrypts the given subsample half. There is no fallback behavior after this;
// an OEMCrypto_ERROR_BUFFER_TOO_LARGE produced here will be returned to the
// caller.
OEMCryptoResult DecryptFallbackChain::DecryptSubsampleHalf(
OEMCrypto_SESSION session_id, const OEMCrypto_SampleDescription& sample,
const OEMCrypto_CENCEncryptPatternDesc* pattern) {
return OEMCrypto_DecryptCENC(session_id, &sample, 1, pattern);
// In a real CDM, you would want some fallback here to handle the case where
// the buffer is too big for the OEMCrypto implementation. But in the case of
// the tests, we won't be passing a buffer that's too big unless we are trying
// to test that failure condition, so there's no need to handle that case
// here.
}
} // namespace wvoec

View File

@@ -0,0 +1,59 @@
// Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#ifndef CDM_OEC_DECRYPT_FALLBACK_CHAIN_H_
#define CDM_OEC_DECRYPT_FALLBACK_CHAIN_H_
#include "OEMCryptoCAS.h"
#include "disallow_copy_and_assign.h"
namespace wvoec {
// This class groups static methods relating to providing proper fallback
// behavior when calling DecryptCENC in OEMCrypto v16. Outside code can leverage
// this behavior by passing the samples to be decrypted to Decrypt(), which will
// set off the chain of fallback functions as needed.
//
// The behavior of this class is pathological. For each block of data, it will
// greedily try every possible way of passing data to OEMCrypto until one works.
// In the order tried, the ways to send data are:
// 1) Multiple Samples at once
// 2) Individual Samples one at a time
// 3) Individual Subsamples one at a time
// 4) Individual Half-Subsamples one at a time
// On a device that only accepts half-subsamples, the way OEMCrypto v15 did,
// this results in many needless roundtrips to OEMCrypto. This would be
// inefficient behavior for a real CDM, but for the sake of testing, we want to
// use the maximal way the OEMCrypto implementation will accept the data. And,
// for implementations that do not accept multiple samples or subsamples per
// call, we want to test that they correctly reject larger calls.
class DecryptFallbackChain {
public:
static OEMCryptoResult Decrypt(
OEMCrypto_SESSION session_id, const OEMCrypto_SampleDescription* samples,
size_t samples_length, OEMCryptoCipherMode cipher_mode,
const OEMCrypto_CENCEncryptPatternDesc* pattern);
private:
static OEMCryptoResult DecryptSample(
OEMCrypto_SESSION session_id, const OEMCrypto_SampleDescription& sample,
OEMCryptoCipherMode cipher_mode,
const OEMCrypto_CENCEncryptPatternDesc* pattern);
static OEMCryptoResult DecryptSubsample(
OEMCrypto_SESSION session_id, const OEMCrypto_SampleDescription& sample,
const OEMCrypto_CENCEncryptPatternDesc* pattern);
static OEMCryptoResult DecryptSubsampleHalf(
OEMCrypto_SESSION session_id, const OEMCrypto_SampleDescription& sample,
const OEMCrypto_CENCEncryptPatternDesc* pattern);
// There is no reason to have an instance of this class.
DecryptFallbackChain() = delete;
CORE_DISALLOW_COPY_AND_ASSIGN(DecryptFallbackChain);
};
} // namespace wvoec
#endif // CDM_OEC_DECRYPT_FALLBACK_CHAIN_H_

View File

@@ -0,0 +1,260 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// OEMCrypto device features for unit tests
//
#include "oec_device_features.h"
#include <stdio.h>
#include <cstring>
#include "oec_test_data.h"
#include "test_sleep.h"
namespace wvoec {
DeviceFeatures global_features;
void DeviceFeatures::Initialize() {
if (initialized_) return;
uses_keybox = false;
loads_certificate = false;
generic_crypto = false;
usage_table = false;
supports_rsa_3072 = false;
api_version = 0;
derive_key_method = NO_METHOD;
OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox));
if (OEMCrypto_SUCCESS != OEMCrypto_Initialize()) {
printf("OEMCrypto_Initialize failed. All tests will fail.\n");
return;
}
uint8_t buffer[1];
uint8_t iv[16] = {};
size_t size = 0;
provisioning_method = OEMCrypto_GetProvisioningMethod();
printf("provisioning_method = %s\n",
ProvisioningMethodName(provisioning_method));
uses_keybox =
(OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_GetKeyData(buffer, &size));
printf("uses_keybox = %s.\n", uses_keybox ? "true" : "false");
OEMCrypto_SESSION session;
OEMCryptoResult result = OEMCrypto_OpenSession(&session);
if (result != OEMCrypto_SUCCESS) {
printf("--- ERROR: Could not open session: %d ----\n", result);
}
// If the device uses a keybox, check to see if loading a certificate is
// installed.
if (provisioning_method == OEMCrypto_Keybox ||
provisioning_method == OEMCrypto_OEMCertificate) {
// Devices with a keybox or OEM Certificate are required to support loading
// a DRM certificate.
loads_certificate = true;
} else {
// Other devices are either broken, or they have a baked in certificate.
loads_certificate = false;
}
printf("loads_certificate = %s.\n", loads_certificate ? "true" : "false");
generic_crypto =
(OEMCrypto_ERROR_NOT_IMPLEMENTED !=
OEMCrypto_Generic_Encrypt(session, buffer, 0, iv,
OEMCrypto_AES_CBC_128_NO_PADDING, buffer));
printf("generic_crypto = %s.\n", generic_crypto ? "true" : "false");
OEMCrypto_CloseSession(session);
api_version = OEMCrypto_APIVersion();
printf("api_version = %d.\n", api_version);
// These unit tests only work with new usage tables. We do not test v12
// usage tables.
if (api_version > 12) usage_table = OEMCrypto_SupportsUsageTable();
printf("usage_table = %s.\n", usage_table ? "true" : "false");
PickDerivedKey();
if (api_version >= 13) {
uint32_t supported_cert = OEMCrypto_SupportedCertificates();
if (supported_cert & OEMCrypto_Supports_RSA_CAST) {
cast_receiver = true;
}
if (supported_cert & OEMCrypto_Supports_RSA_3072bit) {
supports_rsa_3072 = true;
}
}
printf("cast_receiver = %s.\n", cast_receiver ? "true" : "false");
resource_rating = OEMCrypto_ResourceRatingTier();
printf("resource_rating = %d, security level %s.\n", resource_rating,
OEMCrypto_SecurityLevel());
uint32_t decrypt_hash_type = OEMCrypto_SupportsDecryptHash();
supports_crc = (decrypt_hash_type == OEMCrypto_CRC_Clear_Buffer);
if (supports_crc) {
printf("Decrypt hashes will be tested.\n");
} else {
printf("Decrypt hashes will not be tested -- %s.\n",
decrypt_hash_type == OEMCrypto_Hash_Not_Supported
? "not supported"
: "partner defined hash");
}
switch (derive_key_method) {
case NO_METHOD:
printf("NO_METHOD: Cannot derive known session keys.\n");
// Note: cast_receiver left unchanged because set by user on command line.
uses_keybox = false;
loads_certificate = false;
generic_crypto = false;
usage_table = false;
break;
case LOAD_TEST_KEYBOX:
printf("LOAD_TEST_KEYBOX: Call LoadTestKeybox before deriving keys.\n");
break;
case LOAD_TEST_RSA_KEY:
printf("LOAD_TEST_RSA_KEY: Call LoadTestRSAKey before deriving keys.\n");
break;
case TEST_PROVISION_30:
printf("TEST_PROVISION_30: Device provisioed with OEM Cert.\n");
break;
}
std::string security_level = OEMCrypto_SecurityLevel();
supports_level_1 = (security_level == "L1");
printf("SecurityLevel is %s (%s)\n",
supports_level_1 ? "Level 1" : "Not Level 1",
security_level.c_str());
CheckSecureBuffers();
OEMCrypto_Terminate();
initialized_ = true;
}
std::string DeviceFeatures::RestrictFilter(const std::string& initial_filter) {
std::string filter = initial_filter;
// clang-format off
if (!uses_keybox) FilterOut(&filter, "*KeyboxTest*");
if (!loads_certificate) FilterOut(&filter, "OEMCryptoLoadsCert*");
if (!generic_crypto) FilterOut(&filter, "*GenericCrypto*");
if (!cast_receiver) FilterOut(&filter, "*CastReceiver*");
if (!usage_table) FilterOut(&filter, "*UsageTable*");
if (derive_key_method == NO_METHOD) FilterOut(&filter, "*SessionTest*");
if (provisioning_method
!= OEMCrypto_OEMCertificate) FilterOut(&filter, "*Prov30*");
if (!supports_rsa_3072) FilterOut(&filter, "*RSAKey3072*");
if (api_version < 9) FilterOut(&filter, "*API09*");
if (api_version < 10) FilterOut(&filter, "*API10*");
if (api_version < 11) FilterOut(&filter, "*API11*");
if (api_version < 12) FilterOut(&filter, "*API12*");
if (api_version < 13) FilterOut(&filter, "*API13*");
if (api_version < 14) FilterOut(&filter, "*API14*");
if (api_version < 15) FilterOut(&filter, "*API15*");
if (api_version < 16) FilterOut(&filter, "*API16*");
// clang-format on
// Some tests may require root access. If user is not root, filter these tests
// out.
if (!wvutil::TestSleep::CanChangeSystemTime()) {
printf("Filtering out TimeRollbackPrevention.\n");
FilterOut(&filter, "*TimeRollbackPrevention*");
} else {
printf("Can change time. I will run TimeRollbackPrevention.\n");
}
// Performance tests take a long time. Filter them out if they are not
// specifically requested.
if (filter.find("Performance") == std::string::npos) {
FilterOut(&filter, "*Performance*");
}
return filter;
}
void DeviceFeatures::PickDerivedKey() {
if (api_version >= 12) {
switch (provisioning_method) {
case OEMCrypto_OEMCertificate:
derive_key_method = TEST_PROVISION_30;
return;
case OEMCrypto_DrmCertificate:
if (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestRSAKey()) {
derive_key_method = LOAD_TEST_RSA_KEY;
}
return;
case OEMCrypto_Keybox:
// Fall through to api_version < 12 case.
break;
case OEMCrypto_ProvisioningError:
printf(
"ERROR: OEMCrypto_GetProvisioningMethod() returns "
"OEMCrypto_ProvisioningError\n");
// Then fall through to api_version < 12 case.
break;
}
}
if (uses_keybox) {
// If device uses a keybox, try to load the test keybox.
if (OEMCrypto_ERROR_NOT_IMPLEMENTED !=
OEMCrypto_LoadTestKeybox(nullptr, 0)) {
derive_key_method = LOAD_TEST_KEYBOX;
}
} else if (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestRSAKey()) {
derive_key_method = LOAD_TEST_RSA_KEY;
}
}
void DeviceFeatures::CheckSecureBuffers() {
output_types_.push_back({false, OEMCrypto_BufferType_Clear});
output_types_.push_back({true, OEMCrypto_BufferType_Clear});
test_secure_buffers = false;
OEMCrypto_SESSION session;
OEMCryptoResult result = OEMCrypto_OpenSession(&session);
if (result != OEMCrypto_SUCCESS) {
printf("--- ERROR: Could not open session: %d ----\n", result);
return;
}
OEMCrypto_DestBufferDesc output_descriptor;
output_descriptor.type = OEMCrypto_BufferType_Secure;
int secure_fd;
result = OEMCrypto_AllocateSecureBuffer(session, 42, &output_descriptor,
&secure_fd);
if (result == OEMCrypto_ERROR_NOT_IMPLEMENTED) {
printf("Secure buffers will not be tested\n");
return;
}
if (result != OEMCrypto_SUCCESS) {
printf("--- ERROR: Could not create secure buffer: %d ----\n", result);
return;
}
result = OEMCrypto_FreeSecureBuffer(session, &output_descriptor, secure_fd);
if (result != OEMCrypto_SUCCESS) {
printf("--- ERROR: Could not free secure buffer: %d ----\n", result);
return;
}
printf("Secure buffers will be tested\n");
output_types_.push_back({false, OEMCrypto_BufferType_Secure});
test_secure_buffers = true;
}
void DeviceFeatures::FilterOut(std::string* current_filter,
const std::string& new_filter) {
if (current_filter->find('-') == std::string::npos) {
*current_filter += "-" + new_filter;
} else {
*current_filter += ":" + new_filter;
}
}
// Return the list of output types for the decrypt tests.
const std::vector<OutputType>& DeviceFeatures::GetOutputTypes() {
if (!initialized_) {
Initialize();
}
return output_types_;
}
const char* ProvisioningMethodName(OEMCrypto_ProvisioningMethod method) {
switch (method) {
case OEMCrypto_ProvisioningError:
return "OEMCrypto_ProvisioningError";
case OEMCrypto_DrmCertificate:
return "OEMCrypto_DrmCertificate";
case OEMCrypto_Keybox:
return "OEMCrypto_Keybox";
case OEMCrypto_OEMCertificate:
return "OEMCrypto_OEMCertificate";
}
// Not reachable
return "";
}
} // namespace wvoec

View File

@@ -0,0 +1,88 @@
#ifndef CDM_OEC_DEVICE_FEATURES_H_
#define CDM_OEC_DEVICE_FEATURES_H_
#include <string>
#include <vector>
#include "OEMCryptoCAS.h"
#include "oemcrypto_types.h"
namespace wvoec {
// These tests are designed to work for this version:
constexpr unsigned int kCurrentAPI = 16;
// The API version when Core Messages were introduced.
constexpr unsigned int kCoreMessagesAPI = 16;
// An output type for testing. The type field is secure, clear, or direct. If
// the type is clear, then decrypt_inplace could be true. Otherwise,
// decrypt_inplace is false.
struct OutputType {
bool decrypt_inplace;
OEMCryptoBufferType type;
};
// Keeps track of which features are supported by the version of OEMCrypto being
// tested. See the integration guide for a list of optional features.
class DeviceFeatures {
public:
// There are several possible methods used to derive a set of known session
// keys. For example, the test can install a known test keybox, or it can
// parse the OEM certificate.
enum DeriveMethod { // Method to use derive session keys.
NO_METHOD, // Cannot derive known session keys.
LOAD_TEST_KEYBOX, // Call LoadTestKeybox before deriving keys.
LOAD_TEST_RSA_KEY, // Call LoadTestRSAKey before deriving keys.
TEST_PROVISION_30, // Device has OEM Certificate installed.
};
enum DeriveMethod derive_key_method;
bool uses_keybox; // Device uses a keybox to derive session keys.
bool loads_certificate; // Device can load a certificate from the server.
bool generic_crypto; // Device supports generic crypto.
bool cast_receiver; // Device supports alternate rsa signature padding.
bool usage_table; // Device saves usage information.
bool supports_rsa_3072; // Device supports 3072 bit RSA keys.
bool supports_level_1; // Device supports Level 1 security.
uint32_t resource_rating; // Device's resource rating tier.
bool supports_crc; // Supported decrypt hash type CRC.
bool test_secure_buffers; // If we can create a secure buffer for testing.
uint32_t api_version;
OEMCrypto_ProvisioningMethod provisioning_method;
// This should be called from the test program's main procedure.
void Initialize();
void set_cast_receiver(bool is_cast_receiver) {
cast_receiver = is_cast_receiver;
}
// Generate a GTest filter of tests that should not be run. This should be
// called after Initialize. Tests are filtered out based on which features
// are not supported. For example, a device that uses Provisioning 3.0 will
// have all keybox tests filtered out.
std::string RestrictFilter(const std::string& initial_filter);
// Get a list of output types that should be tested.
const std::vector<OutputType>& GetOutputTypes();
private:
// Decide which method should be used to derive session keys, based on
// supported featuers.
void PickDerivedKey();
// Decide if secure buffers can be created, and initialize output_types_.
void CheckSecureBuffers();
// Add a GTest filter restriction to the current filter.
void FilterOut(std::string* current_filter, const std::string& new_filter);
// A list of possible output types.
std::vector<OutputType> output_types_;
bool initialized_ = false;
};
// There is one global set of features for the version of OEMCrypto being
// tested. This should be initialized in the test program's main procedure.
extern DeviceFeatures global_features;
const char* ProvisioningMethodName(OEMCrypto_ProvisioningMethod method);
} // namespace wvoec
#endif // CDM_OEC_DEVICE_FEATURES_H_

View File

@@ -0,0 +1,168 @@
// Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// OEMCrypto unit tests
//
#include "oec_session_util.h"
#include <openssl/aes.h>
#include <openssl/bio.h>
#include <openssl/cmac.h>
#include <openssl/err.h>
#include <openssl/hmac.h>
#include <openssl/pem.h>
#include <openssl/rand.h>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#include <stdint.h>
#include <gtest/gtest.h>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include "OEMCryptoCAS.h"
#include "disallow_copy_and_assign.h"
#include "log.h"
#include "oec_device_features.h"
#include "oec_test_data.h"
#include "oemcrypto_types.h"
#include "platform.h"
#include "string_conversions.h"
using namespace std;
namespace wvoec {
void Encryptor::set_enc_key(const std::vector<uint8_t>& enc_key) {
enc_key_ = enc_key;
}
void Encryptor::CBCEncrypt(const uint8_t* data, uint8_t* encrypted_data,
size_t data_length,
const uint8_t (&iv)[KEY_IV_SIZE]) const {
ASSERT_EQ(enc_key_.size(), KEY_SIZE);
ASSERT_NE(data, nullptr);
ASSERT_NE(encrypted_data, nullptr);
AES_KEY aes_key;
static const int key_size = KEY_SIZE * 8; // in bits.
AES_set_encrypt_key(enc_key_.data(), key_size, &aes_key);
uint8_t iv_buffer[KEY_IV_SIZE];
memcpy(iv_buffer, iv, KEY_IV_SIZE);
AES_cbc_encrypt(data, encrypted_data, data_length, &aes_key, iv_buffer,
AES_ENCRYPT);
}
void Encryptor::PadAndEncryptProvisioningMessage(
RSAPrivateKeyMessage* data, RSAPrivateKeyMessage* encrypted) const {
EXPECT_EQ(1, GetRandBytes(data->rsa_key_iv, KEY_IV_SIZE));
ASSERT_EQ(enc_key_.size(), KEY_SIZE);
*encrypted = *data;
size_t padding = AES_BLOCK_SIZE - (data->rsa_key_length % AES_BLOCK_SIZE);
memset(data->rsa_key + data->rsa_key_length, static_cast<uint8_t>(padding),
padding);
encrypted->rsa_key_length = data->rsa_key_length + padding;
AES_KEY aes_key;
static const int key_size = KEY_SIZE * 8; // in bits.
AES_set_encrypt_key(enc_key_.data(), key_size, &aes_key);
uint8_t iv_buffer[KEY_IV_SIZE];
memcpy(iv_buffer, &data->rsa_key_iv[0], KEY_IV_SIZE);
AES_cbc_encrypt(&data->rsa_key[0], &encrypted->rsa_key[0],
encrypted->rsa_key_length, &aes_key, iv_buffer, AES_ENCRYPT);
}
// This generates the data for deriving one key. If there are failures in
// this function, then there is something wrong with the test program and its
// dependency on BoringSSL.
void KeyDeriver::DeriveKey(const uint8_t* key, const vector<uint8_t>& context,
int counter, vector<uint8_t>* out) {
ASSERT_NE(key, nullptr);
ASSERT_FALSE(context.empty());
ASSERT_GE(4, counter);
ASSERT_LE(1, counter);
ASSERT_NE(out, nullptr);
const EVP_CIPHER* cipher = EVP_aes_128_cbc();
CMAC_CTX* cmac_ctx = CMAC_CTX_new();
ASSERT_NE(nullptr, cmac_ctx);
ASSERT_TRUE(CMAC_Init(cmac_ctx, key, KEY_SIZE, cipher, 0));
std::vector<uint8_t> message;
message.push_back(static_cast<uint8_t>(counter));
message.insert(message.end(), context.begin(), context.end());
ASSERT_TRUE(CMAC_Update(cmac_ctx, message.data(), message.size()));
size_t reslen;
uint8_t res[128];
ASSERT_TRUE(CMAC_Final(cmac_ctx, res, &reslen));
out->assign(res, res + reslen);
CMAC_CTX_free(cmac_ctx);
}
// This generates the data for deriving a set of keys. If there are failures in
// this function, then there is something wrong with the test program and its
// dependency on BoringSSL.
void KeyDeriver::DeriveKeys(const uint8_t* master_key,
const vector<uint8_t>& mac_key_context,
const vector<uint8_t>& enc_key_context) {
// Generate derived key for mac key
std::vector<uint8_t> mac_key_part2;
DeriveKey(master_key, mac_key_context, 1, &mac_key_server_);
DeriveKey(master_key, mac_key_context, 2, &mac_key_part2);
mac_key_server_.insert(mac_key_server_.end(), mac_key_part2.begin(),
mac_key_part2.end());
DeriveKey(master_key, mac_key_context, 3, &mac_key_client_);
DeriveKey(master_key, mac_key_context, 4, &mac_key_part2);
mac_key_client_.insert(mac_key_client_.end(), mac_key_part2.begin(),
mac_key_part2.end());
// Generate derived key for encryption key
std::vector<uint8_t> enc_key;
DeriveKey(master_key, enc_key_context, 1, &enc_key);
set_enc_key(enc_key);
}
void KeyDeriver::set_mac_keys(const uint8_t* mac_keys) {
ASSERT_EQ(mac_key_server_.size(), MAC_KEY_SIZE);
ASSERT_EQ(mac_key_client_.size(), MAC_KEY_SIZE);
memcpy(mac_key_server_.data(), mac_keys, MAC_KEY_SIZE);
memcpy(mac_key_client_.data(), mac_keys + MAC_KEY_SIZE, MAC_KEY_SIZE);
}
void KeyDeriver::ServerSignBuffer(const uint8_t* data, size_t data_length,
std::vector<uint8_t>* signature) const {
ASSERT_EQ(mac_key_server_.size(), MAC_KEY_SIZE);
signature->assign(SHA256_DIGEST_LENGTH, 0);
unsigned int sig_len = SHA256_DIGEST_LENGTH;
ASSERT_TRUE(HMAC(EVP_sha256(), mac_key_server_.data(), mac_key_server_.size(),
data, data_length, signature->data(), &sig_len));
}
void KeyDeriver::ClientSignBuffer(const vector<uint8_t>& buffer,
std::vector<uint8_t>* signature) const {
ASSERT_EQ(mac_key_client_.size(), MAC_KEY_SIZE);
signature->assign(SHA256_DIGEST_LENGTH, 0);
unsigned int sig_len = SHA256_DIGEST_LENGTH;
ASSERT_TRUE(HMAC(EVP_sha256(), mac_key_client_.data(), mac_key_client_.size(),
buffer.data(), buffer.size(), signature->data(), &sig_len));
}
void KeyDeriver::ClientSignPstReport(const vector<uint8_t>& pst_report_buffer,
std::vector<uint8_t>* signature) const {
ASSERT_EQ(mac_key_client_.size(), MAC_KEY_SIZE);
signature->assign(SHA_DIGEST_LENGTH, 0);
unsigned int sig_len = SHA_DIGEST_LENGTH;
ASSERT_TRUE(HMAC(EVP_sha1(), mac_key_client_.data(), mac_key_client_.size(),
&pst_report_buffer[SHA_DIGEST_LENGTH],
pst_report_buffer.size() - SHA_DIGEST_LENGTH,
signature->data(), &sig_len));
}
} // namespace wvoec

View File

@@ -0,0 +1,93 @@
// Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
#ifndef CDM_OEC_KEY_DERIVER_H_
#define CDM_OEC_KEY_DERIVER_H_
#include <openssl/aes.h>
#include <openssl/rsa.h>
#include <time.h>
#include <string>
#include <vector>
#include "oec_device_features.h"
#include "oemcrypto_types.h"
#include "pst_report.h"
namespace wvoec {
constexpr size_t kMaxTestRSAKeyLength = 2000; // Rough estimate.
constexpr size_t kMaxCoreProvRequest = 150; // Rough estimate.
// This structure will be signed to simulate a provisioning response from the
// server.
struct RSAPrivateKeyMessage {
uint8_t rsa_key[kMaxTestRSAKeyLength];
uint8_t rsa_key_iv[KEY_IV_SIZE];
size_t rsa_key_length;
uint8_t enc_message_key[kMaxTestRSAKeyLength];
size_t enc_message_key_length;
uint32_t nonce;
};
// Holds an encryption key and can encrypt a provisioning message. It also can
// encrypt short buffers using CBC, such as content keys in a license.
class Encryptor {
public:
Encryptor() : enc_key_(KEY_SIZE, 0) {}
Encryptor(const std::vector<uint8_t>& enc_key) { set_enc_key(enc_key); };
Encryptor& operator=(const Encryptor&) = default;
void set_enc_key(const std::vector<uint8_t>& enc_key);
// This encrypts an RSAPrivateKeyMessage with encryption_key so that it may be
// loaded with OEMCrypto_LoadProvisioningResponse.
// This modifies the clear data: it adds padding and generates a random iv.
void PadAndEncryptProvisioningMessage(RSAPrivateKeyMessage* data,
RSAPrivateKeyMessage* encrypted) const;
void CBCEncrypt(const uint8_t* data, uint8_t* encrypted_data,
size_t data_length, const uint8_t (&iv)[KEY_IV_SIZE]) const;
private:
std::vector<uint8_t> enc_key_;
};
// Holds encryption and mac keys derived from a master key.
// Can be used to sign a buffer as either a server or client.
class KeyDeriver : public Encryptor {
public:
KeyDeriver()
: mac_key_server_(MAC_KEY_SIZE, 0), mac_key_client_(MAC_KEY_SIZE, 0) {}
KeyDeriver& operator=(const KeyDeriver&) = default;
// Generate mac and enc keys give the master key.
void DeriveKeys(const uint8_t* master_key,
const std::vector<uint8_t>& mac_key_context,
const std::vector<uint8_t>& enc_key_context);
// Sign the buffer with server's mac key.
void ServerSignBuffer(const uint8_t* data, size_t data_length,
std::vector<uint8_t>* signature) const;
// Sign the buffer with client's known mac key. Known test keys must be
// installed first. This uses HMAC with SHA256, so is suitable for a message.
void ClientSignBuffer(const std::vector<uint8_t>& buffer,
std::vector<uint8_t>* signature) const;
// Sign the pst buffer with client's known mac key. Known test keys must be
// installed first. This uses HMAC with SHA128, and skips the beginning of the
// buffer, so is only suitable for a pst report.
void ClientSignPstReport(const std::vector<uint8_t>& pst_report_buffer,
std::vector<uint8_t>* signature) const;
void set_mac_keys(const uint8_t* mac_keys);
private:
// Internal utility function to derive key using CMAC-128
void DeriveKey(const uint8_t* key, const std::vector<uint8_t>& context,
int counter, std::vector<uint8_t>* out);
std::vector<uint8_t> mac_key_server_;
std::vector<uint8_t> mac_key_client_;
};
} // namespace wvoec
#endif // CDM_OEC_KEY_DERIVER_H_

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -0,0 +1,688 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Test data for OEMCrypto unit tests.
//
#ifndef CDM_OEC_TEST_DATA_H_
#define CDM_OEC_TEST_DATA_H_
#include <string>
#include "OEMCryptoCAS.h"
#include "oemcrypto_types.h"
namespace wvoec {
// This is a test keybox. It will not be accepted by production systems. By
// using a known keybox for these tests, the results for a given set of inputs
// to a test are predictable and can be compared to the actual results.
static const WidevineKeybox kTestKeybox = {
// Sample keybox used for test vectors
{
// deviceID = WidevineTestOnlyKeybox000
0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65,
0x54, 0x65, 0x73, 0x74, 0x4f, 0x6e, 0x6c, 0x79,
0x4b, 0x65, 0x79, 0x62, 0x6f, 0x78, 0x30, 0x30,
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}, {
// key
0xe4, 0xff, 0x57, 0x4c, 0x32, 0x2e, 0xf5, 0x34,
0x26, 0x21, 0x2c, 0xb3, 0xed, 0x37, 0xf3, 0x5e,
}, {
// data (system ID 7912 = 1EE8).
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x1e, 0xe8,
0xca, 0x1e, 0x71, 0x7c, 0xfb, 0xe8, 0xa3, 0x94,
0x52, 0x0a, 0x6b, 0x71, 0x37, 0xd2, 0x69, 0xfa,
0x5a, 0xc6, 0xb5, 0x4c, 0x6b, 0x46, 0x63, 0x9b,
0xbe, 0x80, 0x3d, 0xbb, 0x4f, 0xf7, 0x4c, 0x5f,
0x6f, 0x55, 0x0e, 0x3d, 0x3d, 0x9a, 0xcf, 0x81,
0x12, 0x5d, 0x52, 0xe0, 0x47, 0x8c, 0xda, 0x0b,
0xf4, 0x31, 0x41, 0x13, 0xd0, 0xd5, 0x2d, 0xa0,
0x5b, 0x20, 0x9a, 0xed, 0x51, 0x5d, 0x13, 0xd6,
}, {
// magic
0x6b, 0x62, 0x6f, 0x78,
}, {
// Crc
0x39, 0xf2, 0x94, 0xa7,
}
};
// A 2048 bit RSA key in PKCS#8 PrivateKeyInfo format
// Used to verify the functions that manipulate RSA keys.
static const uint8_t kTestRSAPKCS8PrivateKeyInfo2_2048[] = {
0x30, 0x82, 0x04, 0xbc, 0x02, 0x01, 0x00, 0x30,
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
0x04, 0xa6, 0x30, 0x82, 0x04, 0xa2, 0x02, 0x01,
0x00, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa7, 0x00,
0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a,
0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f,
0x94, 0x58, 0xdd, 0xde, 0xa7, 0x1f, 0x3c, 0x2c,
0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e,
0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a,
0x2a, 0xaa, 0x9d, 0xb4, 0x4e, 0xfa, 0xa7, 0x6a,
0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3,
0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f,
0x28, 0xda, 0x3f, 0xce, 0x31, 0x7b, 0xfd, 0x06,
0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb,
0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3,
0x29, 0xf2, 0x73, 0x9e, 0x39, 0xd8, 0xf6, 0x6f,
0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4,
0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04,
0xcd, 0x9a, 0x13, 0x8b, 0x54, 0x73, 0x54, 0x25,
0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda,
0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67,
0x98, 0x56, 0x57, 0x54, 0x71, 0xcd, 0x12, 0x7f,
0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03,
0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53,
0xc9, 0x83, 0x06, 0x51, 0x5a, 0x88, 0x65, 0x13,
0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b,
0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e,
0x2d, 0x5f, 0xf8, 0x12, 0x7f, 0xa2, 0xfc, 0xbb,
0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01,
0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87,
0x82, 0x46, 0x0b, 0x3a, 0x77, 0x8f, 0xc0, 0x72,
0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed,
0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44,
0xd3, 0x5b, 0x3d, 0xdb, 0x9c, 0x5e, 0x1b, 0x7b,
0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb,
0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03,
0x01, 0x00, 0x01, 0x02, 0x82, 0x01, 0x00, 0x5e,
0x79, 0x65, 0x49, 0xa5, 0x76, 0x79, 0xf9, 0x05,
0x45, 0x0f, 0xf4, 0x03, 0xbd, 0xa4, 0x7d, 0x29,
0xd5, 0xde, 0x33, 0x63, 0xd8, 0xb8, 0xac, 0x97,
0xeb, 0x3f, 0x5e, 0x55, 0xe8, 0x7d, 0xf3, 0xe7,
0x3b, 0x5c, 0x2d, 0x54, 0x67, 0x36, 0xd6, 0x1d,
0x46, 0xf5, 0xca, 0x2d, 0x8b, 0x3a, 0x7e, 0xdc,
0x45, 0x38, 0x79, 0x7e, 0x65, 0x71, 0x5f, 0x1c,
0x5e, 0x79, 0xb1, 0x40, 0xcd, 0xfe, 0xc5, 0xe1,
0xc1, 0x6b, 0x78, 0x04, 0x4e, 0x8e, 0x79, 0xf9,
0x0a, 0xfc, 0x79, 0xb1, 0x5e, 0xb3, 0x60, 0xe3,
0x68, 0x7b, 0xc6, 0xef, 0xcb, 0x71, 0x4c, 0xba,
0xa7, 0x79, 0x5c, 0x7a, 0x81, 0xd1, 0x71, 0xe7,
0x00, 0x21, 0x13, 0xe2, 0x55, 0x69, 0x0e, 0x75,
0xbe, 0x09, 0xc3, 0x4f, 0xa9, 0xc9, 0x68, 0x22,
0x0e, 0x97, 0x8d, 0x89, 0x6e, 0xf1, 0xe8, 0x88,
0x7a, 0xd1, 0xd9, 0x09, 0x5d, 0xd3, 0x28, 0x78,
0x25, 0x0b, 0x1c, 0x47, 0x73, 0x25, 0xcc, 0x21,
0xb6, 0xda, 0xc6, 0x24, 0x5a, 0xd0, 0x37, 0x14,
0x46, 0xc7, 0x94, 0x69, 0xe4, 0x43, 0x6f, 0x47,
0xde, 0x00, 0x33, 0x4d, 0x8f, 0x95, 0x72, 0xfa,
0x68, 0x71, 0x17, 0x66, 0x12, 0x1a, 0x87, 0x27,
0xf7, 0xef, 0x7e, 0xe0, 0x35, 0x58, 0xf2, 0x4d,
0x6f, 0x35, 0x01, 0xaa, 0x96, 0xe2, 0x3d, 0x51,
0x13, 0x86, 0x9c, 0x79, 0xd0, 0xb7, 0xb6, 0x64,
0xe8, 0x86, 0x65, 0x50, 0xbf, 0xcc, 0x27, 0x53,
0x1f, 0x51, 0xd4, 0xca, 0xbe, 0xf5, 0xdd, 0x77,
0x70, 0x98, 0x0f, 0xee, 0xa8, 0x96, 0x07, 0x5f,
0x45, 0x6a, 0x7a, 0x0d, 0x03, 0x9c, 0x4f, 0x29,
0xf6, 0x06, 0xf3, 0x5d, 0x58, 0x6c, 0x47, 0xd0,
0x96, 0xa9, 0x03, 0x17, 0xbb, 0x4e, 0xc9, 0x21,
0xe0, 0xac, 0xcd, 0x78, 0x78, 0xb2, 0xfe, 0x81,
0xb2, 0x51, 0x53, 0xa6, 0x1f, 0x98, 0x45, 0x02,
0x81, 0x81, 0x00, 0xcf, 0x73, 0x8c, 0xbe, 0x6d,
0x45, 0x2d, 0x0c, 0x0b, 0x5d, 0x5c, 0x6c, 0x75,
0x78, 0xcc, 0x35, 0x48, 0xb6, 0x98, 0xf1, 0xb9,
0x64, 0x60, 0x8c, 0x43, 0xeb, 0x85, 0xab, 0x04,
0xb6, 0x7d, 0x1b, 0x71, 0x75, 0x06, 0xe2, 0xda,
0x84, 0x68, 0x2e, 0x7f, 0x4c, 0xe3, 0x73, 0xb4,
0xde, 0x51, 0x4b, 0xb6, 0x51, 0x86, 0x7b, 0xd0,
0xe6, 0x4d, 0xf3, 0xd1, 0xcf, 0x1a, 0xfe, 0x7f,
0x3a, 0x83, 0xba, 0xb3, 0xe1, 0xff, 0x54, 0x13,
0x93, 0xd7, 0x9c, 0x27, 0x80, 0xb7, 0x1e, 0x64,
0x9e, 0xf7, 0x32, 0x2b, 0x46, 0x29, 0xf7, 0xf8,
0x18, 0x6c, 0xf7, 0x4a, 0xbe, 0x4b, 0xee, 0x96,
0x90, 0x8f, 0xa2, 0x16, 0x22, 0x6a, 0xcc, 0x48,
0x06, 0x74, 0x63, 0x43, 0x7f, 0x27, 0x22, 0x44,
0x3c, 0x2d, 0x3b, 0x62, 0xf1, 0x1c, 0xb4, 0x27,
0x33, 0x85, 0x26, 0x60, 0x48, 0x16, 0xcb, 0xef,
0xf8, 0xcd, 0x37, 0x02, 0x81, 0x81, 0x00, 0xce,
0x15, 0x43, 0x6e, 0x4b, 0x0f, 0xf9, 0x3f, 0x87,
0xc3, 0x41, 0x45, 0x97, 0xb1, 0x49, 0xc2, 0x19,
0x23, 0x87, 0xe4, 0x24, 0x1c, 0x64, 0xe5, 0x28,
0xcb, 0x43, 0x10, 0x14, 0x14, 0x0e, 0x19, 0xcb,
0xbb, 0xdb, 0xfd, 0x11, 0x9d, 0x17, 0x68, 0x78,
0x6d, 0x61, 0x70, 0x63, 0x3a, 0xa1, 0xb3, 0xf3,
0xa7, 0x5b, 0x0e, 0xff, 0xb7, 0x61, 0x11, 0x54,
0x91, 0x99, 0xe5, 0x91, 0x32, 0x2d, 0xeb, 0x3f,
0xd8, 0x3e, 0xf7, 0xd4, 0xcb, 0xd2, 0xa3, 0x41,
0xc1, 0xee, 0xc6, 0x92, 0x13, 0xeb, 0x7f, 0x42,
0x58, 0xf4, 0xd0, 0xb2, 0x74, 0x1d, 0x8e, 0x87,
0x46, 0xcd, 0x14, 0xb8, 0x16, 0xad, 0xb5, 0xbd,
0x0d, 0x6c, 0x95, 0x5a, 0x16, 0xbf, 0xe9, 0x53,
0xda, 0xfb, 0xed, 0x83, 0x51, 0x67, 0xa9, 0x55,
0xab, 0x54, 0x02, 0x95, 0x20, 0xa6, 0x68, 0x17,
0x53, 0xa8, 0xea, 0x43, 0xe5, 0xb0, 0xa3, 0x02,
0x81, 0x80, 0x67, 0x9c, 0x32, 0x83, 0x39, 0x57,
0xff, 0x73, 0xb0, 0x89, 0x64, 0x8b, 0xd6, 0xf0,
0x0a, 0x2d, 0xe2, 0xaf, 0x30, 0x1c, 0x2a, 0x97,
0xf3, 0x90, 0x9a, 0xab, 0x9b, 0x0b, 0x1b, 0x43,
0x79, 0xa0, 0xa7, 0x3d, 0xe7, 0xbe, 0x8d, 0x9c,
0xeb, 0xdb, 0xad, 0x40, 0xdd, 0xa9, 0x00, 0x80,
0xb8, 0xe1, 0xb3, 0xa1, 0x6c, 0x25, 0x92, 0xe4,
0x33, 0xb2, 0xbe, 0xeb, 0x4d, 0x74, 0x26, 0x5f,
0x37, 0x43, 0x9c, 0x6c, 0x17, 0x76, 0x0a, 0x81,
0x20, 0x82, 0xa1, 0x48, 0x2c, 0x2d, 0x45, 0xdc,
0x0f, 0x62, 0x43, 0x32, 0xbb, 0xeb, 0x59, 0x41,
0xf9, 0xca, 0x58, 0xce, 0x4a, 0x66, 0x53, 0x54,
0xc8, 0x28, 0x10, 0x1e, 0x08, 0x71, 0x16, 0xd8,
0x02, 0x71, 0x41, 0x58, 0xd4, 0x56, 0xcc, 0xf5,
0xb1, 0x31, 0xa3, 0xed, 0x00, 0x85, 0x09, 0xbf,
0x35, 0x95, 0x41, 0x29, 0x40, 0x19, 0x83, 0x35,
0x24, 0x69, 0x02, 0x81, 0x80, 0x55, 0x10, 0x0b,
0xcc, 0x3b, 0xa9, 0x75, 0x3d, 0x16, 0xe1, 0xae,
0x50, 0x76, 0x63, 0x94, 0x49, 0x4c, 0xad, 0x10,
0xcb, 0x47, 0x68, 0x7c, 0xf0, 0xe5, 0xdc, 0xb8,
0x6a, 0xab, 0x8e, 0xf7, 0x9f, 0x08, 0x2c, 0x1b,
0x8a, 0xa2, 0xb9, 0x8f, 0xce, 0xec, 0x5e, 0x61,
0xa8, 0xcd, 0x1c, 0x87, 0x60, 0x4a, 0xc3, 0x1a,
0x5f, 0xdf, 0x87, 0x26, 0xc6, 0xcb, 0x7c, 0x69,
0xe4, 0x8b, 0x01, 0x06, 0x59, 0x22, 0xfa, 0x34,
0x4b, 0x81, 0x87, 0x3c, 0x03, 0x6d, 0x02, 0x0a,
0x77, 0xe6, 0x15, 0xd8, 0xcf, 0xa7, 0x68, 0x26,
0x6c, 0xfa, 0x2b, 0xd9, 0x83, 0x5a, 0x2d, 0x0c,
0x3b, 0x70, 0x1c, 0xd4, 0x48, 0xbe, 0xa7, 0x0a,
0xd9, 0xbe, 0xdc, 0xc3, 0x0c, 0x21, 0x33, 0xb3,
0x66, 0xff, 0x1c, 0x1b, 0xc8, 0x96, 0x76, 0xe8,
0x6f, 0x44, 0x74, 0xbc, 0x9b, 0x1c, 0x7d, 0xc8,
0xac, 0x21, 0xa8, 0x6e, 0x37, 0x02, 0x81, 0x80,
0x2c, 0x7c, 0xad, 0x1e, 0x75, 0xf6, 0x69, 0x1d,
0xe7, 0xa6, 0xca, 0x74, 0x7d, 0x67, 0xc8, 0x65,
0x28, 0x66, 0xc4, 0x43, 0xa6, 0xbd, 0x40, 0x57,
0xae, 0xb7, 0x65, 0x2c, 0x52, 0xf9, 0xe4, 0xc7,
0x81, 0x7b, 0x56, 0xa3, 0xd2, 0x0d, 0xe8, 0x33,
0x70, 0xcf, 0x06, 0x84, 0xb3, 0x4e, 0x44, 0x50,
0x75, 0x61, 0x96, 0x86, 0x4b, 0xb6, 0x2b, 0xad,
0xf0, 0xad, 0x57, 0xd0, 0x37, 0x0d, 0x1d, 0x35,
0x50, 0xcb, 0x69, 0x22, 0x39, 0x29, 0xb9, 0x3a,
0xd3, 0x29, 0x23, 0x02, 0x60, 0xf7, 0xab, 0x30,
0x40, 0xda, 0x8e, 0x4d, 0x45, 0x70, 0x26, 0xf4,
0xa2, 0x0d, 0xd0, 0x64, 0x5d, 0x47, 0x3c, 0x18,
0xf4, 0xd4, 0x52, 0x95, 0x00, 0xae, 0x84, 0x6b,
0x47, 0xb2, 0x3c, 0x82, 0xd3, 0x72, 0x53, 0xde,
0x72, 0x2c, 0xf7, 0xc1, 0x22, 0x36, 0xd9, 0x18,
0x56, 0xfe, 0x39, 0x28, 0x33, 0xe0, 0xdb, 0x03 };
// A 3072 bit RSA key in PKCS#8 PrivateKeyInfo format
// Used to verify the functions that manipulate RSA keys.
static const uint8_t kTestRSAPKCS8PrivateKeyInfo3_3072[] = {
0x30, 0x82, 0x06, 0xfe, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
0x06, 0xe8, 0x30, 0x82, 0x06, 0xe4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01,
0x81, 0x00, 0xe3, 0x32, 0x2f, 0x0a, 0x94, 0x06, 0x46, 0x99, 0x0a, 0x58,
0xda, 0xd0, 0x9b, 0x2b, 0xe4, 0x2a, 0x35, 0xdf, 0xb7, 0x9b, 0x5e, 0xbf,
0xfb, 0xe5, 0x24, 0x47, 0x5a, 0x94, 0x06, 0x04, 0xe5, 0x43, 0xed, 0x37,
0x33, 0x94, 0x09, 0xd0, 0xae, 0xad, 0x86, 0xb4, 0xc7, 0xc3, 0x56, 0x6f,
0x88, 0x74, 0xfb, 0xab, 0xf7, 0xcf, 0xcb, 0xa6, 0x89, 0x48, 0x4a, 0x02,
0x89, 0xcd, 0xfd, 0x83, 0x3d, 0x2a, 0x27, 0xc1, 0xa2, 0x99, 0x8e, 0xef,
0xcf, 0x91, 0xd3, 0xb2, 0x96, 0xe7, 0x5f, 0x0c, 0xb3, 0x44, 0x6a, 0xcf,
0xc1, 0x22, 0xb9, 0xe4, 0xd4, 0xc0, 0xf2, 0xc3, 0x8d, 0xe1, 0x43, 0x38,
0x31, 0x9c, 0x56, 0x04, 0xd4, 0x9d, 0x41, 0x02, 0x31, 0xce, 0x7e, 0xc0,
0x11, 0x24, 0x54, 0xb1, 0xa2, 0x99, 0x0e, 0xe2, 0x0c, 0x5b, 0x24, 0x94,
0x85, 0xe8, 0x8c, 0x30, 0xbb, 0x12, 0x94, 0x74, 0x0f, 0x67, 0xe5, 0x69,
0xa4, 0xc4, 0x59, 0xd6, 0x77, 0x96, 0xae, 0xc6, 0x00, 0xbe, 0xf5, 0xe6,
0x1f, 0x71, 0x90, 0x6d, 0xdd, 0xfb, 0x7b, 0x42, 0xd0, 0xdf, 0x4b, 0x58,
0xaf, 0x9c, 0xba, 0xcb, 0x35, 0x4b, 0xf3, 0x06, 0x3a, 0x20, 0x42, 0x97,
0x96, 0x95, 0x47, 0xbe, 0x2d, 0xeb, 0x9a, 0xb6, 0xea, 0xe0, 0xc1, 0x1d,
0x80, 0x61, 0x3e, 0x8e, 0x18, 0x66, 0xf4, 0x26, 0x77, 0xcf, 0x56, 0x27,
0x8b, 0xde, 0x93, 0x94, 0x3e, 0x1d, 0xe4, 0x5f, 0x6d, 0xf2, 0x39, 0x03,
0x15, 0x4f, 0x2e, 0x58, 0x59, 0x75, 0x19, 0xb9, 0x24, 0x87, 0xd4, 0xff,
0x64, 0x82, 0x11, 0x10, 0x34, 0x30, 0x09, 0x39, 0x43, 0x9c, 0xd2, 0x3b,
0x45, 0xdc, 0x85, 0x4f, 0x6d, 0xb7, 0xbb, 0x49, 0xda, 0x3b, 0x07, 0xa2,
0x76, 0x56, 0xa0, 0xee, 0xa9, 0xa9, 0x52, 0xb7, 0xf1, 0xfd, 0xde, 0xa1,
0x6f, 0x0e, 0x7f, 0x82, 0x3f, 0x9e, 0x3d, 0x46, 0xcd, 0x48, 0x55, 0xe8,
0x59, 0x65, 0xd8, 0xc7, 0xe4, 0x6b, 0xe6, 0xc0, 0xdd, 0x6e, 0x5c, 0xb7,
0x0c, 0xdb, 0x29, 0xad, 0x8e, 0xa4, 0x86, 0xe9, 0x4d, 0xad, 0x54, 0xf9,
0x56, 0x06, 0x0e, 0xc4, 0x2b, 0x01, 0xd9, 0x86, 0x1f, 0x65, 0xbe, 0x0d,
0x77, 0x8d, 0x9d, 0xff, 0x37, 0x97, 0x57, 0xc3, 0x06, 0x8a, 0x05, 0x80,
0x78, 0xd3, 0xbd, 0x91, 0xa5, 0xc1, 0x11, 0x4d, 0x99, 0x1a, 0x83, 0xd7,
0x30, 0x1c, 0x24, 0xac, 0xdf, 0x6c, 0xc1, 0x23, 0x60, 0x76, 0x54, 0xbf,
0x2b, 0xac, 0x34, 0xf0, 0x35, 0x92, 0x0d, 0x36, 0x29, 0x09, 0x24, 0xd5,
0x54, 0xe9, 0x68, 0x9c, 0x90, 0x07, 0x16, 0x86, 0xb1, 0xd0, 0x9b, 0xa5,
0x86, 0x4e, 0xce, 0xbf, 0x30, 0x9d, 0x91, 0xd7, 0xd2, 0xa6, 0x4f, 0xbb,
0xbb, 0x9d, 0x7c, 0x0f, 0x58, 0xaa, 0xf1, 0xd0, 0x90, 0x66, 0x20, 0x48,
0x8f, 0x29, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, 0x81, 0x00,
0x88, 0x41, 0x28, 0x85, 0x27, 0x91, 0x3b, 0xf5, 0xbc, 0x86, 0xdd, 0x74,
0x0e, 0x1b, 0x9c, 0x92, 0xd4, 0x0c, 0x7f, 0x88, 0xe6, 0xa2, 0x2c, 0xe7,
0x97, 0x82, 0x53, 0x88, 0x42, 0xb3, 0xdc, 0xeb, 0x87, 0xf0, 0x7b, 0x36,
0x65, 0x4c, 0x89, 0xf5, 0xf7, 0xbb, 0xa3, 0xb2, 0x3a, 0xbc, 0x59, 0x12,
0x0f, 0x7d, 0x6a, 0xf9, 0x6c, 0x21, 0x4c, 0x63, 0xd6, 0x3e, 0xff, 0x76,
0x52, 0x7b, 0xca, 0xca, 0xe5, 0x5c, 0xf3, 0xaf, 0x34, 0x52, 0x0e, 0x22,
0x5e, 0xdb, 0xd4, 0x34, 0x9e, 0x84, 0x77, 0x5e, 0xa8, 0xd0, 0x3f, 0xfc,
0x1b, 0x90, 0x69, 0x27, 0xee, 0x6f, 0xe9, 0x3f, 0x17, 0x99, 0x33, 0xe7,
0x96, 0x8e, 0xff, 0x13, 0xf0, 0x50, 0xe8, 0x9d, 0xf6, 0xd6, 0x29, 0x71,
0xa8, 0x79, 0x80, 0x12, 0x5b, 0x22, 0xa6, 0x56, 0x62, 0xf1, 0xcf, 0xfd,
0x4f, 0x56, 0x4a, 0x5b, 0x32, 0x3d, 0x08, 0xa0, 0x3e, 0xad, 0xc4, 0xeb,
0x1d, 0x15, 0xca, 0x52, 0xcc, 0x2e, 0x63, 0x74, 0x22, 0xf5, 0x08, 0x16,
0x8b, 0x8f, 0xd8, 0x79, 0x61, 0xcb, 0x08, 0x89, 0x62, 0x1e, 0xa5, 0xf3,
0x50, 0xf3, 0x5d, 0xdb, 0x56, 0xbc, 0x7d, 0x4f, 0xab, 0xa0, 0x4d, 0xe6,
0xe9, 0x47, 0xdd, 0x32, 0x57, 0x6f, 0x2c, 0x1d, 0xee, 0xb3, 0x4a, 0xb3,
0x07, 0x59, 0x20, 0xb9, 0x5d, 0xe3, 0x54, 0x27, 0x3c, 0x7c, 0x2b, 0x1d,
0x07, 0xff, 0x49, 0x93, 0xe2, 0xe3, 0xb2, 0x65, 0xf3, 0x69, 0xc1, 0x1c,
0x2a, 0x75, 0x80, 0x16, 0x37, 0xe6, 0x00, 0x5b, 0xd3, 0x1b, 0xac, 0xca,
0x8b, 0x8b, 0x98, 0x77, 0x81, 0x67, 0xe3, 0xdc, 0xbb, 0xc4, 0x3a, 0x45,
0x15, 0xec, 0xd9, 0xad, 0xdb, 0x60, 0xcf, 0xe5, 0xd8, 0xd9, 0xfc, 0xcf,
0xbe, 0x76, 0x2f, 0x5b, 0x60, 0xdb, 0x06, 0x62, 0x5b, 0x80, 0x7e, 0x53,
0xde, 0x74, 0xb1, 0xa3, 0xb6, 0x9b, 0x14, 0xd7, 0x09, 0x65, 0x21, 0x1d,
0xd5, 0xd3, 0x34, 0xca, 0x89, 0xe7, 0xbc, 0xf4, 0x48, 0x81, 0x6a, 0xcf,
0x28, 0xbe, 0x74, 0x8b, 0x40, 0xad, 0x86, 0xcd, 0xa5, 0xd6, 0xfa, 0x64,
0x9b, 0xd2, 0xd4, 0x17, 0x20, 0xd6, 0x0d, 0xbe, 0x95, 0xd4, 0xaf, 0xa5,
0xde, 0x31, 0x0d, 0x6a, 0x90, 0xc6, 0xd0, 0x59, 0xd4, 0x8c, 0x81, 0x2d,
0x9d, 0x09, 0xf1, 0x22, 0xf5, 0x30, 0x2d, 0xdf, 0x85, 0x54, 0x34, 0x8a,
0xde, 0x3c, 0xce, 0xdb, 0x36, 0x9f, 0xcf, 0x12, 0x61, 0x0e, 0x99, 0x87,
0x70, 0x51, 0x04, 0x91, 0x74, 0xc6, 0x88, 0x22, 0x75, 0x02, 0x8f, 0x7e,
0xb5, 0x79, 0x48, 0x2f, 0xf3, 0x3b, 0xb8, 0x82, 0x3e, 0x7e, 0x45, 0xe5,
0xb2, 0xc8, 0x4c, 0x12, 0x73, 0xb8, 0x92, 0x04, 0xd1, 0x9a, 0xae, 0xaa,
0x08, 0xd9, 0x23, 0x54, 0x19, 0x46, 0xc8, 0x56, 0x5f, 0x5e, 0x10, 0xa1,
0x02, 0x81, 0xc1, 0x00, 0xf6, 0x38, 0x88, 0x31, 0x06, 0x85, 0xd9, 0x00,
0xf0, 0x6b, 0xd8, 0x7d, 0x76, 0x08, 0xc0, 0x69, 0x6a, 0xfb, 0xa4, 0xc8,
0xdc, 0x6b, 0x00, 0xaf, 0xae, 0x52, 0x82, 0xe6, 0xba, 0xc9, 0x5e, 0xc9,
0xb7, 0x7f, 0xa1, 0xc4, 0xcb, 0xa0, 0xbc, 0x66, 0x3c, 0x55, 0x6a, 0xea,
0x6e, 0x42, 0xf1, 0x6b, 0xbd, 0xc4, 0xf2, 0x6b, 0x91, 0x11, 0x82, 0x20,
0xc2, 0xe6, 0x9e, 0x96, 0x5c, 0x9a, 0x7e, 0xb3, 0x57, 0x45, 0x9c, 0x42,
0x60, 0x4c, 0x04, 0x4f, 0x47, 0xfb, 0xa7, 0x68, 0x4e, 0x15, 0x43, 0x5a,
0x97, 0xb3, 0xfc, 0xd2, 0x91, 0x3c, 0x11, 0x5e, 0xaf, 0x57, 0x2a, 0xa1,
0x45, 0xa5, 0x60, 0xf0, 0xbe, 0x31, 0xe8, 0xc4, 0x0b, 0x35, 0xe3, 0x42,
0x9b, 0x22, 0x6b, 0xa3, 0x6c, 0x49, 0x71, 0x20, 0x34, 0x3f, 0x46, 0x0b,
0x79, 0xc9, 0xb8, 0xb4, 0xbd, 0x9c, 0xad, 0xd3, 0xd8, 0x7e, 0x95, 0x9f,
0x9a, 0xd4, 0x03, 0xe9, 0x5a, 0x54, 0x46, 0x94, 0x39, 0x55, 0xf1, 0x28,
0x0d, 0xd1, 0xaa, 0xc9, 0xf8, 0x28, 0x58, 0xef, 0xb0, 0x62, 0xb6, 0x2d,
0xc7, 0xd2, 0x09, 0x3a, 0x21, 0x0f, 0x7d, 0xa1, 0xb9, 0x59, 0xd5, 0xa7,
0x43, 0xa9, 0x51, 0xb7, 0xbf, 0x9d, 0xf3, 0x85, 0xec, 0xb3, 0xfb, 0x51,
0x61, 0xca, 0x81, 0x4d, 0xfa, 0xf1, 0xc3, 0x94, 0x37, 0x45, 0x91, 0xf0,
0x4b, 0xfc, 0x8e, 0xff, 0x02, 0x81, 0xc1, 0x00, 0xec, 0x38, 0x37, 0x3b,
0xba, 0x1b, 0x83, 0xaf, 0x3a, 0x00, 0xb9, 0x5e, 0x1f, 0xc8, 0xad, 0x57,
0xcf, 0x7c, 0xe2, 0x94, 0x95, 0xf1, 0xec, 0x0a, 0x4b, 0x40, 0xc4, 0x48,
0xfb, 0x47, 0x5f, 0x66, 0xc6, 0xf0, 0x70, 0x14, 0xe9, 0x08, 0xe4, 0x50,
0x29, 0x0a, 0x24, 0x57, 0x93, 0x97, 0x21, 0xd9, 0xfb, 0xc5, 0x52, 0x0a,
0x38, 0xb9, 0x68, 0xa3, 0x4f, 0x4b, 0xf8, 0xb8, 0x24, 0xef, 0x0c, 0x42,
0xda, 0x57, 0x32, 0x77, 0xed, 0x9c, 0x78, 0xeb, 0x10, 0x3e, 0x70, 0x67,
0xe9, 0x01, 0x03, 0x19, 0x19, 0xdb, 0x48, 0x9e, 0x1e, 0x52, 0x23, 0x88,
0xb6, 0x87, 0xb8, 0x0d, 0x2d, 0x0c, 0xfc, 0x90, 0x31, 0x9f, 0xa6, 0x96,
0x0a, 0xe1, 0x34, 0x72, 0x86, 0x0e, 0x49, 0x7c, 0xfe, 0x21, 0xaa, 0x25,
0xdd, 0x36, 0xbb, 0x1f, 0x85, 0xfe, 0x34, 0x18, 0xc2, 0x36, 0xa2, 0x7d,
0xee, 0xd9, 0x4f, 0x8e, 0xcb, 0x49, 0x8e, 0x7a, 0x43, 0x3c, 0x52, 0x73,
0x18, 0x60, 0xf6, 0xb7, 0x7a, 0xc4, 0x7a, 0x8a, 0x1c, 0xf0, 0xc9, 0x2e,
0xad, 0x54, 0xb1, 0x7b, 0x8e, 0xcb, 0x4d, 0xc2, 0xbc, 0x2a, 0x72, 0xfe,
0x61, 0x01, 0xd8, 0xff, 0x0a, 0x22, 0x6c, 0x51, 0x7e, 0x06, 0x9e, 0x9e,
0x3c, 0xe8, 0x31, 0x98, 0xf5, 0x08, 0x34, 0x7e, 0xfa, 0x08, 0xd1, 0x14,
0xdf, 0xfd, 0x26, 0x2f, 0x1f, 0x5a, 0x89, 0xd7, 0x02, 0x81, 0xc0, 0x76,
0xdd, 0xed, 0xe9, 0xf5, 0x23, 0x33, 0x13, 0x3f, 0xfe, 0x60, 0xa2, 0x99,
0x14, 0x3a, 0x87, 0xea, 0x0d, 0x18, 0x8d, 0x9b, 0xd3, 0xd0, 0x9d, 0xff,
0xc3, 0x77, 0xcc, 0x9a, 0x0a, 0x53, 0x47, 0x80, 0xde, 0x0e, 0x23, 0xea,
0xc6, 0x6b, 0x8d, 0xd3, 0xbc, 0xcd, 0x03, 0xe6, 0x3d, 0x4d, 0x3d, 0xdd,
0x7c, 0xb2, 0x27, 0xf9, 0xfe, 0x00, 0xdb, 0x7e, 0x1c, 0x46, 0x1d, 0x83,
0x11, 0x56, 0xef, 0x8f, 0xc7, 0x5c, 0x5b, 0xb3, 0x0f, 0x9f, 0xd9, 0x02,
0x80, 0x5c, 0x5e, 0x7f, 0xab, 0xc6, 0x3b, 0x7b, 0x17, 0x7a, 0x8b, 0xd1,
0x6f, 0xb5, 0x57, 0x07, 0xc1, 0x46, 0x24, 0x5b, 0x72, 0x2e, 0xad, 0xaa,
0xb4, 0x7f, 0x91, 0xfd, 0x73, 0x83, 0x86, 0x89, 0x4c, 0x81, 0xb8, 0x80,
0xb3, 0xa7, 0xf8, 0x8b, 0x20, 0xac, 0xd9, 0x27, 0x6f, 0x9a, 0x4b, 0x2f,
0x6a, 0xef, 0x84, 0x61, 0x75, 0x23, 0x18, 0xcd, 0x6f, 0x63, 0x80, 0x09,
0x8a, 0xbc, 0x14, 0x1c, 0xe5, 0xff, 0xa9, 0x7d, 0x9a, 0x66, 0x20, 0x61,
0x3c, 0x61, 0x4b, 0x3d, 0xd5, 0x39, 0xec, 0x3a, 0x16, 0x8d, 0x3b, 0xd1,
0xf0, 0x1f, 0x8f, 0xae, 0xe2, 0xce, 0xc1, 0x94, 0x69, 0xae, 0xb8, 0xcd,
0xba, 0x1c, 0x71, 0xe0, 0x47, 0x37, 0xa2, 0x1f, 0x5a, 0xdb, 0x37, 0xe1,
0x59, 0x4c, 0x39, 0x46, 0xc1, 0xc0, 0x65, 0xc8, 0xd9, 0x61, 0xd3, 0x02,
0x81, 0xc0, 0x2f, 0x63, 0xe7, 0xd0, 0xd7, 0xb9, 0x85, 0x65, 0xb6, 0x21,
0x47, 0x0f, 0x17, 0x19, 0x4f, 0x8d, 0x7a, 0x56, 0xf7, 0xae, 0x0f, 0x97,
0x05, 0x5f, 0xdb, 0x51, 0x17, 0x0f, 0xfd, 0x39, 0x88, 0x6e, 0x3a, 0x23,
0x2a, 0x99, 0x47, 0x57, 0x3d, 0x56, 0xc7, 0xa4, 0xfd, 0x3d, 0x84, 0xa2,
0xa1, 0x6b, 0xf6, 0x12, 0xd4, 0x2e, 0xb0, 0xca, 0xa1, 0xaf, 0x81, 0xcd,
0x20, 0x0c, 0xf1, 0x7b, 0xf3, 0xdd, 0xc5, 0xa8, 0x10, 0xbb, 0xf6, 0xb3,
0x99, 0x9e, 0xaf, 0x17, 0x97, 0xbd, 0x81, 0x05, 0x6e, 0xf5, 0xae, 0x36,
0x4c, 0x0f, 0x4c, 0xcd, 0xf5, 0xcb, 0x0b, 0xb3, 0x96, 0xbd, 0x2d, 0xf8,
0x99, 0x02, 0xe4, 0xb1, 0xbe, 0xde, 0x03, 0x38, 0xc3, 0x28, 0xe6, 0xb4,
0x1f, 0x12, 0x30, 0x79, 0xd8, 0x84, 0xd8, 0x28, 0x8e, 0xc9, 0xf8, 0x3b,
0xd3, 0x7f, 0xd4, 0x16, 0xd9, 0xea, 0xa1, 0xec, 0x7f, 0x05, 0x8a, 0xcb,
0x2b, 0x06, 0x64, 0x4e, 0xc9, 0xcb, 0xc5, 0x6c, 0x4e, 0x92, 0xe8, 0xd2,
0x5a, 0x33, 0x33, 0x33, 0x2b, 0x69, 0x6d, 0xe4, 0xbb, 0xe6, 0xa9, 0xf3,
0x27, 0x9a, 0x95, 0xdd, 0x7e, 0x4c, 0x82, 0x71, 0xb8, 0x73, 0x12, 0x39,
0x6d, 0xb9, 0xbb, 0xaa, 0xe0, 0x4f, 0xa6, 0xb0, 0x7e, 0xa2, 0xcd, 0x25,
0xe4, 0x42, 0x45, 0x2f, 0x57, 0xa2, 0xf4, 0x7c, 0xf9, 0x18, 0x23, 0x16,
0x2a, 0xe9, 0x02, 0x81, 0xc1, 0x00, 0xab, 0x35, 0x0d, 0x35, 0x94, 0x9d,
0x96, 0xb2, 0xb7, 0x45, 0x16, 0xef, 0xb7, 0xea, 0xba, 0xa4, 0x32, 0xec,
0x43, 0x05, 0xb0, 0x14, 0xbd, 0x9e, 0xd2, 0xbe, 0x0a, 0x0c, 0x4f, 0xca,
0x4f, 0xf3, 0x11, 0xb3, 0x1f, 0xdc, 0x04, 0x18, 0x38, 0x9d, 0xb0, 0x09,
0xb8, 0xf1, 0xcf, 0x7a, 0x89, 0x03, 0xd8, 0xed, 0x28, 0x30, 0xe8, 0xe6,
0xbc, 0x7c, 0x1c, 0x59, 0x12, 0xf8, 0x95, 0x9b, 0x36, 0xad, 0xf2, 0xea,
0x4a, 0x34, 0x00, 0xcf, 0x94, 0x3e, 0xeb, 0xff, 0xe2, 0x5b, 0x6c, 0x72,
0xe3, 0x04, 0xd1, 0x10, 0x2e, 0xdd, 0x18, 0x8d, 0x9a, 0x84, 0x93, 0x55,
0x4a, 0x80, 0x6c, 0xb5, 0x82, 0xc4, 0x16, 0x19, 0xc4, 0xba, 0xad, 0x2e,
0x40, 0x76, 0xb3, 0xc9, 0xd4, 0x26, 0x5d, 0xc9, 0xb1, 0x05, 0x0f, 0x1f,
0x7d, 0x59, 0x8c, 0x7b, 0xbe, 0x34, 0x09, 0x3e, 0x71, 0x0b, 0xc8, 0xf9,
0xb3, 0x77, 0x4e, 0x4b, 0xfb, 0xbf, 0x81, 0x55, 0xa4, 0x5e, 0xc6, 0xe9,
0xa1, 0xc3, 0x16, 0xff, 0xc8, 0x37, 0x88, 0xd5, 0x2d, 0xfb, 0x06, 0x98,
0xe9, 0x82, 0x1b, 0x5e, 0x1e, 0xdd, 0x48, 0x5d, 0x6c, 0x59, 0xee, 0x7a,
0xa6, 0xa4, 0x29, 0x41, 0x20, 0xb4, 0xcd, 0xf4, 0x58, 0x95, 0xfd, 0x7d,
0xbf, 0xfc, 0x83, 0xf5, 0xe1, 0x5a, 0x5d, 0xa8, 0x08, 0x66, 0xd8, 0xa0,
0x7f, 0xad, 0x7d, 0xcd, 0x22, 0x06
};
// A 2048 bit RSA key in PKCS#8 PrivateKeyInfo format.
// This is a different key from the one above.
static const uint8_t kTestRSAPKCS8PrivateKeyInfo4_2048[] = {
0x30, 0x82, 0x04, 0xbd, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
0x04, 0xa7, 0x30, 0x82, 0x04, 0xa3, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01,
0x01, 0x00, 0xc7, 0xfd, 0xa7, 0xca, 0x67, 0x15, 0xd1, 0x29, 0xea, 0xbc,
0x42, 0x9b, 0x02, 0x37, 0xbb, 0xfb, 0xb4, 0x72, 0x86, 0x76, 0x05, 0x20,
0x05, 0xcb, 0x94, 0x58, 0x79, 0x4a, 0x79, 0x68, 0xfe, 0xb4, 0x1d, 0x27,
0x87, 0x97, 0x22, 0xeb, 0x13, 0xb2, 0xb6, 0xed, 0xda, 0xb3, 0xc0, 0x63,
0x32, 0xd9, 0x31, 0x29, 0xb1, 0xb9, 0x97, 0x17, 0x67, 0x65, 0xd3, 0x9b,
0x8d, 0xf2, 0x73, 0x1c, 0x70, 0x08, 0xe5, 0x64, 0x9f, 0xcf, 0x5b, 0x52,
0x9e, 0x47, 0x51, 0xb0, 0xeb, 0x21, 0x81, 0xb4, 0x24, 0xc8, 0xd0, 0x42,
0xf3, 0xd4, 0x77, 0x1e, 0x96, 0x12, 0x2f, 0x74, 0xab, 0x06, 0xb2, 0x2e,
0xfa, 0xcd, 0x83, 0xcc, 0xbf, 0x02, 0x14, 0x34, 0x3c, 0x2c, 0x79, 0x7f,
0x60, 0x60, 0xd0, 0x68, 0x7e, 0x70, 0x32, 0xd4, 0x34, 0x73, 0x0a, 0x42,
0x7b, 0xbc, 0x69, 0xc0, 0xf8, 0xa6, 0xdc, 0x8f, 0x10, 0xda, 0x1c, 0xd4,
0x9d, 0x59, 0x23, 0xb4, 0x05, 0x32, 0xac, 0xcc, 0x54, 0xff, 0x35, 0xb3,
0x3f, 0x22, 0x1b, 0x8d, 0x9b, 0x6d, 0x76, 0xd7, 0xe5, 0xd1, 0xaa, 0x54,
0x01, 0xd9, 0x53, 0x88, 0x40, 0xb4, 0x7a, 0x3c, 0x2b, 0x47, 0x09, 0xcc,
0x50, 0xfa, 0x7a, 0x87, 0x56, 0x44, 0x28, 0x4b, 0x47, 0xc4, 0xee, 0x2e,
0x2a, 0xaa, 0xe7, 0x7a, 0xd6, 0x7f, 0xd3, 0xc5, 0xf8, 0x70, 0x14, 0x97,
0x64, 0x1c, 0x62, 0xdc, 0x42, 0xed, 0x90, 0x7d, 0x18, 0x36, 0xc2, 0xfa,
0xd2, 0xdf, 0xd5, 0x23, 0x5c, 0x5a, 0xfb, 0x84, 0xe1, 0xe3, 0x5d, 0x3a,
0x6a, 0x4e, 0x6a, 0x4b, 0xd9, 0x2d, 0xbd, 0xea, 0x88, 0x95, 0xc0, 0xb5,
0xf2, 0xd3, 0x37, 0x1f, 0xfe, 0xc7, 0x0a, 0x62, 0x33, 0x5b, 0x98, 0x36,
0x9d, 0x8d, 0x1a, 0x8e, 0x3a, 0xc5, 0x69, 0xe3, 0x2b, 0x95, 0x6e, 0xa6,
0xf6, 0x00, 0xc0, 0x9d, 0xa7, 0x39, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02,
0x82, 0x01, 0x00, 0x3e, 0x5b, 0x16, 0x80, 0x03, 0x58, 0x48, 0x19, 0x3b,
0xb9, 0x6b, 0x43, 0x0d, 0x93, 0xf7, 0x26, 0xea, 0x02, 0x73, 0x6e, 0x44,
0xf6, 0xd1, 0x17, 0xc2, 0xaf, 0x3b, 0x52, 0x3f, 0x3c, 0xbf, 0x7d, 0xc5,
0x41, 0x58, 0x03, 0x85, 0xbd, 0xaa, 0x2c, 0xa4, 0xe0, 0xd0, 0xba, 0x0f,
0x18, 0x5e, 0xf8, 0x5d, 0x5d, 0xd4, 0xae, 0x3b, 0x2f, 0xee, 0xeb, 0x4e,
0xe9, 0x47, 0x7e, 0xfa, 0xe9, 0x38, 0xfd, 0x6d, 0x18, 0xcc, 0xc3, 0x48,
0x84, 0x20, 0x19, 0xb8, 0x9c, 0xe3, 0x13, 0x55, 0x6f, 0xa7, 0xb0, 0x7d,
0x4f, 0x02, 0xdb, 0x92, 0x30, 0x95, 0x36, 0x22, 0x59, 0xcc, 0x21, 0x90,
0x59, 0x19, 0x96, 0x0e, 0xac, 0x3e, 0x3a, 0x15, 0xb6, 0x9b, 0xb4, 0x7a,
0x45, 0x7e, 0xf5, 0x70, 0xc5, 0xc3, 0xf6, 0x93, 0xc2, 0x9a, 0x7f, 0xec,
0x09, 0x02, 0xaf, 0xa2, 0x81, 0xaa, 0x85, 0xcc, 0x6b, 0x47, 0x23, 0x4d,
0x65, 0x7e, 0xd7, 0xa9, 0x0c, 0x37, 0x48, 0x83, 0xc8, 0x40, 0x60, 0x88,
0xfd, 0xeb, 0x31, 0xea, 0x65, 0xe3, 0xf6, 0xc5, 0x1d, 0x7b, 0xbd, 0xbc,
0x4b, 0x60, 0x27, 0xcb, 0xf1, 0xe2, 0xd9, 0x09, 0x03, 0xf3, 0xfe, 0xd8,
0x5c, 0xc1, 0x70, 0xdb, 0x0e, 0xdc, 0xc3, 0x7a, 0xb2, 0x41, 0x07, 0xf6,
0x85, 0x26, 0x31, 0xed, 0xa3, 0x36, 0x80, 0x08, 0x4f, 0xf7, 0x02, 0x37,
0x6e, 0x06, 0x9b, 0x1a, 0x76, 0x47, 0x62, 0x86, 0xdc, 0x33, 0xab, 0xcc,
0x88, 0x77, 0x1c, 0x15, 0x43, 0xac, 0x72, 0x46, 0x73, 0x6e, 0x77, 0x28,
0x82, 0x75, 0xa0, 0x2f, 0xd4, 0x96, 0x1b, 0x1e, 0x2e, 0x63, 0x66, 0x6c,
0x75, 0x4f, 0xaa, 0xd0, 0x2c, 0xcc, 0xd3, 0x65, 0x85, 0xbe, 0x87, 0x6a,
0x8e, 0x72, 0x65, 0x57, 0x64, 0xb5, 0x79, 0x71, 0x92, 0x7f, 0xe9, 0x80,
0x08, 0xa3, 0xa3, 0x2d, 0xc0, 0x49, 0x89, 0x02, 0x81, 0x81, 0x00, 0xee,
0x13, 0x86, 0xc3, 0x48, 0xb1, 0x4c, 0x7d, 0xe2, 0x31, 0x6c, 0x16, 0x37,
0x72, 0x6f, 0x33, 0x9d, 0x17, 0xe4, 0x20, 0x91, 0xa3, 0x75, 0x42, 0x19,
0xc1, 0xdb, 0x60, 0x90, 0x00, 0x4f, 0x04, 0x33, 0x88, 0xe1, 0xb8, 0x6f,
0xdf, 0xde, 0x71, 0x34, 0xb1, 0xc8, 0x45, 0x16, 0x20, 0xac, 0x83, 0xd2,
0xfe, 0x4c, 0x87, 0xb8, 0xdb, 0xfa, 0x42, 0x8e, 0xf5, 0x08, 0x03, 0x77,
0xb3, 0x07, 0x17, 0xb2, 0x9b, 0xd1, 0x8c, 0xe8, 0xdc, 0x61, 0xb8, 0x82,
0xf1, 0xe2, 0xa5, 0x46, 0xb1, 0xc1, 0x62, 0x1a, 0x9d, 0xf7, 0x44, 0x65,
0xda, 0xe3, 0xa0, 0xe5, 0xd5, 0x30, 0xca, 0x28, 0x07, 0x2f, 0xd7, 0xba,
0x99, 0x9f, 0x2a, 0x16, 0xc7, 0xe8, 0x98, 0x00, 0x7e, 0xd5, 0x53, 0x3c,
0x29, 0x8a, 0x52, 0xd0, 0x93, 0xbe, 0xf7, 0xa9, 0x3a, 0x6e, 0x07, 0x28,
0x44, 0x15, 0x6f, 0x20, 0x22, 0x52, 0xe3, 0x02, 0x81, 0x81, 0x00, 0xd7,
0x0c, 0x1a, 0x8e, 0x0a, 0x11, 0x60, 0x12, 0xb0, 0x62, 0xfb, 0x71, 0x21,
0xc0, 0x92, 0x65, 0x3d, 0xa4, 0x44, 0x1b, 0xbf, 0x17, 0x50, 0x45, 0xe6,
0x19, 0x5f, 0x95, 0xda, 0x56, 0x12, 0x79, 0xc7, 0xcd, 0x8f, 0x07, 0x31,
0x51, 0x93, 0xb7, 0x31, 0xd7, 0xc3, 0x09, 0x46, 0x8f, 0xfc, 0xd2, 0x1c,
0xcd, 0x3c, 0xbc, 0x87, 0x54, 0x9d, 0xe8, 0xa4, 0xc1, 0xb6, 0xa4, 0x68,
0x5e, 0xfd, 0x03, 0x78, 0xef, 0x69, 0xac, 0xd9, 0x0e, 0x00, 0x6f, 0x29,
0xe8, 0x2b, 0x54, 0x62, 0x7f, 0x83, 0xe5, 0x5f, 0x9d, 0x83, 0xe2, 0x01,
0x33, 0x33, 0x28, 0x39, 0x8f, 0x83, 0xaf, 0x6d, 0x60, 0xd5, 0x6f, 0xec,
0xdb, 0x74, 0x5b, 0x87, 0x6e, 0x32, 0xe5, 0x51, 0x95, 0xbe, 0x08, 0xa5,
0x8a, 0xf8, 0x92, 0x09, 0xe8, 0xae, 0xca, 0x95, 0x16, 0x44, 0x95, 0x84,
0x52, 0xd8, 0x67, 0x1d, 0x31, 0x8c, 0x33, 0x02, 0x81, 0x81, 0x00, 0xe7,
0x34, 0x05, 0x52, 0xce, 0xdc, 0x87, 0xf9, 0x54, 0x5a, 0x44, 0xaa, 0x8a,
0xac, 0x52, 0x3b, 0xe0, 0x9a, 0x9c, 0x0b, 0xd9, 0x03, 0xd1, 0xd3, 0x20,
0xaa, 0x77, 0xbe, 0x9d, 0xf9, 0xfe, 0xc2, 0x88, 0xbd, 0xac, 0xdf, 0x6d,
0x9e, 0x0e, 0x2b, 0x08, 0x4e, 0x82, 0xbc, 0x3d, 0x11, 0xfc, 0x17, 0x85,
0x27, 0x3a, 0xf1, 0x2f, 0x60, 0x49, 0xf8, 0xab, 0x56, 0x60, 0xb2, 0xe5,
0x62, 0xf2, 0x47, 0x5c, 0x48, 0x20, 0x47, 0xe4, 0xb8, 0x69, 0x1a, 0x43,
0xe8, 0x5d, 0xff, 0xbd, 0xd8, 0xd0, 0x81, 0xd2, 0x71, 0x87, 0xf9, 0x5f,
0xa5, 0x24, 0x1c, 0x54, 0x37, 0x26, 0xcb, 0x9b, 0xf5, 0xe6, 0xcb, 0x6d,
0x46, 0xd5, 0x20, 0x8d, 0xc1, 0x14, 0x2b, 0xd1, 0x87, 0x5a, 0xea, 0x1b,
0x6a, 0x08, 0x10, 0x06, 0xc9, 0x04, 0xd3, 0x05, 0x00, 0x5e, 0x6c, 0x0a,
0xf9, 0x9b, 0x8b, 0x30, 0xbc, 0xc4, 0x9b, 0x02, 0x81, 0x80, 0x20, 0x16,
0x83, 0x43, 0xdc, 0x86, 0xb9, 0x32, 0x30, 0xb5, 0xa4, 0x55, 0x3e, 0x37,
0x10, 0xe1, 0x20, 0x70, 0x89, 0x65, 0x26, 0x7f, 0x61, 0x0f, 0xfd, 0x04,
0x9e, 0x39, 0xab, 0x09, 0x9a, 0xda, 0x27, 0x11, 0x2a, 0x1d, 0x65, 0xa3,
0x89, 0x8a, 0x15, 0x5a, 0xdf, 0x94, 0x5b, 0xbe, 0x12, 0x78, 0x7b, 0xa9,
0xb8, 0x3d, 0x5d, 0x68, 0x27, 0xe3, 0xd5, 0xe9, 0xbd, 0xca, 0x0c, 0x74,
0xd8, 0x06, 0x13, 0x9e, 0x8d, 0xc3, 0x27, 0xe4, 0x29, 0xf6, 0x6c, 0x67,
0x63, 0x47, 0xc5, 0x26, 0xc7, 0xd4, 0x8b, 0x0e, 0xe2, 0xe5, 0xef, 0x4d,
0xe7, 0x7d, 0x42, 0x11, 0x83, 0x11, 0xc3, 0x1d, 0x66, 0xdb, 0xbb, 0x99,
0x07, 0x64, 0xbc, 0xf1, 0x99, 0x90, 0x94, 0x3a, 0xe6, 0xcf, 0x3d, 0x7c,
0x5e, 0x18, 0xd4, 0x77, 0xae, 0xd5, 0x35, 0xa7, 0xcb, 0xf6, 0x0f, 0x77,
0x99, 0x28, 0xd1, 0xb7, 0x59, 0xf7, 0x02, 0x81, 0x80, 0x43, 0x4d, 0xf6,
0xfe, 0x87, 0x20, 0xfb, 0x31, 0xc4, 0x00, 0x83, 0xa2, 0x66, 0x63, 0xa9,
0xed, 0x4c, 0xff, 0x79, 0xd3, 0xdc, 0x5d, 0x9d, 0xad, 0xa2, 0x03, 0x66,
0x1b, 0x97, 0xe0, 0x44, 0xd0, 0xc0, 0x5e, 0xf4, 0x5d, 0xe4, 0xc9, 0x2a,
0xa0, 0x6e, 0x1d, 0x2e, 0xb0, 0x23, 0xf4, 0x7b, 0x1c, 0xaa, 0x5d, 0x86,
0xb9, 0xf1, 0x93, 0xf8, 0x32, 0x09, 0x74, 0x53, 0xfe, 0x90, 0x24, 0xfc,
0x35, 0x1e, 0x7a, 0x0e, 0x4a, 0x3b, 0x1e, 0x58, 0x49, 0x3e, 0x7e, 0xc8,
0x8a, 0xb1, 0x1c, 0xb0, 0xe1, 0x35, 0x1b, 0x9e, 0xc5, 0x59, 0x7c, 0x32,
0x3a, 0xab, 0x24, 0x5a, 0xb7, 0x70, 0x27, 0xf9, 0x62, 0x4b, 0x89, 0x35,
0x20, 0x0d, 0x10, 0xea, 0x76, 0x24, 0x91, 0xe6, 0x64, 0x02, 0xbc, 0xba,
0xf7, 0x59, 0x16, 0xc7, 0x41, 0xc0, 0xb7, 0xa4, 0x6d, 0xa4, 0xb9, 0xe6,
0x61, 0x66, 0x42, 0xbf, 0xf0};
// This is an RSA key where e*d != 1 mod phi. Instead, it uses the carmicahel
// totient. That means e*d = 1 mod lambda, where lambda = lcm(p-1, q-1).
static const uint8_t kTestKeyRSACarmichael_2048[] = {
0x30, 0x82, 0x04, 0xbc, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
0x04, 0xa6, 0x30, 0x82, 0x04, 0xa2, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01,
0x01, 0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a,
0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd, 0xde,
0xa7, 0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e,
0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d, 0xb4,
0x4e, 0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3,
0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f, 0xce,
0x31, 0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb,
0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73, 0x9e,
0x39, 0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4,
0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13, 0x8b,
0x54, 0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda,
0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57, 0x54,
0x71, 0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03,
0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06, 0x51,
0x5a, 0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b,
0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8, 0x12,
0x7f, 0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01,
0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b, 0x3a,
0x77, 0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed,
0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d, 0xdb,
0x9c, 0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb,
0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02,
0x82, 0x01, 0x00, 0x0a, 0xf9, 0x4a, 0x19, 0x72, 0x88, 0x1b, 0x4e, 0xd8,
0x2f, 0xef, 0x99, 0x93, 0x32, 0xda, 0x51, 0x21, 0x2e, 0x14, 0x06, 0xf4,
0xe9, 0x65, 0x1c, 0xf9, 0xd4, 0xcf, 0x1a, 0x51, 0x53, 0xcd, 0x48, 0x33,
0x8c, 0x30, 0xed, 0xdd, 0x53, 0x6f, 0x29, 0x82, 0xf9, 0xe0, 0x74, 0xde,
0xb1, 0x13, 0x01, 0x88, 0x8f, 0xce, 0x14, 0xc1, 0x3b, 0x90, 0xb7, 0xcc,
0x6c, 0xdf, 0x35, 0xa1, 0xf2, 0x1a, 0x3d, 0xbe, 0x19, 0xd7, 0x0a, 0xe4,
0x67, 0x75, 0xbb, 0xfa, 0x87, 0xf4, 0x03, 0xb5, 0x7f, 0x69, 0xe4, 0x0b,
0x6a, 0xdc, 0x92, 0x82, 0x54, 0x64, 0x1a, 0x94, 0x2d, 0xe4, 0x63, 0x40,
0xb2, 0xb4, 0x85, 0x6b, 0xc8, 0x34, 0xba, 0xa2, 0x14, 0x30, 0x47, 0x1a,
0xeb, 0x90, 0x62, 0x30, 0x43, 0x44, 0x02, 0xc7, 0x0c, 0x30, 0xc0, 0x7f,
0xa9, 0x47, 0xae, 0xde, 0x68, 0x27, 0x92, 0xaa, 0x11, 0x95, 0xf5, 0x6f,
0xfc, 0x19, 0x8b, 0x49, 0xa0, 0x77, 0x9d, 0xc6, 0x13, 0x5d, 0x73, 0xff,
0x45, 0xa2, 0x4c, 0x3b, 0xf3, 0xe1, 0x2d, 0xd7, 0xc4, 0x70, 0xe2, 0x6c,
0x37, 0x99, 0x4c, 0x7a, 0xa9, 0x27, 0xf8, 0x3a, 0xd6, 0xfd, 0xc5, 0xd8,
0xfa, 0x2d, 0x0e, 0x71, 0x4b, 0x85, 0x7e, 0xce, 0xcb, 0x1c, 0x79, 0x71,
0xbd, 0xff, 0x63, 0x03, 0x6b, 0x58, 0x68, 0xe0, 0x14, 0xca, 0x5e, 0x85,
0xfd, 0xd0, 0xb7, 0xe0, 0x68, 0x14, 0xff, 0x2c, 0x82, 0x22, 0x26, 0x8a,
0x3f, 0xbf, 0xb0, 0x2a, 0x90, 0xff, 0xc7, 0x72, 0xfc, 0x66, 0x51, 0x3e,
0x51, 0x9f, 0x82, 0x68, 0x0e, 0xf3, 0x65, 0x74, 0x88, 0xab, 0xb7, 0xe5,
0x97, 0x5f, 0x0f, 0x3e, 0xe5, 0x3a, 0xbc, 0xa4, 0xa1, 0x50, 0xdd, 0x5c,
0x94, 0x4b, 0x0c, 0x70, 0x71, 0x48, 0x4e, 0xd0, 0xec, 0x46, 0x8f, 0xdf,
0xa2, 0x9a, 0xfe, 0xd8, 0x35, 0x1a, 0x2f, 0x02, 0x81, 0x81, 0x00, 0xcf,
0x73, 0x8c, 0xbe, 0x6d, 0x45, 0x2d, 0x0c, 0x0b, 0x5d, 0x5c, 0x6c, 0x75,
0x78, 0xcc, 0x35, 0x48, 0xb6, 0x98, 0xf1, 0xb9, 0x64, 0x60, 0x8c, 0x43,
0xeb, 0x85, 0xab, 0x04, 0xb6, 0x7d, 0x1b, 0x71, 0x75, 0x06, 0xe2, 0xda,
0x84, 0x68, 0x2e, 0x7f, 0x4c, 0xe3, 0x73, 0xb4, 0xde, 0x51, 0x4b, 0xb6,
0x51, 0x86, 0x7b, 0xd0, 0xe6, 0x4d, 0xf3, 0xd1, 0xcf, 0x1a, 0xfe, 0x7f,
0x3a, 0x83, 0xba, 0xb3, 0xe1, 0xff, 0x54, 0x13, 0x93, 0xd7, 0x9c, 0x27,
0x80, 0xb7, 0x1e, 0x64, 0x9e, 0xf7, 0x32, 0x2b, 0x46, 0x29, 0xf7, 0xf8,
0x18, 0x6c, 0xf7, 0x4a, 0xbe, 0x4b, 0xee, 0x96, 0x90, 0x8f, 0xa2, 0x16,
0x22, 0x6a, 0xcc, 0x48, 0x06, 0x74, 0x63, 0x43, 0x7f, 0x27, 0x22, 0x44,
0x3c, 0x2d, 0x3b, 0x62, 0xf1, 0x1c, 0xb4, 0x27, 0x33, 0x85, 0x26, 0x60,
0x48, 0x16, 0xcb, 0xef, 0xf8, 0xcd, 0x37, 0x02, 0x81, 0x81, 0x00, 0xce,
0x15, 0x43, 0x6e, 0x4b, 0x0f, 0xf9, 0x3f, 0x87, 0xc3, 0x41, 0x45, 0x97,
0xb1, 0x49, 0xc2, 0x19, 0x23, 0x87, 0xe4, 0x24, 0x1c, 0x64, 0xe5, 0x28,
0xcb, 0x43, 0x10, 0x14, 0x14, 0x0e, 0x19, 0xcb, 0xbb, 0xdb, 0xfd, 0x11,
0x9d, 0x17, 0x68, 0x78, 0x6d, 0x61, 0x70, 0x63, 0x3a, 0xa1, 0xb3, 0xf3,
0xa7, 0x5b, 0x0e, 0xff, 0xb7, 0x61, 0x11, 0x54, 0x91, 0x99, 0xe5, 0x91,
0x32, 0x2d, 0xeb, 0x3f, 0xd8, 0x3e, 0xf7, 0xd4, 0xcb, 0xd2, 0xa3, 0x41,
0xc1, 0xee, 0xc6, 0x92, 0x13, 0xeb, 0x7f, 0x42, 0x58, 0xf4, 0xd0, 0xb2,
0x74, 0x1d, 0x8e, 0x87, 0x46, 0xcd, 0x14, 0xb8, 0x16, 0xad, 0xb5, 0xbd,
0x0d, 0x6c, 0x95, 0x5a, 0x16, 0xbf, 0xe9, 0x53, 0xda, 0xfb, 0xed, 0x83,
0x51, 0x67, 0xa9, 0x55, 0xab, 0x54, 0x02, 0x95, 0x20, 0xa6, 0x68, 0x17,
0x53, 0xa8, 0xea, 0x43, 0xe5, 0xb0, 0xa3, 0x02, 0x81, 0x80, 0x67, 0x9c,
0x32, 0x83, 0x39, 0x57, 0xff, 0x73, 0xb0, 0x89, 0x64, 0x8b, 0xd6, 0xf0,
0x0a, 0x2d, 0xe2, 0xaf, 0x30, 0x1c, 0x2a, 0x97, 0xf3, 0x90, 0x9a, 0xab,
0x9b, 0x0b, 0x1b, 0x43, 0x79, 0xa0, 0xa7, 0x3d, 0xe7, 0xbe, 0x8d, 0x9c,
0xeb, 0xdb, 0xad, 0x40, 0xdd, 0xa9, 0x00, 0x80, 0xb8, 0xe1, 0xb3, 0xa1,
0x6c, 0x25, 0x92, 0xe4, 0x33, 0xb2, 0xbe, 0xeb, 0x4d, 0x74, 0x26, 0x5f,
0x37, 0x43, 0x9c, 0x6c, 0x17, 0x76, 0x0a, 0x81, 0x20, 0x82, 0xa1, 0x48,
0x2c, 0x2d, 0x45, 0xdc, 0x0f, 0x62, 0x43, 0x32, 0xbb, 0xeb, 0x59, 0x41,
0xf9, 0xca, 0x58, 0xce, 0x4a, 0x66, 0x53, 0x54, 0xc8, 0x28, 0x10, 0x1e,
0x08, 0x71, 0x16, 0xd8, 0x02, 0x71, 0x41, 0x58, 0xd4, 0x56, 0xcc, 0xf5,
0xb1, 0x31, 0xa3, 0xed, 0x00, 0x85, 0x09, 0xbf, 0x35, 0x95, 0x41, 0x29,
0x40, 0x19, 0x83, 0x35, 0x24, 0x69, 0x02, 0x81, 0x80, 0x55, 0x10, 0x0b,
0xcc, 0x3b, 0xa9, 0x75, 0x3d, 0x16, 0xe1, 0xae, 0x50, 0x76, 0x63, 0x94,
0x49, 0x4c, 0xad, 0x10, 0xcb, 0x47, 0x68, 0x7c, 0xf0, 0xe5, 0xdc, 0xb8,
0x6a, 0xab, 0x8e, 0xf7, 0x9f, 0x08, 0x2c, 0x1b, 0x8a, 0xa2, 0xb9, 0x8f,
0xce, 0xec, 0x5e, 0x61, 0xa8, 0xcd, 0x1c, 0x87, 0x60, 0x4a, 0xc3, 0x1a,
0x5f, 0xdf, 0x87, 0x26, 0xc6, 0xcb, 0x7c, 0x69, 0xe4, 0x8b, 0x01, 0x06,
0x59, 0x22, 0xfa, 0x34, 0x4b, 0x81, 0x87, 0x3c, 0x03, 0x6d, 0x02, 0x0a,
0x77, 0xe6, 0x15, 0xd8, 0xcf, 0xa7, 0x68, 0x26, 0x6c, 0xfa, 0x2b, 0xd9,
0x83, 0x5a, 0x2d, 0x0c, 0x3b, 0x70, 0x1c, 0xd4, 0x48, 0xbe, 0xa7, 0x0a,
0xd9, 0xbe, 0xdc, 0xc3, 0x0c, 0x21, 0x33, 0xb3, 0x66, 0xff, 0x1c, 0x1b,
0xc8, 0x96, 0x76, 0xe8, 0x6f, 0x44, 0x74, 0xbc, 0x9b, 0x1c, 0x7d, 0xc8,
0xac, 0x21, 0xa8, 0x6e, 0x37, 0x02, 0x81, 0x80, 0x2c, 0x7c, 0xad, 0x1e,
0x75, 0xf6, 0x69, 0x1d, 0xe7, 0xa6, 0xca, 0x74, 0x7d, 0x67, 0xc8, 0x65,
0x28, 0x66, 0xc4, 0x43, 0xa6, 0xbd, 0x40, 0x57, 0xae, 0xb7, 0x65, 0x2c,
0x52, 0xf9, 0xe4, 0xc7, 0x81, 0x7b, 0x56, 0xa3, 0xd2, 0x0d, 0xe8, 0x33,
0x70, 0xcf, 0x06, 0x84, 0xb3, 0x4e, 0x44, 0x50, 0x75, 0x61, 0x96, 0x86,
0x4b, 0xb6, 0x2b, 0xad, 0xf0, 0xad, 0x57, 0xd0, 0x37, 0x0d, 0x1d, 0x35,
0x50, 0xcb, 0x69, 0x22, 0x39, 0x29, 0xb9, 0x3a, 0xd3, 0x29, 0x23, 0x02,
0x60, 0xf7, 0xab, 0x30, 0x40, 0xda, 0x8e, 0x4d, 0x45, 0x70, 0x26, 0xf4,
0xa2, 0x0d, 0xd0, 0x64, 0x5d, 0x47, 0x3c, 0x18, 0xf4, 0xd4, 0x52, 0x95,
0x00, 0xae, 0x84, 0x6b, 0x47, 0xb2, 0x3c, 0x82, 0xd3, 0x72, 0x53, 0xde,
0x72, 0x2c, 0xf7, 0xc1, 0x22, 0x36, 0xd9, 0x18, 0x56, 0xfe, 0x39, 0x28,
0x33, 0xe0, 0xdb, 0x03,
};
// This is the same key as above, except the private key was chosen using the
// Euler totient.
static const uint8_t kTestKeyRSAEuler_2048[] = {
0x30, 0x82, 0x04, 0xbc, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
0x04, 0xa6, 0x30, 0x82, 0x04, 0xa2, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01,
0x01, 0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a,
0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd, 0xde,
0xa7, 0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e,
0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d, 0xb4,
0x4e, 0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3,
0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f, 0xce,
0x31, 0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb,
0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73, 0x9e,
0x39, 0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4,
0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13, 0x8b,
0x54, 0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda,
0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57, 0x54,
0x71, 0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03,
0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06, 0x51,
0x5a, 0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b,
0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8, 0x12,
0x7f, 0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01,
0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b, 0x3a,
0x77, 0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed,
0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d, 0xdb,
0x9c, 0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb,
0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02,
0x82, 0x01, 0x00, 0x5e, 0x79, 0x65, 0x49, 0xa5, 0x76, 0x79, 0xf9, 0x05,
0x45, 0x0f, 0xf4, 0x03, 0xbd, 0xa4, 0x7d, 0x29, 0xd5, 0xde, 0x33, 0x63,
0xd8, 0xb8, 0xac, 0x97, 0xeb, 0x3f, 0x5e, 0x55, 0xe8, 0x7d, 0xf3, 0xe7,
0x3b, 0x5c, 0x2d, 0x54, 0x67, 0x36, 0xd6, 0x1d, 0x46, 0xf5, 0xca, 0x2d,
0x8b, 0x3a, 0x7e, 0xdc, 0x45, 0x38, 0x79, 0x7e, 0x65, 0x71, 0x5f, 0x1c,
0x5e, 0x79, 0xb1, 0x40, 0xcd, 0xfe, 0xc5, 0xe1, 0xc1, 0x6b, 0x78, 0x04,
0x4e, 0x8e, 0x79, 0xf9, 0x0a, 0xfc, 0x79, 0xb1, 0x5e, 0xb3, 0x60, 0xe3,
0x68, 0x7b, 0xc6, 0xef, 0xcb, 0x71, 0x4c, 0xba, 0xa7, 0x79, 0x5c, 0x7a,
0x81, 0xd1, 0x71, 0xe7, 0x00, 0x21, 0x13, 0xe2, 0x55, 0x69, 0x0e, 0x75,
0xbe, 0x09, 0xc3, 0x4f, 0xa9, 0xc9, 0x68, 0x22, 0x0e, 0x97, 0x8d, 0x89,
0x6e, 0xf1, 0xe8, 0x88, 0x7a, 0xd1, 0xd9, 0x09, 0x5d, 0xd3, 0x28, 0x78,
0x25, 0x0b, 0x1c, 0x47, 0x73, 0x25, 0xcc, 0x21, 0xb6, 0xda, 0xc6, 0x24,
0x5a, 0xd0, 0x37, 0x14, 0x46, 0xc7, 0x94, 0x69, 0xe4, 0x43, 0x6f, 0x47,
0xde, 0x00, 0x33, 0x4d, 0x8f, 0x95, 0x72, 0xfa, 0x68, 0x71, 0x17, 0x66,
0x12, 0x1a, 0x87, 0x27, 0xf7, 0xef, 0x7e, 0xe0, 0x35, 0x58, 0xf2, 0x4d,
0x6f, 0x35, 0x01, 0xaa, 0x96, 0xe2, 0x3d, 0x51, 0x13, 0x86, 0x9c, 0x79,
0xd0, 0xb7, 0xb6, 0x64, 0xe8, 0x86, 0x65, 0x50, 0xbf, 0xcc, 0x27, 0x53,
0x1f, 0x51, 0xd4, 0xca, 0xbe, 0xf5, 0xdd, 0x77, 0x70, 0x98, 0x0f, 0xee,
0xa8, 0x96, 0x07, 0x5f, 0x45, 0x6a, 0x7a, 0x0d, 0x03, 0x9c, 0x4f, 0x29,
0xf6, 0x06, 0xf3, 0x5d, 0x58, 0x6c, 0x47, 0xd0, 0x96, 0xa9, 0x03, 0x17,
0xbb, 0x4e, 0xc9, 0x21, 0xe0, 0xac, 0xcd, 0x78, 0x78, 0xb2, 0xfe, 0x81,
0xb2, 0x51, 0x53, 0xa6, 0x1f, 0x98, 0x45, 0x02, 0x81, 0x81, 0x00, 0xcf,
0x73, 0x8c, 0xbe, 0x6d, 0x45, 0x2d, 0x0c, 0x0b, 0x5d, 0x5c, 0x6c, 0x75,
0x78, 0xcc, 0x35, 0x48, 0xb6, 0x98, 0xf1, 0xb9, 0x64, 0x60, 0x8c, 0x43,
0xeb, 0x85, 0xab, 0x04, 0xb6, 0x7d, 0x1b, 0x71, 0x75, 0x06, 0xe2, 0xda,
0x84, 0x68, 0x2e, 0x7f, 0x4c, 0xe3, 0x73, 0xb4, 0xde, 0x51, 0x4b, 0xb6,
0x51, 0x86, 0x7b, 0xd0, 0xe6, 0x4d, 0xf3, 0xd1, 0xcf, 0x1a, 0xfe, 0x7f,
0x3a, 0x83, 0xba, 0xb3, 0xe1, 0xff, 0x54, 0x13, 0x93, 0xd7, 0x9c, 0x27,
0x80, 0xb7, 0x1e, 0x64, 0x9e, 0xf7, 0x32, 0x2b, 0x46, 0x29, 0xf7, 0xf8,
0x18, 0x6c, 0xf7, 0x4a, 0xbe, 0x4b, 0xee, 0x96, 0x90, 0x8f, 0xa2, 0x16,
0x22, 0x6a, 0xcc, 0x48, 0x06, 0x74, 0x63, 0x43, 0x7f, 0x27, 0x22, 0x44,
0x3c, 0x2d, 0x3b, 0x62, 0xf1, 0x1c, 0xb4, 0x27, 0x33, 0x85, 0x26, 0x60,
0x48, 0x16, 0xcb, 0xef, 0xf8, 0xcd, 0x37, 0x02, 0x81, 0x81, 0x00, 0xce,
0x15, 0x43, 0x6e, 0x4b, 0x0f, 0xf9, 0x3f, 0x87, 0xc3, 0x41, 0x45, 0x97,
0xb1, 0x49, 0xc2, 0x19, 0x23, 0x87, 0xe4, 0x24, 0x1c, 0x64, 0xe5, 0x28,
0xcb, 0x43, 0x10, 0x14, 0x14, 0x0e, 0x19, 0xcb, 0xbb, 0xdb, 0xfd, 0x11,
0x9d, 0x17, 0x68, 0x78, 0x6d, 0x61, 0x70, 0x63, 0x3a, 0xa1, 0xb3, 0xf3,
0xa7, 0x5b, 0x0e, 0xff, 0xb7, 0x61, 0x11, 0x54, 0x91, 0x99, 0xe5, 0x91,
0x32, 0x2d, 0xeb, 0x3f, 0xd8, 0x3e, 0xf7, 0xd4, 0xcb, 0xd2, 0xa3, 0x41,
0xc1, 0xee, 0xc6, 0x92, 0x13, 0xeb, 0x7f, 0x42, 0x58, 0xf4, 0xd0, 0xb2,
0x74, 0x1d, 0x8e, 0x87, 0x46, 0xcd, 0x14, 0xb8, 0x16, 0xad, 0xb5, 0xbd,
0x0d, 0x6c, 0x95, 0x5a, 0x16, 0xbf, 0xe9, 0x53, 0xda, 0xfb, 0xed, 0x83,
0x51, 0x67, 0xa9, 0x55, 0xab, 0x54, 0x02, 0x95, 0x20, 0xa6, 0x68, 0x17,
0x53, 0xa8, 0xea, 0x43, 0xe5, 0xb0, 0xa3, 0x02, 0x81, 0x80, 0x67, 0x9c,
0x32, 0x83, 0x39, 0x57, 0xff, 0x73, 0xb0, 0x89, 0x64, 0x8b, 0xd6, 0xf0,
0x0a, 0x2d, 0xe2, 0xaf, 0x30, 0x1c, 0x2a, 0x97, 0xf3, 0x90, 0x9a, 0xab,
0x9b, 0x0b, 0x1b, 0x43, 0x79, 0xa0, 0xa7, 0x3d, 0xe7, 0xbe, 0x8d, 0x9c,
0xeb, 0xdb, 0xad, 0x40, 0xdd, 0xa9, 0x00, 0x80, 0xb8, 0xe1, 0xb3, 0xa1,
0x6c, 0x25, 0x92, 0xe4, 0x33, 0xb2, 0xbe, 0xeb, 0x4d, 0x74, 0x26, 0x5f,
0x37, 0x43, 0x9c, 0x6c, 0x17, 0x76, 0x0a, 0x81, 0x20, 0x82, 0xa1, 0x48,
0x2c, 0x2d, 0x45, 0xdc, 0x0f, 0x62, 0x43, 0x32, 0xbb, 0xeb, 0x59, 0x41,
0xf9, 0xca, 0x58, 0xce, 0x4a, 0x66, 0x53, 0x54, 0xc8, 0x28, 0x10, 0x1e,
0x08, 0x71, 0x16, 0xd8, 0x02, 0x71, 0x41, 0x58, 0xd4, 0x56, 0xcc, 0xf5,
0xb1, 0x31, 0xa3, 0xed, 0x00, 0x85, 0x09, 0xbf, 0x35, 0x95, 0x41, 0x29,
0x40, 0x19, 0x83, 0x35, 0x24, 0x69, 0x02, 0x81, 0x80, 0x55, 0x10, 0x0b,
0xcc, 0x3b, 0xa9, 0x75, 0x3d, 0x16, 0xe1, 0xae, 0x50, 0x76, 0x63, 0x94,
0x49, 0x4c, 0xad, 0x10, 0xcb, 0x47, 0x68, 0x7c, 0xf0, 0xe5, 0xdc, 0xb8,
0x6a, 0xab, 0x8e, 0xf7, 0x9f, 0x08, 0x2c, 0x1b, 0x8a, 0xa2, 0xb9, 0x8f,
0xce, 0xec, 0x5e, 0x61, 0xa8, 0xcd, 0x1c, 0x87, 0x60, 0x4a, 0xc3, 0x1a,
0x5f, 0xdf, 0x87, 0x26, 0xc6, 0xcb, 0x7c, 0x69, 0xe4, 0x8b, 0x01, 0x06,
0x59, 0x22, 0xfa, 0x34, 0x4b, 0x81, 0x87, 0x3c, 0x03, 0x6d, 0x02, 0x0a,
0x77, 0xe6, 0x15, 0xd8, 0xcf, 0xa7, 0x68, 0x26, 0x6c, 0xfa, 0x2b, 0xd9,
0x83, 0x5a, 0x2d, 0x0c, 0x3b, 0x70, 0x1c, 0xd4, 0x48, 0xbe, 0xa7, 0x0a,
0xd9, 0xbe, 0xdc, 0xc3, 0x0c, 0x21, 0x33, 0xb3, 0x66, 0xff, 0x1c, 0x1b,
0xc8, 0x96, 0x76, 0xe8, 0x6f, 0x44, 0x74, 0xbc, 0x9b, 0x1c, 0x7d, 0xc8,
0xac, 0x21, 0xa8, 0x6e, 0x37, 0x02, 0x81, 0x80, 0x2c, 0x7c, 0xad, 0x1e,
0x75, 0xf6, 0x69, 0x1d, 0xe7, 0xa6, 0xca, 0x74, 0x7d, 0x67, 0xc8, 0x65,
0x28, 0x66, 0xc4, 0x43, 0xa6, 0xbd, 0x40, 0x57, 0xae, 0xb7, 0x65, 0x2c,
0x52, 0xf9, 0xe4, 0xc7, 0x81, 0x7b, 0x56, 0xa3, 0xd2, 0x0d, 0xe8, 0x33,
0x70, 0xcf, 0x06, 0x84, 0xb3, 0x4e, 0x44, 0x50, 0x75, 0x61, 0x96, 0x86,
0x4b, 0xb6, 0x2b, 0xad, 0xf0, 0xad, 0x57, 0xd0, 0x37, 0x0d, 0x1d, 0x35,
0x50, 0xcb, 0x69, 0x22, 0x39, 0x29, 0xb9, 0x3a, 0xd3, 0x29, 0x23, 0x02,
0x60, 0xf7, 0xab, 0x30, 0x40, 0xda, 0x8e, 0x4d, 0x45, 0x70, 0x26, 0xf4,
0xa2, 0x0d, 0xd0, 0x64, 0x5d, 0x47, 0x3c, 0x18, 0xf4, 0xd4, 0x52, 0x95,
0x00, 0xae, 0x84, 0x6b, 0x47, 0xb2, 0x3c, 0x82, 0xd3, 0x72, 0x53, 0xde,
0x72, 0x2c, 0xf7, 0xc1, 0x22, 0x36, 0xd9, 0x18, 0x56, 0xfe, 0x39, 0x28,
0x33, 0xe0, 0xdb, 0x03,
};
static const uint8_t kTestSandbox[] = { 0x01, 0x02, 0x03 };
} // namespace wvoec
#endif // CDM_OEC_TEST_DATA_H_

View File

@@ -0,0 +1,34 @@
/* Copyright 2020 Google LLC. All rights reserved. This file and proprietary */
/* source code may only be used and distributed under the Widevine Master */
/* License Agreement. */
#include "oemcrypto_corpus_generator_helper.h"
#include <fstream>
#include <iostream>
namespace wvoec {
bool g_generate_corpus;
void AppendToFile(const std::string& file_name, const char* message,
const size_t message_size) {
std::ofstream filebuf(file_name.c_str(), std::ios::app | std::ios::binary);
if (!filebuf) {
std::cout << "Cannot open file " << file_name.c_str() << std::endl;
}
filebuf.write(message, message_size);
filebuf.close();
}
std::string GetFileName(const char* directory) {
std::string file_name(PATH_TO_CORPUS);
file_name += directory;
file_name += "/";
file_name += std::to_string(rand());
return file_name;
}
void SetGenerateCorpus(bool should_generate_corpus) {
g_generate_corpus = should_generate_corpus;
}
bool ShouldGenerateCorpus() { return g_generate_corpus; }
} // namespace wvoec

View File

@@ -0,0 +1,25 @@
/* Copyright 2020 Google LLC. All rights reserved. This file and proprietary */
/* source code may only be used and distributed under the Widevine Master */
/* License Agreement. */
#ifndef CDM_OEMCRYPTO_CORPUS_GENERATOR_HELPER_H_
#define CDM_OEMCRYPTO_CORPUS_GENERATOR_HELPER_H_
#define PATH_TO_CORPUS "./oemcrypto/test/fuzz_tests/corpus/"
#include <stdio.h>
#include <stdlib.h>
#include <string>
namespace wvoec {
void AppendToFile(const std::string& file_name, const char* message,
const size_t message_size);
std::string GetFileName(const char* directory);
void SetGenerateCorpus(bool should_generate_corpus);
// Output of this function decides if binary data needs to be written
// to corpus files or not. Controlled by --generate_corpus flag.
bool ShouldGenerateCorpus();
} // namespace wvoec
#endif // CDM_OEMCRYPTO_CORPUS_GENERATOR_HELPER_H_

View File

@@ -0,0 +1,86 @@
#include "oemcrypto_session_tests_helper.h"
#include <gtest/gtest.h>
#include "oec_test_data.h"
using namespace std;
using namespace wvoec;
namespace wvoec {
// Make this function available when in Fuzz mode because we are not inheriting
// from OEMCryptoClientTest.
const uint8_t* find(const vector<uint8_t>& message,
const vector<uint8_t>& substring) {
vector<uint8_t>::const_iterator pos = search(
message.begin(), message.end(), substring.begin(), substring.end());
if (pos == message.end()) {
return nullptr;
}
return &(*pos);
}
// This creates a wrapped RSA key.
void SessionUtil::CreateWrappedRSAKey() {
Session s;
ProvisioningRoundTrip provisioning_messages(&s, 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());
ASSERT_EQ(OEMCrypto_SUCCESS, provisioning_messages.LoadResponse());
wrapped_rsa_key_ = provisioning_messages.wrapped_rsa_key();
}
void SessionUtil::InstallKeybox(const wvoec::WidevineKeybox& keybox,
bool good) {
uint8_t wrapped[sizeof(wvoec::WidevineKeybox)];
size_t length = sizeof(wvoec::WidevineKeybox);
keybox_ = keybox;
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_WrapKeybox(reinterpret_cast<const uint8_t*>(&keybox),
sizeof(keybox), wrapped, &length, nullptr, 0));
OEMCryptoResult sts = OEMCrypto_InstallKeybox(wrapped, sizeof(keybox));
if (good) {
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
} else {
// Can return error now, or return error on IsKeyboxValid.
}
}
void SessionUtil::EnsureTestKeys() {
switch (global_features.derive_key_method) {
case DeviceFeatures::LOAD_TEST_KEYBOX:
keybox_ = kTestKeybox;
ASSERT_EQ(
OEMCrypto_SUCCESS,
OEMCrypto_LoadTestKeybox(reinterpret_cast<const uint8_t*>(&keybox_),
sizeof(keybox_)));
break;
case DeviceFeatures::LOAD_TEST_RSA_KEY:
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadTestRSAKey());
break;
case DeviceFeatures::TEST_PROVISION_30:
// Can use oem certificate to install test rsa key.
break;
default:
FAIL() << "Cannot run test without test keybox or RSA key installed.";
}
}
// This makes sure that the derived keys (encryption key and two mac keys)
// are installed in OEMCrypto and in the test session.
void SessionUtil::InstallTestRSAKey(Session* s) {
if (global_features.loads_certificate) {
if (wrapped_rsa_key_.size() == 0) {
// If we don't have a wrapped key yet, create one.
// This wrapped key will be shared by all sessions in the test.
ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey());
}
// Load the wrapped rsa test key.
ASSERT_NO_FATAL_FAILURE(s->InstallRSASessionTestKey(wrapped_rsa_key_));
}
// Test RSA key should be loaded.
ASSERT_NO_FATAL_FAILURE(s->PreparePublicKey());
}
} // namespace wvoec

View File

@@ -0,0 +1,38 @@
#include <assert.h>
#include <algorithm>
#include <iostream>
#include <openssl/aes.h>
#include <openssl/rand.h>
#include "oec_session_util.h"
#include "oec_test_data.h"
#include "OEMCryptoCAS.h"
namespace wvoec {
class SessionUtil {
public:
SessionUtil()
: encoded_rsa_key_(kTestRSAPKCS8PrivateKeyInfo2_2048,
kTestRSAPKCS8PrivateKeyInfo2_2048 +
sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048)) {}
// Create a new wrapped DRM Certificate.
void CreateWrappedRSAKey();
// This is used to force installation of a keybox. This overwrites the
// production keybox -- it does NOT use OEMCrypto_LoadTestKeybox.
void InstallKeybox(const wvoec::WidevineKeybox& keybox, bool good);
// This loads the test keybox or the test RSA key, using LoadTestKeybox or
// LoadTestRSAKey as needed.
void EnsureTestKeys();
void InstallTestRSAKey(Session* s);
std::vector<uint8_t> encoded_rsa_key_;
std::vector<uint8_t> wrapped_rsa_key_;
wvoec::WidevineKeybox keybox_;
};
} // namespace wvoec

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,161 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// OEMCrypto unit tests - extra tests required for Android platform.
//
// The Widevine CDM system can be built on many platforms, with different
// capabilities. For example, some platforms do not require usage tables,
// and some can have a pre-installed certificate and do not need a keybox.
// On Android, these features are not optional. This set of unit tests
// verify that these features are implemented.
//
// In the file oemcrypto_test.cpp, the unit tests only verify correct
// functionality for functions that are implemented. Android devices must pass
// unit tests in both files.
#include <gtest/gtest.h>
#include "oec_test_data.h"
#include "OEMCryptoCAS.h"
namespace wvoec {
// These tests are required for LollyPop Android devices.
class OEMCryptoAndroidLMPTest : public ::testing::Test {
protected:
void SetUp() override {
OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox));
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize());
}
void TearDown() override { OEMCrypto_Terminate(); }
};
// Android devices must have a keybox, or use provisioning 3.0.
TEST_F(OEMCryptoAndroidLMPTest, GetKeyDataImplemented) {
uint8_t key_data[256];
size_t key_data_len = sizeof(key_data);
if (OEMCrypto_Keybox == OEMCrypto_GetProvisioningMethod()) {
ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED,
OEMCrypto_GetKeyData(key_data, &key_data_len));
} else {
ASSERT_EQ(OEMCrypto_OEMCertificate, OEMCrypto_GetProvisioningMethod());
}
}
// Android devices must have a valid keybox.
TEST_F(OEMCryptoAndroidLMPTest, ValidKeybox) {
if (OEMCrypto_GetProvisioningMethod() == OEMCrypto_Keybox) {
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_IsKeyboxValid());
}
}
TEST_F(OEMCryptoAndroidLMPTest, MinVersionNumber9) {
uint32_t version = OEMCrypto_APIVersion();
ASSERT_LE(9u, version);
}
TEST_F(OEMCryptoAndroidLMPTest, ValidKeyboxTest) {
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_IsKeyboxValid());
}
TEST_F(OEMCryptoAndroidLMPTest, RewrapDeviceRSAKeyImplemented) {
ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED,
OEMCrypto_LoadProvisioning(0, nullptr, 0, 0, nullptr, 0, nullptr,
nullptr));
}
// The Generic Crypto API functions are required for Android.
TEST_F(OEMCryptoAndroidLMPTest, GenericCryptoImplemented) {
ASSERT_NE(
OEMCrypto_ERROR_NOT_IMPLEMENTED,
OEMCrypto_Generic_Encrypt(0, nullptr, 0, nullptr,
OEMCrypto_AES_CBC_128_NO_PADDING, nullptr));
ASSERT_NE(
OEMCrypto_ERROR_NOT_IMPLEMENTED,
OEMCrypto_Generic_Decrypt(0, nullptr, 0, nullptr,
OEMCrypto_AES_CBC_128_NO_PADDING, nullptr));
ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED,
OEMCrypto_Generic_Sign(0, nullptr, 0, OEMCrypto_HMAC_SHA256,
nullptr, nullptr));
ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED,
OEMCrypto_Generic_Verify(0, nullptr, 0, OEMCrypto_HMAC_SHA256,
nullptr, 0));
}
// Android requires support of usage table. The usage table is used for Secure
// Stops and for offline licenses.
TEST_F(OEMCryptoAndroidLMPTest, SupportsUsageTable) {
ASSERT_TRUE(OEMCrypto_SupportsUsageTable());
}
// Android devices require L1 OEMCrypto.
TEST_F(OEMCryptoAndroidLMPTest, Level1Required) {
const char* char_level = OEMCrypto_SecurityLevel();
std::string security_level(char_level ? char_level : "");
EXPECT_EQ("L1", security_level)
<< "The security level is " << security_level << ". but we expect L1.\n"
<< "If you are testing a device that should be L3 or L2, please\n"
<< "repeat the tests with the flag --gtest_filter=\"*-*Level1Required\"";
}
// These tests are required for M Android devices.
class OEMCryptoAndroidMNCTest : public OEMCryptoAndroidLMPTest {};
TEST_F(OEMCryptoAndroidMNCTest, MinVersionNumber10) {
uint32_t version = OEMCrypto_APIVersion();
ASSERT_GE(version, 10u);
}
// Android devices using Provisioning 2.0 must be able to load a test keybox.
// If they are not using Provisioning 2.0, then they must use Provisioning 3.0.
TEST_F(OEMCryptoAndroidMNCTest, LoadsTestKeyboxImplemented) {
if (OEMCrypto_Keybox == OEMCrypto_GetProvisioningMethod()) {
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadTestKeybox(
reinterpret_cast<const uint8_t*>(&kTestKeybox),
sizeof(kTestKeybox)));
} else {
// Android should use keybox or provisioning 3.0.
ASSERT_EQ(OEMCrypto_OEMCertificate, OEMCrypto_GetProvisioningMethod());
}
}
// Android requires implementation of these functions.
TEST_F(OEMCryptoAndroidMNCTest, NumberOfSessionsImplemented) {
ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED,
OEMCrypto_GetNumberOfOpenSessions(nullptr));
ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED,
OEMCrypto_GetMaxNumberOfSessions(nullptr));
}
// Android requires implementation of these functions.
TEST_F(OEMCryptoAndroidMNCTest, QueryKeyControlImplemented) {
ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED,
OEMCrypto_QueryKeyControl(0, nullptr, 0, nullptr, nullptr));
}
// These tests are required for N Android devices.
class OEMCryptoAndroidNYCTest : public OEMCryptoAndroidMNCTest {};
TEST_F(OEMCryptoAndroidNYCTest, MinVersionNumber11) {
uint32_t version = OEMCrypto_APIVersion();
ASSERT_GE(version, 11u);
}
// These tests are required for O MR1 Android devices.
class OEMCryptoAndroidOCTest : public OEMCryptoAndroidNYCTest {};
TEST_F(OEMCryptoAndroidOCTest, MinVersionNumber13) {
uint32_t version = OEMCrypto_APIVersion();
ASSERT_GE(version, 13u);
}
// These tests are required for Q Android devices.
class OEMCryptoAndroidQTest : public OEMCryptoAndroidOCTest {};
TEST_F(OEMCryptoAndroidQTest, MinVersionNumber14) {
uint32_t version = OEMCrypto_APIVersion();
ASSERT_GE(version, 15u);
}
} // namespace wvoec

View File

@@ -0,0 +1,59 @@
#include <gtest/gtest.h>
#include <iostream>
#include "OEMCryptoCAS.h"
#include "log.h"
#include "oec_device_features.h"
#include "oemcrypto_corpus_generator_helper.h"
#include "test_sleep.h"
static void acknowledge_cast() {
std::cout
<< "==================================================================\n"
<< "= This device is expected to load x509 certs as a cast receiver. =\n"
<< "==================================================================\n";
}
// This special main procedure is used instead of the standard GTest main,
// because we need to initialize the list of features supported by the device.
// Also, the test filter is updated based on the feature list.
int main(int argc, char** argv) {
bool is_cast_receiver = false;
bool filter_tests = true;
int verbosity = 0;
// Skip the first element, which is the program name.
const std::vector<std::string> args(argv + 1, argv + argc);
for (const std::string& arg : args) {
if (arg == "--generate_corpus") {
wvoec::SetGenerateCorpus(true);
}
if (arg == "--verbose" || arg == "-v") {
++verbosity;
} else if (arg == "--cast") {
acknowledge_cast();
is_cast_receiver = true;
}
if (arg == "--force_load_test_keybox") {
std::cerr << "The argument --force_load_test_keybox is obsolete.\n";
return 1;
}
if (arg == "--no_filter") {
filter_tests = false;
}
if (arg == "--fake_sleep") {
wvutil::TestSleep::set_real_sleep(false);
}
}
wvutil::g_cutoff = static_cast<wvutil::LogPriority>(verbosity);
wvoec::global_features.Initialize();
wvoec::global_features.set_cast_receiver(is_cast_receiver);
// Init GTest after device properties has been initialized.
::testing::InitGoogleTest(&argc, argv);
// If the user requests --no_filter, we don't change the filter, otherwise, we
// filter out features that are not supported.
if (filter_tests) {
::testing::GTEST_FLAG(filter) =
wvoec::global_features.RestrictFilter(::testing::GTEST_FLAG(filter));
}
return RUN_ALL_TESTS();
}

View File

@@ -0,0 +1,148 @@
// Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#include "test_sleep.h"
#ifdef _WIN32
# include <windows.h>
#else
# include <sys/types.h>
#endif
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <chrono>
#include "clock.h"
#include "log.h"
namespace wvutil {
bool TestSleep::real_sleep_ = true;
TestSleep::CallBack* TestSleep::callback_ = nullptr;
int TestSleep::total_clock_rollback_ = 0;
void TestSleep::Sleep(unsigned int seconds) {
int64_t milliseconds = 1000 * seconds;
if (real_sleep_) {
// This next bit of logic is to avoid slow drift apart of the real clock and
// the fake clock. We compute how far from the real clock has advanced in
// total since the start, and then compare to a running total of sleep
// calls. We sleep for approximately x second, and then advance the clock by
// the amount of time that has actually passed.
static auto start_real = std::chrono::system_clock().now();
static int64_t fake_clock = 0;
sleep(seconds);
auto now_real = std::chrono::system_clock().now();
int64_t total_real = (now_real - start_real) / std::chrono::milliseconds(1);
// We want to advance the fake clock by the difference between the real
// clock, and the previous value on the fake clock.
milliseconds = total_real - fake_clock;
fake_clock += milliseconds;
}
if (callback_ != nullptr) callback_->ElapseTime(milliseconds);
}
void TestSleep::SyncFakeClock() {
// Syncing can be done by sleeping 0 seconds.
Sleep(0);
}
bool TestSleep::RollbackSystemTime(int seconds) {
if (real_sleep_) {
#ifdef _WIN32
// See remarks from this for why this series is used.
// https://msdn.microsoft.com/en-us/f77cdf86-0f97-4a89-b565-95b46fa7d65b
SYSTEMTIME time;
GetSystemTime(&time);
FILETIME file_time;
if (!SystemTimeToFileTime(time, &file_time)) return false;
uint64_t long_time =
static_cast<uint64_t>(file_time.dwLowDateTime) |
(static_cast<uint64_t>(file_time.dwHighDateTime) << 32);
long_time += static_cast<uint64_t>(delta_seconds) *
1e7; // long_time is in 100-nanosecond intervals.
file_time.dwLowDateTime = long_time & ((1ull << 32) - 1);
file_time.dwHighDateTime = long_time >> 32;
if (!FileTimeToSystemTime(&file_time, &time)) return false;
if (!SetSystemTime(&time)) return false;
#else
auto time = std::chrono::system_clock::now();
auto modified_time = time - std::chrono::seconds(seconds);
;
timespec time_spec;
time_spec.tv_sec = std::chrono::duration_cast<std::chrono::seconds>(
modified_time.time_since_epoch())
.count();
time_spec.tv_nsec = std::chrono::duration_cast<std::chrono::nanoseconds>(
modified_time.time_since_epoch())
.count() %
(1000 * 1000 * 1000);
if (clock_settime(CLOCK_REALTIME, &time_spec)) {
LOGE("Error setting clock: %s", strerror(errno));
return false;
}
#endif
} // end if(real_sleep_)...
// For both real and fake sleep we still update the callback and we still keep
// track of the total amount of time slept.
total_clock_rollback_ += seconds;
if (callback_ != nullptr) callback_->ElapseTime(-1000 * seconds);
return true;
}
bool TestSleep::CanChangeSystemTime() {
// If we are using a fake clock, then we can move the clock backwards by
// just going backwards.
// ElapseTime.
if (!real_sleep_) {
return true;
}
#ifdef _WIN32
LUID desired_id;
if (!LookupPrivilegeValue(nullptr, SE_SYSTEMTIME_NAME, &desired_id)) {
LOGE("Win32 time rollback: no SYSTEMTIME permission.");
return false;
}
HANDLE token;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token)) {
LOGE("Win32 time rollback: cannot access process token.");
return false;
}
std::unique_ptr<void, decltype(&CloseHandle)> safe_token(token, &CloseHandle);
// This queries all the permissions given to the token to determine if we can
// change the system time. Note this is subtly different from PrivilegeCheck
// as that only checks "enabled" privileges; even with admin rights, the
// privilege is default disabled, even when granted.
DWORD size = 0;
// Determine how big we need to allocate first.
GetTokenInformation(token, TokenPrivileges, nullptr, 0, &size);
// Since TOKEN_PRIVILEGES uses a variable-length array, we need to use malloc
std::unique_ptr<TOKEN_PRIVILEGES, decltype(&free)> privileges(
(TOKEN_PRIVILEGES*)malloc(size), &free);
if (privileges && GetTokenInformation(token, TokenPrivileges,
privileges.get(), size, &size)) {
for (int i = 0; i < privileges->PrivilegeCount; i++) {
if (privileges->Privileges[i].Luid.HighPart == desired_id.HighPart &&
privileges->Privileges[i].Luid.LowPart == desired_id.LowPart) {
return true;
}
}
}
LOGE("Win32 time rollback: cannot set system time.");
return false;
#else
// Otherwise, the test needs to be run as root.
const uid_t uid = getuid();
if (uid == 0) return true;
LOGE("Unix time rollback: not running as root (uid=%u.", uid);
return false;
#endif
}
} // namespace wvutil

View File

@@ -0,0 +1,75 @@
// Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// TestSleep - Controls sleep and clock adjustment during tests.
//
#ifndef WVCAS_UTIL_TEST_SLEEP_H_
#define WVCAS_UTIL_TEST_SLEEP_H_
#include <stdint.h>
namespace wvutil {
class TestSleep {
public:
// The callback is called when the clock should be advanced.
class CallBack {
public:
virtual void ElapseTime(int64_t milliseconds) = 0;
protected:
virtual ~CallBack(){};
};
// If real_sleep_ is true, then this sleeps for |seconds| of time. If
// real_sleep_ is false, then the fake clock is advanced by |seconds|. If the
// callback exists, this calls the callback.
static void Sleep(unsigned int seconds);
// If we are using a real clock and a fake clock, then the real clock advances
// a little while we are doing work, but the fake one only advances when we
// sleep. This function advances the fake clock to be in sync with the real
// clock. This function should be called to prevent a slow flaky test from
// failing due to this drift.
static void SyncFakeClock();
// Roll the system clock back by |seconds|. Returns true on success. A well
// mannered test will call CanChangeSystemTime before attempting to call this
// function and then assert that this is true. This function should *NOT* roll
// back the clock used by OEMCrypto -- in fact, there are several tests that
// verify this function does not roll back the clock used by OEMCrypto.
static bool RollbackSystemTime(int seconds);
// Roll the system clock forward to undo all previous calls to
// RollBackSystemTime. Returns true on success.
static bool ResetRollback() {
return total_clock_rollback_ == 0 ||
RollbackSystemTime(-total_clock_rollback_);
}
// Returns true if the system time can be rolled back. This is true on some
// devices if the tests are run as root. It is also true when using a fake
// clock with the reference version of OEMCrypto. This function is about the
// system clock, *NOT* the clock used by OEMCrypto.
static bool CanChangeSystemTime();
static void set_real_sleep(bool real_sleep) { real_sleep_ = real_sleep; }
static bool real_sleep() { return real_sleep_; }
// The callback is notified whenever sleep is called.
static void set_callback(CallBack* callback) { callback_ = callback; }
private:
// Controls if the test sleep should use real sleep.
static bool real_sleep_;
// Called when the clock should advance.
static CallBack* callback_;
// The sum of all calls to RollBackSystemTime. Kept so we can undo all changes
// at the end of a test.
static int total_clock_rollback_;
};
} // namespace wvutil
#endif // WVCAS_UTIL_TEST_SLEEP_H_

108
oemcrypto/test/wvcrc.cpp Normal file
View File

@@ -0,0 +1,108 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Compute CRC32 Checksum. Needed for verification of WV Keybox.
//
#include "platform.h"
#include "wvcrc32.h"
namespace wvoec {
#define INIT_CRC32 0xffffffff
uint32_t wvrunningcrc32(const uint8_t* p_begin, int i_count, uint32_t i_crc) {
static uint32_t CRC32[256] = {
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
};
/* Calculate the CRC */
while (i_count > 0) {
i_crc = (i_crc << 8) ^ CRC32[(i_crc >> 24) ^ ((uint32_t) * p_begin)];
p_begin++;
i_count--;
}
return(i_crc);
}
uint32_t wvcrc32(const uint8_t* p_begin, int i_count) {
return(wvrunningcrc32(p_begin, i_count, INIT_CRC32));
}
uint32_t wvcrc32Init() {
return INIT_CRC32;
}
uint32_t wvcrc32Cont(const uint8_t* p_begin, int i_count, uint32_t prev_crc) {
return(wvrunningcrc32(p_begin, i_count, prev_crc));
}
uint32_t wvcrc32n(const uint8_t* p_begin, int i_count) {
return htonl(wvrunningcrc32(p_begin, i_count, INIT_CRC32));
}
} // namespace wvoec

23
oemcrypto/test/wvcrc32.h Normal file
View File

@@ -0,0 +1,23 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Compute CRC32 Checksum. Needed for verification of WV Keybox.
//
#ifndef CDM_WVCRC32_H_
#define CDM_WVCRC32_H_
#include <stdint.h>
namespace wvoec {
uint32_t wvcrc32(const uint8_t* p_begin, int i_count);
uint32_t wvcrc32Init();
uint32_t wvcrc32Cont(const uint8_t* p_begin, int i_count, uint32_t prev_crc);
// Convert to network byte order
uint32_t wvcrc32n(const uint8_t* p_begin, int i_count);
} // namespace wvoec
#endif // CDM_WVCRC32_H_