Source release v3.1.0

This commit is contained in:
Gene Morgan
2016-07-19 18:43:15 -07:00
parent 7a7f78d654
commit 643b91b616
108 changed files with 16537 additions and 7174 deletions

View File

@@ -121,6 +121,14 @@ typedef struct {
} buffer;
} OEMCrypto_DestBufferDesc;
/** OEMCryptoCipherMode is used in LoadKeys to prepare a key for either CTR
* decryption or CBC decryption.
*/
typedef enum OEMCryptoCipherMode {
OEMCrypto_CipherMode_CTR,
OEMCrypto_CipherMode_CBC,
} OEMCryptoCipherMode;
/*
* OEMCrypto_KeyObject
* Points to the relevant fields for a content key. The fields are extracted
@@ -137,6 +145,8 @@ typedef struct {
* key_control field.
* key_control - the key control block. It is encrypted (AES-128-CBC) with
* the content key from the key_data field.
* cipher_mode - whether the key should be prepared for CTR mode or CBC mode
* when used in later calls to DecryptCENC.
*
* The memory for the OEMCrypto_KeyObject fields is allocated and freed
* by the caller of OEMCrypto_LoadKeys().
@@ -149,6 +159,7 @@ typedef struct {
size_t key_data_length;
const uint8_t* key_control_iv;
const uint8_t* key_control;
OEMCryptoCipherMode cipher_mode;
} OEMCrypto_KeyObject;
/*
@@ -188,11 +199,21 @@ typedef enum OEMCrypto_Algorithm {
} OEMCrypto_Algorithm;
/*
* Flags indicating data endpoints in OEMCrypto_DecryptCTR.
* Flags indicating data endpoints in OEMCrypto_DecryptCENC.
*/
#define OEMCrypto_FirstSubsample 1
#define OEMCrypto_LastSubsample 2
/* OEMCrypto_CENCEncryptPatternDesc
* This is used in OEMCrypto_DecryptCENC to indicate the encrypt/skip pattern
* used, as specified in the CENC standard.
*/
typedef struct {
size_t encrypt; // number of 16 byte blocks to decrypt.
size_t skip; // number of 16 byte blocks to leave in clear.
size_t offset; // offset into the pattern in blocks for this call.
} OEMCrypto_CENCEncryptPatternDesc;
/*
* OEMCrypto_Usage_Entry_Status.
* Valid values for status in the usage table.
@@ -260,7 +281,7 @@ typedef enum OEMCrypto_HDCP_Capability {
#define OEMCrypto_WrapKeybox _oecc08
#define OEMCrypto_OpenSession _oecc09
#define OEMCrypto_CloseSession _oecc10
#define OEMCrypto_DecryptCTR _oecc11
#define OEMCrypto_DecryptCTR_V10 _oecc11
#define OEMCrypto_GenerateDerivedKeys _oecc12
#define OEMCrypto_GenerateSignature _oecc13
#define OEMCrypto_GenerateNonce _oecc14
@@ -284,7 +305,7 @@ typedef enum OEMCrypto_HDCP_Capability {
#define OEMCrypto_ReportUsage _oecc32
#define OEMCrypto_DeleteUsageEntry _oecc33
#define OEMCrypto_DeleteUsageTable _oecc34
#define OEMCrypto_LoadKeys _oecc35
#define OEMCrypto_LoadKeys_V9_or_V10 _oecc35
#define OEMCrypto_GenerateRSASignature _oecc36
#define OEMCrypto_GetMaxNumberOfSessions _oecc37
#define OEMCrypto_GetNumberOfOpenSessions _oecc38
@@ -295,6 +316,9 @@ typedef enum OEMCrypto_HDCP_Capability {
#define OEMCrypto_ForceDeleteUsageEntry _oecc43
#define OEMCrypto_GetHDCPCapability _oecc44
#define OEMCrypto_LoadTestRSAKey _oecc45
#define OEMCrypto_Security_Patch_Level _oecc46
#define OEMCrypto_LoadKeys _oecc47
#define OEMCrypto_DecryptCENC _oecc48
/*
@@ -373,7 +397,8 @@ OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION *session);
* OEMCrypto_CloseSession
*
* Description:
* Closes the crypto security engine session and frees any associated resources.
* Closes the crypto security engine session and frees any associated
* resources.
*
* Parameters:
* session (in) - handle for the session to be closed.
@@ -565,10 +590,12 @@ OEMCryptoResult OEMCrypto_GenerateSignature(
* the previous call to OEMCrypto_GenerateNonce().
*
* This sessions elapsed time clock is started at 0. The clock will be used
* in OEMCrypto_DecryptCTR().
* in OEMCrypto_DecryptCENC().
*
* NOTE: OEMCrypto_GenerateDerivedKeys() must be called first to establish the
* mac_key and encrypt_key.
* NOTE: The calling software must have previously established the mac_keys
* and encrypt_key with a call to OEMCrypto_GenerateDerivedKeys(),
* OEMCrypto_DeriveKeysFromSessionKey(), or a previous call to
* OEMCrypto_LoadKeys().
*
* Refer to document "Widevine Modular DRM Security Integration Guide for
* CENC" for details.
@@ -604,9 +631,15 @@ OEMCryptoResult OEMCrypto_GenerateSignature(
* the cache. Note that all the key control blocks in a particular call shall
* have the same nonce value.
*
* 6. If the key control block has a nonzero Replay_Control, then the
* 6. If any key control block has the Require_AntiRollback_Hardware bit set,
* and the device does not protect the usage table from rollback, then do not
* load the keys and return OEMCrypto_ERROR_UNKNOWN_FAILURE.
*
* 7. If the key control block has a nonzero Replay_Control, then the
* verification described below is also performed.
*
* 8. If num_keys == 0, then return OEMCrypto_ERROR_INVALID_CONTEXT.
*
* Usage Table and Provider Session Token (pst):
*
* If a key control block has a nonzero value for Replay_Control, then all keys
@@ -652,6 +685,10 @@ OEMCryptoResult OEMCrypto_GenerateSignature(
* Devices that do not support the Usage Table will return
* OEMCrypto_ERROR_INVALID_CONTEXT if the Replay_Control is nonzero.
*
* Note: If LoadKeys creates a new entry in the usage table, OEMCrypto will
* increment the Usage Tables generation number, and then sign, encrypt, and
* save the Usage Table.
*
* Parameters:
* session (in) - crypto session identifier.
* message (in) - pointer to memory containing message to be verified.
@@ -681,7 +718,7 @@ OEMCryptoResult OEMCrypto_GenerateSignature(
* OEMCrypto_ERROR_UNKNOWN_FAILURE
*
* Version:
* This method changed in API version 9.
* This method changed in API version 11.
*/
OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
const uint8_t* message,
@@ -714,7 +751,7 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
* first to establish the mac_key[server].
*
* This sessions elapsed time clock is reset to 0 when this function is called.
* The elapsed time clock is used in OEMCrypto_DecryptCTR().
* The elapsed time clock is used in OEMCrypto_DecryptCENC().
*
* This function does not add keys to the key table. It is only used to update a
* key control block license duration. Refer to the License Signing and
@@ -849,7 +886,7 @@ OEMCrypto_QueryKeyControl(OEMCrypto_SESSION session,
*
* Description:
* Select a content key and install it in the hardware key ladder for
* subsequent decryption operations (OEMCrypto_DecryptCTR()) for this session.
* subsequent decryption operations (OEMCrypto_DecryptCENC()) for this session.
* The specified key must have been previously "installed" via
* OEMCrypto_LoadKeys() or OEMCrypto_RefreshKeys().
*
@@ -864,7 +901,7 @@ OEMCrypto_QueryKeyControl(OEMCrypto_SESSION session,
* permission flags and timers based on the key's control block.
*
* Step 3: use the latched content key to decrypt (AES-128-CTR) buffers passed in
* via OEMCrypto_DecryptCTR(). If the key is 256 bits it will be used for
* via OEMCrypto_DecryptCENC(). If the key is 256 bits it will be used for
* OEMCrypto_Generic_Sign or OEMCrypto_Generic_Verify as specified in the key
* control block. Continue to use this key until OEMCrypto_SelectKey() is called
* again, or until OEMCrypto_CloseSession() is called.
@@ -898,15 +935,17 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session,
size_t key_id_length);
/*
* OEMCrypto_DecryptCTR
* OEMCrypto_DecryptCENC
*
* Description:
* Decrypts (AES-128-CTR) or copies the payload in the buffer referenced by the
* data_addr parameter into the buffer referenced by the out_buffer parameter,
* using the session context indicated by the session parameter. If is_encrypted
* is true, the content key associated with the session is latched in the active
* hardware key ladder and is used for the decryption operation. If is_encrypted
* is false, the data is simply copied.
* Decrypts or copies the payload in the buffer referenced by the *data_addr
* parameter into the buffer referenced by the out_buffer parameter, using
* the session context indicated by the session parameter. Decryption mode
* is AES-128-CTR or AES-128-CBC depending on the value of cipher_mode set in
* the OEMCrypto_KeyObject passed in to OEMCrypto_LoadKeys. If is_encrypted
* is true, the content key associated with the session is latched in the
* active hardware key ladder and is used for the decryption operation. If
* is_encrypted is false, the data is simply copied.
*
* After decryption, the data_length bytes are copied to the location described
* by out_buffer. This could be one of
@@ -921,13 +960,13 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session,
* the decoder and rendered.
*
* NOTES:
* IV points to the counter value to be used for the initial
* encrypted block of the input buffer. The IV length is the AES
* block size. For subsequent encrypted AES blocks the IV is
* calculated by incrementing the lower 64 bits (byte 8-15) of the
* IV value used for the previous block. The counter rolls over to
* zero when it reaches its maximum value (0xFFFFFFFFFFFFFFFF).
* The upper 64 bits (byte 0-7) of the IV do not change.
* For CTR mode, IV points to the counter value to be used for the initial
* encrypted block of the input buffer. The IV length is the AES block
* size. For subsequent encrypted AES blocks the IV is calculated by
* incrementing the lower 64 bits (byte 8-15) of the IV value used for the
* previous block. The counter rolls over to zero when it reaches its maximum
* value (0xFFFFFFFFFFFFFFFF). The upper 64 bits (byte 0-7) of the IV do not
* change.
*
* This method may be called several times before the decrypted data is used.
* For this reason, the parameter subsample_flags may be used to optimize
@@ -938,7 +977,7 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session,
* OEMCrypto_LastSubsample has been set. If an implementation decrypts data
* immediately, it may ignore subsample_flags.
*
* If the destination buffer is secure, an offset may be specified. DecryptCTR
* If the destination buffer is secure, an offset may be specified. DecryptCENC
* begins storing data out_buffer->secure.offset bytes after the beginning of the
* secure buffer.
*
@@ -946,6 +985,13 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session,
* time_of_last_decrypt. If the status of the entry is "unused", then change the
* status to "active" and set the time_of_first_decrypt.
*
* The decryption mode, either OEMCrypto_CipherMode_CTR or
* OEMCrypto_CipherMode_CBC, was specified in the call to OEMCrypto_LoadKeys.
* The encryption pattern is specified in by the parameter pattern. A
* description of partial encryption patterns can be found in the document
* Draft International Standard ISO/IEC DIS 23001-7. Search for the codes
* "cenc", "cbc1", "cens" or "cbcs".
*
*
* Verification:
* The following checks should be performed if is_encrypted is true. If any
@@ -992,9 +1038,12 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session,
* decryption block start address and data_addr are discarded
* after decryption. It does not adjust the beginning of the
* source or destination data. This parameter satisfies
* 0 <= block_offset < 16.
* 0 <= block_offset < 16. This paramater is only used
* for CTR mode.
* out_buffer (in) - A caller-owned descriptor that specifies the handling of the
* decrypted byte stream. See OEMCrypto_DestbufferDesc for details.
* pattern (in) - A caller-owned structure indicating the encrypt/skip
* pattern as specified in the CENC standard.
* subsample_flags (in) - bitwise flags indicating if this is the first, middle,
* or last subsample in a chunk of data.
* 0 = neither first nor last subsample,
@@ -1018,16 +1067,18 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session,
* OEMCrypto_ERROR_UNKNOWN_FAILURE
*
* Version:
* This method changed in API version 9.
* This method changed in API version 11.
* This method changed its name in API version 11.
*/
OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
const uint8_t *data_addr,
size_t data_length,
bool is_encrypted,
const uint8_t *iv,
size_t block_offset,
OEMCrypto_DestBufferDesc* out_buffer,
uint8_t subsample_flags);
OEMCryptoResult OEMCrypto_DecryptCENC(OEMCrypto_SESSION session,
const uint8_t *data_addr,
size_t data_length,
bool is_encrypted,
const uint8_t *iv,
size_t block_offset,
OEMCrypto_DestBufferDesc* out_buffer,
const OEMCrypto_CENCEncryptPatternDesc* pattern,
uint8_t subsample_flags);
/*
@@ -1037,9 +1088,9 @@ OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
* Copies the payload in the buffer referenced by the *data_addr parameter into
* the buffer referenced by the out_buffer parameter. The data is simply
* copied. The definition of OEMCrypto_DestBufferDesc and subsample_flags are
* the same as in OEMCrypto_DecryptCTR, above.
* the same as in OEMCrypto_DecryptCENC, above.
*
* The main difference between this and DecryptCTR is that this function does
* The main difference between this and DecryptCENC is that this function does
* not need an open session, and it may be called concurrently with other
* session functions on a multithreaded system. In particular, an application
* will use this to copy the clear leader of a video to a secure buffer while
@@ -1648,9 +1699,6 @@ OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey(OEMCrypto_SESSION session,
* There is no plan to introduce forward-compatibility. Applications will reject
* a library with a newer version of the API.
*
* The version specified in this document is 9. Any OEM that returns this
* version number guarantees it passes all unit tests associated this version.
*
* Parameters:
* none
*
@@ -1665,6 +1713,28 @@ OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey(OEMCrypto_SESSION session,
*/
uint32_t OEMCrypto_APIVersion();
/**
* OEMCrypto_Security_Patch_Level()
*
* Description:
* This function returns the current patch level of the software running in
* the trusted environment. The patch level is defined by the OEM, and is
* only incremented when a security update has been added.
*
* Parameters:
* none
*
* Returns:
* The OEM defined version number.
*
* Threading:
* This function may be called simultaneously with any other functions.
*
* Version:
* This method was introduced in API version 11.
*/
uint8_t OEMCrypto_Security_Patch_Level();
/*
* OEMCrypto_SecurityLevel()
*

View File

@@ -0,0 +1,144 @@
#include "oec_device_features.h"
#include <stdio.h>
#include <cstring>
#include "oec_test_data.h"
namespace wvoec {
DeviceFeatures global_features;
void DeviceFeatures::Initialize(bool is_cast_receiver,
bool force_load_test_keybox) {
cast_receiver = is_cast_receiver;
uses_keybox = false;
uses_certificate = false;
loads_certificate = false;
generic_crypto = false;
usage_table = false;
api_version = 0;
derive_key_method = NO_METHOD;
if (OEMCrypto_SUCCESS != OEMCrypto_Initialize()) {
printf("OEMCrypto_Initialze failed. All tests will fail.\n");
return;
}
uint32_t nonce = 0;
uint8_t buffer[1];
size_t size = 0;
uses_keybox =
(OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_GetKeyData(buffer, &size));
printf("uses_keybox = %s.\n", uses_keybox ? "true" : "false");
loads_certificate = uses_keybox && (OEMCrypto_ERROR_NOT_IMPLEMENTED !=
OEMCrypto_RewrapDeviceRSAKey(
0, buffer, 0, buffer, 0, &nonce,
buffer, 0, buffer, buffer, &size));
printf("loads_certificate = %s.\n", loads_certificate ? "true" : "false");
uses_certificate = (OEMCrypto_ERROR_NOT_IMPLEMENTED !=
OEMCrypto_GenerateRSASignature(0, buffer, 0, buffer,
&size, kSign_RSASSA_PSS));
printf("uses_certificate = %s.\n", uses_certificate ? "true" : "false");
generic_crypto =
(OEMCrypto_ERROR_NOT_IMPLEMENTED !=
OEMCrypto_Generic_Encrypt(0, buffer, 0, buffer,
OEMCrypto_AES_CBC_128_NO_PADDING, buffer));
printf("generic_crypto = %s.\n", generic_crypto ? "true" : "false");
api_version = OEMCrypto_APIVersion();
printf("api_version = %d.\n", api_version);
usage_table = OEMCrypto_SupportsUsageTable();
printf("usage_table = %s.\n", usage_table ? "true" : "false");
if (force_load_test_keybox) {
derive_key_method = FORCE_TEST_KEYBOX;
} else {
PickDerivedKey();
}
printf("cast_receiver = %s.\n", cast_receiver ? "true" : "false");
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;
uses_certificate = 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 EXISTING_TEST_KEYBOX:
printf("EXISTING_TEST_KEYBOX: Keybox is already the test keybox.\n");
break;
case FORCE_TEST_KEYBOX:
printf("FORCE_TEST_KEYBOX: User requested calling InstallKeybox.\n");
break;
}
OEMCrypto_Terminate();
}
std::string DeviceFeatures::RestrictFilter(const std::string& initial_filter) {
std::string filter = initial_filter;
if (!uses_keybox) FilterOut(&filter, "*KeyboxTest*");
if (derive_key_method
!= FORCE_TEST_KEYBOX) FilterOut(&filter, "*ForceKeybox*");
if (!uses_certificate) FilterOut(&filter, "OEMCrypto*Cert*");
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 (api_version < 10) FilterOut(&filter, "*API10*");
if (api_version < 11) FilterOut(&filter, "*API11*");
// 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 (uses_keybox) {
// If device uses a keybox, try to load the test keybox.
if (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestKeybox()) {
derive_key_method = LOAD_TEST_KEYBOX;
} else if (IsTestKeyboxInstalled()) {
derive_key_method = EXISTING_TEST_KEYBOX;
}
} else if (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestRSAKey()) {
derive_key_method = LOAD_TEST_RSA_KEY;
}
}
bool DeviceFeatures::IsTestKeyboxInstalled() {
uint8_t key_data[256];
size_t key_data_len = sizeof(key_data);
if (OEMCrypto_GetKeyData(key_data, &key_data_len) != OEMCrypto_SUCCESS)
return false;
if (key_data_len != sizeof(kTestKeybox.data_)) return false;
if (memcmp(key_data, kTestKeybox.data_, key_data_len)) return false;
uint8_t dev_id[128] = {0};
size_t dev_id_len = 128;
if (OEMCrypto_GetDeviceID(dev_id, &dev_id_len) != OEMCrypto_SUCCESS)
return false;
// We use strncmp instead of memcmp because we don't really care about the
// multiple '\0' characters at the end of the device id.
return 0 == strncmp(reinterpret_cast<const char*>(dev_id),
reinterpret_cast<const char*>(kTestKeybox.device_id_),
sizeof(kTestKeybox.device_id_));
}
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;
}
}
} // namespace wvoec

View File

@@ -1,5 +1,7 @@
#ifndef CDM_OEMCRYPTO_TEST_H_
#define CDM_OEMCRYPTO_TEST_H_
#ifndef CDM_OEC_DEVICE_FEATURES_H_
#define CDM_OEC_DEVICE_FEATURES_H_
#include <string>
#include "OEMCryptoCENC.h"
#include "wv_keybox.h"
@@ -38,4 +40,4 @@ extern DeviceFeatures global_features;
} // namespace wvoec
#endif // CDM_OEMCRYPTO_TEST_H_
#endif // CDM_OEC_DEVICE_FEATURES_H_

View File

@@ -0,0 +1,802 @@
// Copyright 2016 Google Inc. All Rights Reserved.
//
// OEMCrypto unit tests
//
#include "oec_session_util.h"
#include <arpa/inet.h> // needed for ntoh()
#include <openssl/aes.h>
#include <openssl/err.h>
#include <openssl/hmac.h>
#include <openssl/x509.h>
#include <stdint.h>
#include <gtest/gtest.h>
#include <iostream>
#include <string>
#include <vector>
#include "log.h"
#include "oec_device_features.h"
#include "oec_test_data.h"
#include "oemcrypto_key_mock.h"
#include "OEMCryptoCENC.h"
#include "string_conversions.h"
#include "wv_cdm_constants.h"
#include "wv_keybox.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) {
*os << wvcdm::b2a_hex(value);
}
void PrintTo(const PatternTestVariant& param, ostream* os) {
*os << ((param.mode == OEMCrypto_CipherMode_CTR) ? "CTR mode" : "CBC mode")
<< ", encrypt=" << param.pattern.encrypt
<< ", skip=" << param.pattern.skip;
}
} // namespace std
namespace wvoec {
// 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) {
ASSERT_NE(static_cast<void*>(NULL), iv);
uint64_t* counterBuffer = reinterpret_cast<uint64_t*>(&iv[8]);
(*counterBuffer) =
wvcdm::htonll64(wvcdm::ntohll64(*counterBuffer) + increaseBy);
}
// Some compilers don't like the macro htonl within an ASSERT_EQ.
uint32_t htonl_fnc(uint32_t x) { return htonl(x); }
void dump_openssl_error() {
while (unsigned long err = ERR_get_error()) {
char buffer[120];
ERR_error_string_n(err, buffer, sizeof(buffer));
cout << "openssl error -- " << buffer << "\n";
}
}
Session::Session()
: open_(false),
forced_session_id_(false),
session_id_(0),
mac_key_server_(wvcdm::MAC_KEY_SIZE),
mac_key_client_(wvcdm::MAC_KEY_SIZE),
enc_key_(wvcdm::KEY_SIZE),
public_rsa_(0) {}
Session::~Session() {
if (!forced_session_id_ && open_) close();
if (public_rsa_) RSA_free(public_rsa_);
}
void Session::open() {
EXPECT_FALSE(forced_session_id_);
EXPECT_FALSE(open_);
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_OpenSession(&session_id_));
open_ = true;
}
void Session::SetSessionId(uint32_t session_id) {
EXPECT_FALSE(open_);
session_id_ = session_id;
forced_session_id_ = true;
}
void Session::close() {
EXPECT_TRUE(open_ || forced_session_id_);
if (open_) {
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CloseSession(session_id_));
}
forced_session_id_ = false;
open_ = false;
}
void Session::GenerateNonce(uint32_t* nonce, int* error_counter) {
if (OEMCrypto_SUCCESS == OEMCrypto_GenerateNonce(session_id(), nonce)) {
return;
}
if (error_counter) {
(*error_counter)++;
} else {
sleep(1); // wait a second, then try again.
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_GenerateNonce(session_id(), nonce));
}
}
void Session::FillDefaultContext(vector<uint8_t>* mac_context,
vector<uint8_t>* enc_context) {
/* Context strings
* These context strings are normally created by the CDM layer
* from a license request message.
* They are used to test MAC and ENC key generation.
*/
*mac_context = wvcdm::a2b_hex(
"41555448454e5449434154494f4e000a4c08001248000000020000101907d9ff"
"de13aa95c122678053362136bdf8408f8276e4c2d87ec52b61aa1b9f646e5873"
"4930acebe899b3e464189a14a87202fb02574e70640bd22ef44b2d7e3912250a"
"230a14080112100915007caa9b5931b76a3a85f046523e10011a093938373635"
"34333231180120002a0c31383836373837343035000000000200");
*enc_context = wvcdm::a2b_hex(
"454e4352595054494f4e000a4c08001248000000020000101907d9ffde13aa95"
"c122678053362136bdf8408f8276e4c2d87ec52b61aa1b9f646e58734930aceb"
"e899b3e464189a14a87202fb02574e70640bd22ef44b2d7e3912250a230a1408"
"0112100915007caa9b5931b76a3a85f046523e10011a09393837363534333231"
"180120002a0c31383836373837343035000000000080");
}
void Session::GenerateDerivedKeysFromKeybox() {
GenerateNonce(&nonce_);
vector<uint8_t> mac_context;
vector<uint8_t> enc_context;
FillDefaultContext(&mac_context, &enc_context);
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_GenerateDerivedKeys(session_id(), &mac_context[0],
mac_context.size(), &enc_context[0],
enc_context.size()));
// Expected MAC and ENC keys generated from context strings
// with test keybox "installed".
mac_key_server_ = wvcdm::a2b_hex(
"3CFD60254786AF350B353B4FBB700AB382558400356866BA16C256BCD8C502BF");
mac_key_client_ = wvcdm::a2b_hex(
"A9DE7B3E4E199ED8D1FBC29CD6B4C772CC4538C8B0D3E208B3E76F2EC0FD6F47");
enc_key_ = wvcdm::a2b_hex("D0BFC35DA9E33436E81C4229E78CB9F4");
}
void Session::GenerateDerivedKeysFromSessionKey() {
// Uses test certificate.
GenerateNonce(&nonce_);
vector<uint8_t> enc_session_key;
PreparePublicKey();
ASSERT_TRUE(GenerateRSASessionKey(&enc_session_key));
vector<uint8_t> mac_context;
vector<uint8_t> enc_context;
FillDefaultContext(&mac_context, &enc_context);
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_DeriveKeysFromSessionKey(
session_id(), &enc_session_key[0], enc_session_key.size(),
&mac_context[0], mac_context.size(), &enc_context[0],
enc_context.size()));
// Expected MAC and ENC keys generated from context strings
// with RSA certificate "installed".
mac_key_server_ = wvcdm::a2b_hex(
"1E451E59CB663DA1646194DD28880788ED8ED2EFF913CBD6A0D535D1D5A90381");
mac_key_client_ = wvcdm::a2b_hex(
"F9AAE74690909F2207B53B13307FCA096CA8C49CC6DFE3659873CB952889A74B");
enc_key_ = wvcdm::a2b_hex("CB477D09014D72C9B8DCE76C33EA43B3");
}
void Session::GenerateTestSessionKeys() {
if (global_features.derive_key_method == DeviceFeatures::LOAD_TEST_RSA_KEY) {
GenerateDerivedKeysFromSessionKey();
} else {
GenerateDerivedKeysFromKeybox();
}
}
void Session::LoadTestKeys(const std::string& pst, bool new_mac_keys) {
uint8_t* pst_ptr = NULL;
if (pst.length() > 0) {
pst_ptr = encrypted_license_.pst;
}
if (new_mac_keys) {
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_LoadKeys(
session_id(), message_ptr(), sizeof(MessageData),
&signature_[0], signature_.size(),
encrypted_license_.mac_key_iv, encrypted_license_.mac_keys,
kNumKeys, key_array_, pst_ptr, pst.length()));
// Update new generated keys.
memcpy(&mac_key_server_[0], license_.mac_keys, wvcdm::MAC_KEY_SIZE);
memcpy(&mac_key_client_[0], license_.mac_keys + wvcdm::MAC_KEY_SIZE,
wvcdm::MAC_KEY_SIZE);
} else {
ASSERT_EQ(
OEMCrypto_SUCCESS,
OEMCrypto_LoadKeys(session_id(), message_ptr(), sizeof(MessageData),
&signature_[0], signature_.size(), NULL, NULL,
kNumKeys, key_array_, pst_ptr, pst.length()));
}
VerifyTestKeys();
}
void Session::VerifyTestKeys() {
for (unsigned int i = 0; i < kNumKeys; i++) {
KeyControlBlock block;
size_t size = sizeof(block);
OEMCryptoResult sts = OEMCrypto_QueryKeyControl(
session_id(), license_.keys[i].key_id, license_.keys[i].key_id_length,
reinterpret_cast<uint8_t*>(&block), &size);
if (sts != OEMCrypto_ERROR_NOT_IMPLEMENTED) {
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
ASSERT_EQ(sizeof(block), size);
// control duration and bits stored in network byte order. For printing
// we change to host byte order.
ASSERT_EQ((htonl_fnc(license_.keys[i].control.duration)),
(htonl_fnc(block.duration))) << "For key " << i;
ASSERT_EQ(htonl_fnc(license_.keys[i].control.control_bits),
htonl_fnc(block.control_bits)) << "For key " << i;
}
}
}
void Session::RefreshTestKeys(const size_t key_count,
uint32_t control_bits, uint32_t nonce,
OEMCryptoResult expected_result) {
// Note: we store the message in encrypted_license_, but the refresh key
// message is not actually encrypted. It is, however, signed.
FillRefreshMessage(key_count, control_bits, nonce);
ServerSignMessage(encrypted_license_, &signature_);
OEMCrypto_KeyRefreshObject key_array[key_count];
FillRefreshArray(key_array, key_count);
OEMCryptoResult sts = OEMCrypto_RefreshKeys(
session_id(), message_ptr(), sizeof(MessageData), &signature_[0],
signature_.size(), key_count, key_array);
ASSERT_EQ(expected_result, sts);
ASSERT_NO_FATAL_FAILURE(TestDecryptCTR());
sleep(kShortSleep); // Should still be valid key.
ASSERT_NO_FATAL_FAILURE(TestDecryptCTR(false));
sleep(kShortSleep + kLongSleep); // Should be after first expiration.
if (expected_result == OEMCrypto_SUCCESS) {
ASSERT_NO_FATAL_FAILURE(TestDecryptCTR(false, OEMCrypto_SUCCESS));
} else {
ASSERT_NO_FATAL_FAILURE(
TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE));
}
}
void Session::SetKeyId(int index, const string& key_id) {
MessageKeyData& key = license_.keys[index];
key.key_id_length = key_id.length();
ASSERT_LE(key.key_id_length, kTestKeyIdMaxLength);
memcpy(key.key_id, key_id.data(), key.key_id_length);
}
void Session::FillSimpleMessage(
uint32_t duration, uint32_t control, uint32_t nonce,
const std::string& pst) {
EXPECT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_GetRandom(license_.mac_key_iv,
sizeof(license_.mac_key_iv)));
EXPECT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_GetRandom(license_.mac_keys, sizeof(license_.mac_keys)));
for (unsigned int i = 0; i < kNumKeys; i++) {
memset(license_.keys[i].key_id, 0, kTestKeyIdMaxLength);
license_.keys[i].key_id_length = kDefaultKeyIdLength;
memset(license_.keys[i].key_id, i, license_.keys[i].key_id_length);
EXPECT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_GetRandom(license_.keys[i].key_data,
sizeof(license_.keys[i].key_data)));
license_.keys[i].key_data_length = wvcdm::KEY_SIZE;
EXPECT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_GetRandom(license_.keys[i].key_iv,
sizeof(license_.keys[i].key_iv)));
EXPECT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_GetRandom(license_.keys[i].control_iv,
sizeof(license_.keys[i].control_iv)));
if (control & wvoec_mock::kControlSecurityPatchLevelMask) {
memcpy(license_.keys[i].control.verification, "kc11", 4);
} else if (control & wvoec_mock::kControlRequireAntiRollbackHardware) {
memcpy(license_.keys[i].control.verification, "kc10", 4);
} else if (control & (wvoec_mock::kControlHDCPVersionMask |
wvoec_mock::kControlReplayMask)) {
memcpy(license_.keys[i].control.verification, "kc09", 4);
} else {
memcpy(license_.keys[i].control.verification, "kctl", 4);
}
license_.keys[i].control.duration = htonl(duration);
license_.keys[i].control.nonce = htonl(nonce);
license_.keys[i].control.control_bits = htonl(control);
license_.keys[i].cipher_mode = OEMCrypto_CipherMode_CTR;
}
memcpy(license_.pst, pst.c_str(), min(sizeof(license_.pst), pst.length()));
}
void Session::FillRefreshMessage(size_t key_count, uint32_t control_bits,
uint32_t nonce) {
for (unsigned int i = 0; i < key_count; i++) {
encrypted_license_.keys[i].key_id_length = license_.keys[i].key_id_length;
memcpy(encrypted_license_.keys[i].key_id, license_.keys[i].key_id,
encrypted_license_.keys[i].key_id_length);
memcpy(encrypted_license_.keys[i].control.verification, "kctl", 4);
encrypted_license_.keys[i].control.duration = htonl(kLongDuration);
encrypted_license_.keys[i].control.nonce = htonl(nonce);
encrypted_license_.keys[i].control.control_bits = htonl(control_bits);
}
}
void Session::EncryptAndSign() {
encrypted_license_ = license_;
uint8_t iv_buffer[16];
memcpy(iv_buffer, &license_.mac_key_iv[0], wvcdm::KEY_IV_SIZE);
AES_KEY aes_key;
AES_set_encrypt_key(&enc_key_[0], 128, &aes_key);
AES_cbc_encrypt(&license_.mac_keys[0], &encrypted_license_.mac_keys[0],
2 * wvcdm::MAC_KEY_SIZE, &aes_key, iv_buffer, AES_ENCRYPT);
for (unsigned int i = 0; i < kNumKeys; i++) {
memcpy(iv_buffer, &license_.keys[i].control_iv[0], wvcdm::KEY_IV_SIZE);
AES_set_encrypt_key(&license_.keys[i].key_data[0], 128, &aes_key);
AES_cbc_encrypt(
reinterpret_cast<const uint8_t*>(&license_.keys[i].control),
reinterpret_cast<uint8_t*>(&encrypted_license_.keys[i].control),
wvcdm::KEY_SIZE, &aes_key, iv_buffer, AES_ENCRYPT);
memcpy(iv_buffer, &license_.keys[i].key_iv[0], wvcdm::KEY_IV_SIZE);
AES_set_encrypt_key(&enc_key_[0], 128, &aes_key);
AES_cbc_encrypt(&license_.keys[i].key_data[0],
&encrypted_license_.keys[i].key_data[0],
license_.keys[i].key_data_length, &aes_key, iv_buffer,
AES_ENCRYPT);
}
memcpy(encrypted_license_.pst, license_.pst, sizeof(license_.pst));
ServerSignMessage(encrypted_license_, &signature_);
FillKeyArray(encrypted_license_, key_array_);
}
void Session::EncryptMessage(RSAPrivateKeyMessage* data,
RSAPrivateKeyMessage* encrypted) {
*encrypted = *data;
size_t padding = wvcdm::KEY_SIZE - (data->rsa_key_length % wvcdm::KEY_SIZE);
memset(data->rsa_key + data->rsa_key_length, static_cast<uint8_t>(padding),
padding);
encrypted->rsa_key_length = data->rsa_key_length + padding;
uint8_t iv_buffer[16];
memcpy(iv_buffer, &data->rsa_key_iv[0], wvcdm::KEY_IV_SIZE);
AES_KEY aes_key;
AES_set_encrypt_key(&enc_key_[0], 128, &aes_key);
AES_cbc_encrypt(&data->rsa_key[0], &encrypted->rsa_key[0],
encrypted->rsa_key_length, &aes_key, iv_buffer,
AES_ENCRYPT);
}
template <typename T>
void Session::ServerSignMessage(const T& data,
std::vector<uint8_t>* signature) {
signature->assign(SHA256_DIGEST_LENGTH, 0);
unsigned int md_len = SHA256_DIGEST_LENGTH;
HMAC(EVP_sha256(), &mac_key_server_[0], mac_key_server_.size(),
reinterpret_cast<const uint8_t*>(&data), sizeof(data),
&(signature->front()), &md_len);
}
void Session::ClientSignMessage(const vector<uint8_t>& data,
std::vector<uint8_t>* signature) {
signature->assign(SHA256_DIGEST_LENGTH, 0);
unsigned int md_len = SHA256_DIGEST_LENGTH;
HMAC(EVP_sha256(), &mac_key_client_[0], mac_key_client_.size(),
&(data.front()), data.size(), &(signature->front()), &md_len);
}
void Session::FillKeyArray(const MessageData& data,
OEMCrypto_KeyObject* key_array) {
for (unsigned int i = 0; i < kNumKeys; i++) {
key_array[i].key_id = data.keys[i].key_id;
key_array[i].key_id_length = data.keys[i].key_id_length;
key_array[i].key_data_iv = data.keys[i].key_iv;
key_array[i].key_data = data.keys[i].key_data;
key_array[i].key_data_length = data.keys[i].key_data_length;
key_array[i].key_control_iv = data.keys[i].control_iv;
key_array[i].key_control =
reinterpret_cast<const uint8_t*>(&data.keys[i].control);
key_array[i].cipher_mode = data.keys[i].cipher_mode;
}
}
void Session::FillRefreshArray(OEMCrypto_KeyRefreshObject* key_array,
size_t key_count) {
for (size_t i = 0; i < key_count; i++) {
if (key_count > 1) {
key_array[i].key_id = encrypted_license_.keys[i].key_id;
key_array[i].key_id_length = encrypted_license_.keys[i].key_id_length;
} else {
key_array[i].key_id = NULL;
key_array[i].key_id_length = 0;
}
key_array[i].key_control_iv = NULL;
key_array[i].key_control =
reinterpret_cast<const uint8_t*>(&encrypted_license_.keys[i].control);
}
}
void Session::EncryptCTR(
const vector<uint8_t>& in_buffer, const uint8_t *key,
const uint8_t* starting_iv, vector<uint8_t>* out_buffer) {
ASSERT_NE(static_cast<void*>(NULL), key);
ASSERT_NE(static_cast<void*>(NULL), starting_iv);
ASSERT_NE(static_cast<void*>(NULL), out_buffer);
AES_KEY aes_key;
AES_set_encrypt_key(key, AES_BLOCK_SIZE * 8, &aes_key);
out_buffer->resize(in_buffer.size());
uint8_t iv[AES_BLOCK_SIZE]; // Current iv.
memcpy(iv, &starting_iv[0], AES_BLOCK_SIZE);
size_t l = 0; // byte index into encrypted subsample.
while (l < in_buffer.size()) {
uint8_t aes_output[AES_BLOCK_SIZE];
AES_encrypt(iv, aes_output, &aes_key);
for (size_t n = 0; n < AES_BLOCK_SIZE && l < in_buffer.size(); n++, l++) {
(*out_buffer)[l] = aes_output[n] ^ in_buffer[l];
}
ctr128_inc64(1, iv);
}
}
void Session::TestDecryptCTR(bool select_key_first,
OEMCryptoResult expected_result) {
OEMCryptoResult sts;
if (select_key_first) {
// Select the key (from FillSimpleMessage)
sts = OEMCrypto_SelectKey(session_id(), license_.keys[0].key_id,
license_.keys[0].key_id_length);
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
}
vector<uint8_t> unencryptedData(256);
for(size_t i=0; i < unencryptedData.size(); i++) unencryptedData[i] = i % 256;
EXPECT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_GetRandom(&unencryptedData[0], unencryptedData.size()));
vector<uint8_t> encryptionIv(wvcdm::KEY_IV_SIZE);
EXPECT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_GetRandom(&encryptionIv[0], wvcdm::KEY_IV_SIZE));
vector<uint8_t> encryptedData(unencryptedData.size());
EncryptCTR(unencryptedData, license_.keys[0].key_data, &encryptionIv[0],
&encryptedData);
// Describe the output
vector<uint8_t> outputBuffer(256);
OEMCrypto_DestBufferDesc destBuffer;
destBuffer.type = OEMCrypto_BufferType_Clear;
destBuffer.buffer.clear.address = outputBuffer.data();
destBuffer.buffer.clear.max_length = outputBuffer.size();
OEMCrypto_CENCEncryptPatternDesc pattern;
pattern.encrypt = 0;
pattern.skip = 0;
pattern.offset = 0;
// Decrypt the data
sts = OEMCrypto_DecryptCENC(
session_id(), &encryptedData[0], encryptedData.size(), true,
&encryptionIv[0], 0, &destBuffer, &pattern,
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample);
// We only have a few errors that we test are reported.
if (expected_result == OEMCrypto_SUCCESS) { // No error.
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
ASSERT_EQ(unencryptedData, outputBuffer);
} else if (expected_result == OEMCrypto_ERROR_KEY_EXPIRED) {
// Report stale keys.
ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, sts);
ASSERT_NE(unencryptedData, outputBuffer);
} else if (expected_result == OEMCrypto_ERROR_INSUFFICIENT_HDCP) {
// Report HDCP errors.
ASSERT_EQ(OEMCrypto_ERROR_INSUFFICIENT_HDCP, sts);
ASSERT_NE(unencryptedData, outputBuffer);
} else {
// OEM's can fine tune other error codes for debugging.
ASSERT_NE(OEMCrypto_SUCCESS, sts);
ASSERT_NE(unencryptedData, outputBuffer);
}
}
void Session::MakeRSACertificate(
struct RSAPrivateKeyMessage* encrypted, std::vector<uint8_t>* signature,
uint32_t allowed_schemes, const vector<uint8_t>& rsa_key) {
// Dummy context for testing signature generation.
vector<uint8_t> context = wvcdm::a2b_hex(
"0a4c08001248000000020000101907d9ffde13aa95c122678053362136bdf840"
"8f8276e4c2d87ec52b61aa1b9f646e58734930acebe899b3e464189a14a87202"
"fb02574e70640bd22ef44b2d7e3912250a230a14080112100915007caa9b5931"
"b76a3a85f046523e10011a09393837363534333231180120002a0c3138383637"
"38373430350000");
OEMCryptoResult sts;
// Generate signature
size_t gen_signature_length = 0;
sts = OEMCrypto_GenerateSignature(session_id(), &context[0], context.size(),
NULL, &gen_signature_length);
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
ASSERT_EQ(static_cast<size_t>(32), gen_signature_length);
vector<uint8_t> gen_signature(gen_signature_length);
sts = OEMCrypto_GenerateSignature(session_id(), &context[0], context.size(),
&gen_signature[0], &gen_signature_length);
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
std::vector<uint8_t> expected_signature;
ClientSignMessage(context, &expected_signature);
ASSERT_EQ(expected_signature, gen_signature);
// Rewrap Canned Response
// In the real world, the signature above would just have been used to
// contact the certificate provisioning server to get this response.
struct RSAPrivateKeyMessage message;
if (allowed_schemes != kSign_RSASSA_PSS) {
uint32_t algorithm_n = htonl(allowed_schemes);
memcpy(message.rsa_key, "SIGN", 4);
memcpy(message.rsa_key + 4, &algorithm_n, 4);
memcpy(message.rsa_key + 8, rsa_key.data(), rsa_key.size());
message.rsa_key_length = 8 + rsa_key.size();
} else {
memcpy(message.rsa_key, rsa_key.data(), rsa_key.size());
message.rsa_key_length = rsa_key.size();
}
EXPECT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_GetRandom(message.rsa_key_iv, wvcdm::KEY_IV_SIZE));
message.nonce = nonce_;
EncryptMessage(&message, encrypted);
ServerSignMessage(*encrypted, signature);
}
void Session::RewrapRSAKey(const struct RSAPrivateKeyMessage& encrypted,
const std::vector<uint8_t>& signature,
vector<uint8_t>* wrapped_key, bool force) {
size_t wrapped_key_length = 0;
const uint8_t* message_ptr = reinterpret_cast<const uint8_t*>(&encrypted);
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
OEMCrypto_RewrapDeviceRSAKey(
session_id(), message_ptr, sizeof(encrypted), &signature[0],
signature.size(), &encrypted.nonce, encrypted.rsa_key,
encrypted.rsa_key_length, encrypted.rsa_key_iv, NULL,
&wrapped_key_length));
wrapped_key->clear();
wrapped_key->assign(wrapped_key_length, 0);
OEMCryptoResult sts = OEMCrypto_RewrapDeviceRSAKey(
session_id(), message_ptr, sizeof(encrypted), &signature[0],
signature.size(), &encrypted.nonce, encrypted.rsa_key,
encrypted.rsa_key_length, encrypted.rsa_key_iv, &(wrapped_key->front()),
&wrapped_key_length);
if (force) {
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
}
if (OEMCrypto_SUCCESS != sts) {
wrapped_key->clear();
}
}
void Session::PreparePublicKey(const uint8_t* rsa_key,
size_t rsa_key_length) {
if (rsa_key == NULL) {
rsa_key = kTestRSAPKCS8PrivateKeyInfo2_2048;
rsa_key_length = sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048);
}
uint8_t* p = const_cast<uint8_t*>(rsa_key);
BIO* bio = BIO_new_mem_buf(p, rsa_key_length);
ASSERT_TRUE(NULL != bio);
PKCS8_PRIV_KEY_INFO* pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL);
ASSERT_TRUE(NULL != pkcs8_pki);
EVP_PKEY* evp = NULL;
evp = EVP_PKCS82PKEY(pkcs8_pki);
ASSERT_TRUE(NULL != evp);
if (public_rsa_) RSA_free(public_rsa_);
public_rsa_ = EVP_PKEY_get1_RSA(evp);
EVP_PKEY_free(evp);
PKCS8_PRIV_KEY_INFO_free(pkcs8_pki);
BIO_free(bio);
if (!public_rsa_) {
cout << "d2i_RSAPrivateKey failed. ";
dump_openssl_error();
ASSERT_TRUE(false);
}
switch (RSA_check_key(public_rsa_)) {
case 1: // valid.
ASSERT_TRUE(true);
return;
case 0: // not valid.
cout << "[rsa key not valid] ";
dump_openssl_error();
ASSERT_TRUE(false);
default: // -1 == check failed.
cout << "[error checking rsa key] ";
dump_openssl_error();
ASSERT_TRUE(false);
}
}
bool Session::VerifyPSSSignature(
EVP_PKEY* pkey, const uint8_t* message, size_t message_length,
const uint8_t* signature, size_t signature_length) {
EVP_MD_CTX ctx;
EVP_MD_CTX_init(&ctx);
EVP_PKEY_CTX* pctx = NULL;
if (EVP_DigestVerifyInit(&ctx, &pctx, EVP_sha1(), NULL /* no ENGINE */,
pkey) != 1) {
LOGE("EVP_DigestVerifyInit failed in VerifyPSSSignature");
goto err;
}
if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha1()) != 1) {
LOGE("EVP_PKEY_CTX_set_signature_md failed in VerifyPSSSignature");
goto err;
}
if (EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) != 1) {
LOGE("EVP_PKEY_CTX_set_rsa_padding failed in VerifyPSSSignature");
goto err;
}
if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, SHA_DIGEST_LENGTH) != 1) {
LOGE("EVP_PKEY_CTX_set_rsa_pss_saltlen failed in VerifyPSSSignature");
goto err;
}
if (EVP_DigestVerifyUpdate(&ctx, message, message_length) != 1) {
LOGE("EVP_DigestVerifyUpdate failed in VerifyPSSSignature");
goto err;
}
if (EVP_DigestVerifyFinal(&ctx, const_cast<uint8_t*>(signature),
signature_length) != 1) {
LOGE(
"EVP_DigestVerifyFinal failed in VerifyPSSSignature. (Probably a bad "
"signature.)");
goto err;
}
EVP_MD_CTX_cleanup(&ctx);
return true;
err:
dump_openssl_error();
EVP_MD_CTX_cleanup(&ctx);
return false;
}
void Session::VerifyRSASignature(
const vector<uint8_t>& message, const uint8_t* signature,
size_t signature_length, RSA_Padding_Scheme padding_scheme) {
EXPECT_TRUE(NULL != public_rsa_)
<< "No public RSA key loaded in test code.\n";
EXPECT_EQ(static_cast<size_t>(RSA_size(public_rsa_)), signature_length)
<< "Signature size is wrong. " << signature_length << ", should be "
<< RSA_size(public_rsa_) << "\n";
if (padding_scheme == kSign_RSASSA_PSS) {
EVP_PKEY* pkey = EVP_PKEY_new();
ASSERT_TRUE(EVP_PKEY_set1_RSA(pkey, public_rsa_) == 1);
const bool ok = VerifyPSSSignature(pkey, &message[0], message.size(),
signature, signature_length);
EVP_PKEY_free(pkey);
EXPECT_TRUE(ok) << "PSS signature check failed.";
} else if (padding_scheme == kSign_PKCS1_Block1) {
vector<uint8_t> padded_digest(signature_length);
int size;
// RSA_public_decrypt decrypts the signature, and then verifies that
// it was padded with RSA PKCS1 padding.
size = RSA_public_decrypt(signature_length, signature, &padded_digest[0],
public_rsa_, RSA_PKCS1_PADDING);
EXPECT_GT(size, 0);
padded_digest.resize(size);
EXPECT_EQ(message, padded_digest);
} else {
EXPECT_TRUE(false) << "Padding scheme not supported.";
}
}
bool Session::GenerateRSASessionKey(vector<uint8_t>* enc_session_key) {
if (!public_rsa_) {
cout << "No public RSA key loaded in test code.\n";
return false;
}
vector<uint8_t> session_key =
wvcdm::a2b_hex("6fa479c731d2770b6a61a5d1420bb9d1");
enc_session_key->assign(RSA_size(public_rsa_), 0);
int status = RSA_public_encrypt(session_key.size(), &session_key[0],
&(enc_session_key->front()), public_rsa_,
RSA_PKCS1_OAEP_PADDING);
int size = static_cast<int>(RSA_size(public_rsa_));
if (status != size) {
cout << "GenerateRSASessionKey error encrypting session key. ";
dump_openssl_error();
return false;
}
return true;
}
void Session::InstallRSASessionTestKey(
const vector<uint8_t>& wrapped_rsa_key) {
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_LoadDeviceRSAKey(session_id(), &wrapped_rsa_key[0],
wrapped_rsa_key.size()));
GenerateDerivedKeysFromSessionKey();
}
void Session::DisallowDeriveKeys() {
GenerateNonce(&nonce_);
vector<uint8_t> enc_session_key;
PreparePublicKey();
ASSERT_TRUE(GenerateRSASessionKey(&enc_session_key));
vector<uint8_t> mac_context;
vector<uint8_t> enc_context;
FillDefaultContext(&mac_context, &enc_context);
ASSERT_NE(OEMCrypto_SUCCESS,
OEMCrypto_DeriveKeysFromSessionKey(
session_id(), &enc_session_key[0], enc_session_key.size(),
&mac_context[0], mac_context.size(), &enc_context[0],
enc_context.size()));
}
void Session::GenerateReport(
const std::string& pst, bool expect_success, Session* other) {
if (other) { // If other is specified, copy mac keys.
mac_key_server_ = other->mac_key_server_;
mac_key_client_ = other->mac_key_client_;
}
size_t length = 0;
OEMCryptoResult sts = OEMCrypto_ReportUsage(
session_id(), reinterpret_cast<const uint8_t*>(pst.c_str()), pst.length(),
pst_report(), &length);
if (expect_success) {
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
}
if (sts == OEMCrypto_ERROR_SHORT_BUFFER) {
ASSERT_LE(sizeof(OEMCrypto_PST_Report), length);
pst_report_buffer_.resize(length);
}
sts = OEMCrypto_ReportUsage(session_id(),
reinterpret_cast<const uint8_t*>(pst.c_str()),
pst.length(), pst_report(), &length);
if (!expect_success) {
ASSERT_NE(OEMCrypto_SUCCESS, sts);
return;
}
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
vector<uint8_t> computed_signature(SHA_DIGEST_LENGTH);
unsigned int sig_len = SHA_DIGEST_LENGTH;
HMAC(EVP_sha1(), &mac_key_client_[0], mac_key_client_.size(),
reinterpret_cast<uint8_t*>(pst_report()) + SHA_DIGEST_LENGTH,
length - SHA_DIGEST_LENGTH, &computed_signature[0], &sig_len);
EXPECT_EQ(0, memcmp(&computed_signature[0], pst_report()->signature,
SHA_DIGEST_LENGTH));
EXPECT_GE(kInactive, pst_report()->status);
EXPECT_GE(kHardwareSecureClock, pst_report()->clock_security_level);
EXPECT_EQ(pst.length(), pst_report()->pst_length);
EXPECT_EQ(0, memcmp(pst.c_str(), pst_report()->pst, pst.length()));
}
OEMCrypto_PST_Report* Session::pst_report() {
return reinterpret_cast<OEMCrypto_PST_Report*>(&pst_report_buffer_[0]);
}
void Session::DeleteEntry(const std::string& pst) {
uint8_t* pst_ptr = encrypted_license_.pst;
memcpy(pst_ptr, pst.c_str(), min(sizeof(license_.pst), pst.length()));
ServerSignMessage(encrypted_license_, &signature_);
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_DeleteUsageEntry(session_id(), pst_ptr, pst.length(),
message_ptr(), sizeof(MessageData),
&signature_[0], signature_.size()));
}
void Session::ForceDeleteEntry(const std::string& pst) {
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_ForceDeleteUsageEntry(
reinterpret_cast<const uint8_t*>(pst.c_str()), pst.length()));
}
const uint8_t* Session::message_ptr() {
return reinterpret_cast<const uint8_t*>(&encrypted_license_);
}
} // namespace wvoec

View File

@@ -0,0 +1,207 @@
#ifndef CDM_OEC_SESSION_UTIL_H_
#define CDM_OEC_SESSION_UTIL_H_
// Copyright 2016 Google Inc. All Rights Reserved.
//
// OEMCrypto unit tests
//
#include <openssl/rsa.h>
#include <string>
#include <vector>
#include "oec_device_features.h"
#include "wv_cdm_constants.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 {
struct PatternTestVariant {
PatternTestVariant(size_t encrypt, size_t skip, OEMCryptoCipherMode mode) {
this->pattern.encrypt = encrypt;
this->pattern.skip = skip;
this->pattern.offset = 0;
this->mode = mode;
}
OEMCrypto_CENCEncryptPatternDesc pattern;
OEMCryptoCipherMode mode;
};
void PrintTo(const vector<uint8_t>& value, ostream* os);
void PrintTo(const PatternTestVariant& param, ostream* os);
} // namespace std
namespace wvoec {
const size_t kNumKeys = 4;
namespace {
#if defined(TEST_SPEED_MULTIPLIER) // Can slow test time limits when
// debugging is slowing everything.
const int kSpeedMultiplier = TEST_SPEED_MULTIPLIER;
#else
const int kSpeedMultiplier = 1;
#endif
const int kShortSleep = 1 * kSpeedMultiplier;
const int kLongSleep = 2 * kSpeedMultiplier;
const uint32_t kDuration = 2 * kSpeedMultiplier;
const uint32_t kLongDuration = 5 * kSpeedMultiplier;
const int32_t kTimeTolerance = 3 * 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.
const size_t kTestKeyIdMaxLength = 16;
// Most content will use a key id that is 16 bytes long.
const int kDefaultKeyIdLength = 16;
const size_t kMaxTestRSAKeyLength = 2000; // Rough estimate.
typedef struct {
uint8_t key_id[kTestKeyIdMaxLength];
size_t key_id_length;
uint8_t key_data[wvcdm::MAC_KEY_SIZE];
size_t key_data_length;
uint8_t key_iv[wvcdm::KEY_IV_SIZE];
uint8_t control_iv[wvcdm::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[kNumKeys];
uint8_t mac_key_iv[wvcdm::KEY_IV_SIZE];
uint8_t mac_keys[2 * wvcdm::MAC_KEY_SIZE];
uint8_t pst[kTestKeyIdMaxLength];
};
struct RSAPrivateKeyMessage {
uint8_t rsa_key[kMaxTestRSAKeyLength];
uint8_t rsa_key_iv[wvcdm::KEY_IV_SIZE];
size_t rsa_key_length;
uint32_t nonce;
};
// 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 openSSL
void dump_openssl_error();
class Session {
public:
Session();
~Session();
uint32_t get_nonce() { return nonce_; }
uint32_t session_id() { return (uint32_t)session_id_; }
void open();
void close();
void SetSessionId(uint32_t session_id);
uint32_t GetOecSessionId() { return session_id_; }
void GenerateNonce(uint32_t* nonce, int* error_counter = NULL);
void FillDefaultContext(vector<uint8_t>* mac_context,
vector<uint8_t>* enc_context);
void GenerateDerivedKeysFromKeybox();
void GenerateDerivedKeysFromSessionKey();
void GenerateTestSessionKeys();
void LoadTestKeys(const std::string& pst = "", bool new_mac_keys = true);
void VerifyTestKeys();
void RefreshTestKeys(const size_t key_count, uint32_t control_bits,
uint32_t nonce, OEMCryptoResult expected_result);
void SetKeyId(int index, const string& key_id);
void FillSimpleMessage(uint32_t duration, uint32_t control, uint32_t nonce,
const std::string& pst = "");
void FillRefreshMessage(size_t key_count, uint32_t control_bits,
uint32_t nonce);
void EncryptAndSign();
void EncryptMessage(RSAPrivateKeyMessage* data,
RSAPrivateKeyMessage* encrypted);
template <typename T>
void ServerSignMessage(const T& data, std::vector<uint8_t>* signature);
void ClientSignMessage(const vector<uint8_t>& data,
std::vector<uint8_t>* signature);
void FillKeyArray(const MessageData& data, OEMCrypto_KeyObject* key_array);
void FillRefreshArray(OEMCrypto_KeyRefreshObject* key_array,
size_t key_count);
void EncryptCTR(
const vector<uint8_t>& in_buffer, const uint8_t *key,
const uint8_t* starting_iv, vector<uint8_t>* out_buffer);
void TestDecryptCTR(bool select_key_first = true,
OEMCryptoResult expected_result = OEMCrypto_SUCCESS);
void MakeRSACertificate(
struct RSAPrivateKeyMessage* encrypted, std::vector<uint8_t>* signature,
uint32_t allowed_schemes, const vector<uint8_t>& rsa_key);
void RewrapRSAKey(const struct RSAPrivateKeyMessage& encrypted,
const std::vector<uint8_t>& signature,
vector<uint8_t>* wrapped_key, bool force);
void PreparePublicKey(const uint8_t* rsa_key = NULL,
size_t rsa_key_length = 0);
static bool VerifyPSSSignature(
EVP_PKEY* pkey, const uint8_t* message, size_t message_length,
const uint8_t* signature, size_t signature_length);
void VerifyRSASignature(
const vector<uint8_t>& message, const uint8_t* signature,
size_t signature_length, RSA_Padding_Scheme padding_scheme);
bool GenerateRSASessionKey(vector<uint8_t>* enc_session_key);
void InstallRSASessionTestKey(const vector<uint8_t>& wrapped_rsa_key);
void DisallowDeriveKeys();
void GenerateReport(const std::string& pst, bool expect_success = true,
Session* other = 0);
OEMCrypto_PST_Report* pst_report();
void DeleteEntry(const std::string& pst);
void ForceDeleteEntry(const std::string& pst);
MessageData& license() { return license_; }
MessageData& encrypted_license() { return encrypted_license_; }
const uint8_t* message_ptr();
OEMCrypto_KeyObject* key_array() { return key_array_; }
std::vector<uint8_t>& signature() { return signature_; }
private:
bool open_;
bool forced_session_id_;
OEMCrypto_SESSION session_id_;
vector<uint8_t> mac_key_server_;
vector<uint8_t> mac_key_client_;
vector<uint8_t> enc_key_;
uint32_t nonce_;
RSA* public_rsa_;
vector<uint8_t> pst_report_buffer_;
MessageData license_;
MessageData encrypted_license_;
OEMCrypto_KeyObject key_array_[kNumKeys];
std::vector<uint8_t> signature_;
};
} // namespace wvoec
#endif // CDM_OEC_SESSION_UTIL_H_

View File

@@ -0,0 +1,273 @@
#ifndef CDM_OEC_TEST_DATA_H_
#define CDM_OEC_TEST_DATA_H_
#include <string>
#if 0
#include "OEMCryptoCENC.h"
#include "wv_keybox.h"
#endif
namespace wvoec {
// These are test keyboxes. They will not be accepted by production systems.
// By using known keyboxes for these tests, the results for a given set of
// inputs to a test are predictable and can be compared to the actual results.
// The first keybox, kTestKeybox, with deviceID "TestKey01" is used for most of
// the tests. It should be loaded by OEMCrypto when OEMCrypto_LoadTestKeybox
// is called.
const wvoec_mock::WidevineKeybox kTestKeybox = {
// Sample keybox used for test vectors
{
// deviceID
0x54, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x30, // TestKey01
0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
}, {
// key
0xfb, 0xda, 0x04, 0x89, 0xa1, 0x58, 0x16, 0x0e,
0xa4, 0x02, 0xe9, 0x29, 0xe3, 0xb6, 0x8f, 0x04,
}, {
// data
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x19,
0x07, 0xd9, 0xff, 0xde, 0x13, 0xaa, 0x95, 0xc1,
0x22, 0x67, 0x80, 0x53, 0x36, 0x21, 0x36, 0xbd,
0xf8, 0x40, 0x8f, 0x82, 0x76, 0xe4, 0xc2, 0xd8,
0x7e, 0xc5, 0x2b, 0x61, 0xaa, 0x1b, 0x9f, 0x64,
0x6e, 0x58, 0x73, 0x49, 0x30, 0xac, 0xeb, 0xe8,
0x99, 0xb3, 0xe4, 0x64, 0x18, 0x9a, 0x14, 0xa8,
0x72, 0x02, 0xfb, 0x02, 0x57, 0x4e, 0x70, 0x64,
0x0b, 0xd2, 0x2e, 0xf4, 0x4b, 0x2d, 0x7e, 0x39,
}, {
// magic
0x6b, 0x62, 0x6f, 0x78,
}, {
// Crc
0x0a, 0x7a, 0x2c, 0x35,
}
};
static wvoec_mock::WidevineKeybox kValidKeybox02 = {
// Sample keybox used for test vectors
{
// deviceID
0x54, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x30, // TestKey02
0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
}, {
// key
0x76, 0x5d, 0xce, 0x01, 0x04, 0x89, 0xb3, 0xd0,
0xdf, 0xce, 0x54, 0x8a, 0x49, 0xda, 0xdc, 0xb6,
}, {
// data
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x19,
0x92, 0x27, 0x0b, 0x1f, 0x1a, 0xd5, 0xc6, 0x93,
0x19, 0x3f, 0xaa, 0x74, 0x1f, 0xdd, 0x5f, 0xb4,
0xe9, 0x40, 0x2f, 0x34, 0xa4, 0x92, 0xf4, 0xae,
0x9a, 0x52, 0x39, 0xbc, 0xb7, 0x24, 0x38, 0x13,
0xab, 0xf4, 0x92, 0x96, 0xc4, 0x81, 0x60, 0x33,
0xd8, 0xb8, 0x09, 0xc7, 0x55, 0x0e, 0x12, 0xfa,
0xa8, 0x98, 0x62, 0x8a, 0xec, 0xea, 0x74, 0x8a,
0x4b, 0xfa, 0x5a, 0x9e, 0xb6, 0x49, 0x0d, 0x80,
}, {
// magic
0x6b, 0x62, 0x6f, 0x78,
}, {
// Crc
0x2a, 0x3b, 0x3e, 0xe4,
}
};
static wvoec_mock::WidevineKeybox kValidKeybox03 = {
// Sample keybox used for test vectors
{
// deviceID
0x54, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x30, // TestKey03
0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
}, {
// key
0x25, 0xe5, 0x2a, 0x02, 0x29, 0x68, 0x04, 0xa2,
0x92, 0xfd, 0x7c, 0x67, 0x0b, 0x67, 0x1f, 0x31,
}, {
// data
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x19,
0xf4, 0x0a, 0x0e, 0xa2, 0x0a, 0x71, 0xd5, 0x92,
0xfa, 0xa3, 0x25, 0xc6, 0x4b, 0x76, 0xf1, 0x64,
0xf4, 0x60, 0xa0, 0x30, 0x72, 0x23, 0xbe, 0x03,
0xcd, 0xde, 0x7a, 0x06, 0xd4, 0x01, 0xeb, 0xdc,
0xe0, 0x50, 0xc0, 0x53, 0x0a, 0x50, 0xb0, 0x37,
0xe5, 0x05, 0x25, 0x0e, 0xa4, 0xc8, 0x5a, 0xff,
0x46, 0x6e, 0xa5, 0x31, 0xf3, 0xdd, 0x94, 0xb7,
0xe0, 0xd3, 0xf9, 0x04, 0xb2, 0x54, 0xb1, 0x64,
}, {
// magic
0x6b, 0x62, 0x6f, 0x78,
}, {
// Crc
0xa1, 0x99, 0x5f, 0x46,
}
};
// 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 };
} // namespace wvoec
#endif // CDM_OEC_TEST_DATA_H_

File diff suppressed because it is too large Load Diff

View File

@@ -88,7 +88,7 @@ TEST_F(OEMCryptoAndroidLMPTest, Level1Required) {
}
// These tests are required for M Android devices.
class OEMCryptoAndroidMNCTest : public OEMCryptoAndroidLMPTest {};
class OEMCryptoAndroidMNCTest : public OEMCryptoAndroidLMPTest {};
TEST_F(OEMCryptoAndroidMNCTest, MinVersionNumber10) {
uint32_t version = OEMCrypto_APIVersion();
@@ -111,4 +111,12 @@ TEST_F(OEMCryptoAndroidMNCTest, QueryKeyControlImplemented) {
OEMCrypto_QueryKeyControl(0, NULL, 0, NULL, NULL));
}
// 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);
}
} // namespace wvoec

View File

@@ -2,7 +2,7 @@
#include <iostream>
#include "log.h"
#include "oemcrypto_test.h"
#include "oec_device_features.h"
#include "OEMCryptoCENC.h"
#include "properties.h"