diff --git a/libwvdrmengine/oemcrypto/test/common.mk b/libwvdrmengine/oemcrypto/test/common.mk index 37ccaec2..2b488bbf 100644 --- a/libwvdrmengine/oemcrypto/test/common.mk +++ b/libwvdrmengine/oemcrypto/test/common.mk @@ -6,6 +6,8 @@ LOCAL_LDFLAGS+=-Wl,--hash-style=both endif LOCAL_SRC_FILES:= \ + oec_device_features.cpp \ + oec_session_util.cpp \ oemcrypto_test.cpp \ oemcrypto_test_android.cpp \ oemcrypto_test_main.cpp \ diff --git a/libwvdrmengine/oemcrypto/test/oec_device_features.cpp b/libwvdrmengine/oemcrypto/test/oec_device_features.cpp new file mode 100644 index 00000000..a5cc1a5f --- /dev/null +++ b/libwvdrmengine/oemcrypto/test/oec_device_features.cpp @@ -0,0 +1,148 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// OEMCrypto device features for unit tests +// +#include "oec_device_features.h" + +#include + +#include + +#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_Initialize 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(dev_id), + reinterpret_cast(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 diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_test.h b/libwvdrmengine/oemcrypto/test/oec_device_features.h similarity index 91% rename from libwvdrmengine/oemcrypto/test/oemcrypto_test.h rename to libwvdrmengine/oemcrypto/test/oec_device_features.h index 4a3988c7..76a3fc03 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_test.h +++ b/libwvdrmengine/oemcrypto/test/oec_device_features.h @@ -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 #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_ diff --git a/libwvdrmengine/oemcrypto/test/oec_session_util.cpp b/libwvdrmengine/oemcrypto/test/oec_session_util.cpp new file mode 100644 index 00000000..ac07d4ca --- /dev/null +++ b/libwvdrmengine/oemcrypto/test/oec_session_util.cpp @@ -0,0 +1,812 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// OEMCrypto unit tests +// + +#include "oec_session_util.h" + +#include // needed for ntoh() +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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& 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(NULL), iv); + uint64_t* counterBuffer = reinterpret_cast(&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* mac_context, + vector* 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 mac_context; + vector 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 enc_session_key; + PreparePublicKey(); + ASSERT_TRUE(GenerateRSASessionKey(&enc_session_key)); + vector mac_context; + vector 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(&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(&license_.keys[i].control), + reinterpret_cast(&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(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 +void Session::ServerSignMessage(const T& data, + std::vector* 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(&data), sizeof(data), + &(signature->front()), &md_len); +} + +template +void Session::ServerSignMessage( + const MessageData& data, + std::vector* signature); + +template +void Session::ServerSignMessage( + const RSAPrivateKeyMessage& data, + std::vector* signature); + +void Session::ClientSignMessage(const vector& data, + std::vector* 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(&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(&encrypted_license_.keys[i].control); + } +} + +void Session::EncryptCTR( + const vector& in_buffer, const uint8_t *key, + const uint8_t* starting_iv, vector* out_buffer) { + ASSERT_NE(static_cast(NULL), key); + ASSERT_NE(static_cast(NULL), starting_iv); + ASSERT_NE(static_cast(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 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 encryptionIv(wvcdm::KEY_IV_SIZE); + EXPECT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_GetRandom(&encryptionIv[0], wvcdm::KEY_IV_SIZE)); + vector encryptedData(unencryptedData.size()); + EncryptCTR(unencryptedData, license_.keys[0].key_data, &encryptionIv[0], + &encryptedData); + + // Describe the output + vector 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* signature, + uint32_t allowed_schemes, const vector& rsa_key) { + // Dummy context for testing signature generation. + vector 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(32), gen_signature_length); + vector 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 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& signature, + vector* wrapped_key, bool force) { + size_t wrapped_key_length = 0; + const uint8_t* message_ptr = reinterpret_cast(&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(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(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& 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(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 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* enc_session_key) { + if (!public_rsa_) { + cout << "No public RSA key loaded in test code.\n"; + return false; + } + vector 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(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& 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 enc_session_key; + PreparePublicKey(); + ASSERT_TRUE(GenerateRSASessionKey(&enc_session_key)); + vector mac_context; + vector 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(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(pst.c_str()), + pst.length(), pst_report(), &length); + if (!expect_success) { + ASSERT_NE(OEMCrypto_SUCCESS, sts); + return; + } + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + vector 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(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(&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(pst.c_str()), pst.length())); +} + +const uint8_t* Session::message_ptr() { + return reinterpret_cast(&encrypted_license_); +} + +} // namespace wvoec diff --git a/libwvdrmengine/oemcrypto/test/oec_session_util.h b/libwvdrmengine/oemcrypto/test/oec_session_util.h new file mode 100644 index 00000000..4a2bcc10 --- /dev/null +++ b/libwvdrmengine/oemcrypto/test/oec_session_util.h @@ -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 +#include +#include + +#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& 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* mac_context, + vector* 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 + void ServerSignMessage(const T& data, std::vector* signature); + + void ClientSignMessage(const vector& data, + std::vector* signature); + void FillKeyArray(const MessageData& data, OEMCrypto_KeyObject* key_array); + void FillRefreshArray(OEMCrypto_KeyRefreshObject* key_array, + size_t key_count); + void EncryptCTR( + const vector& in_buffer, const uint8_t *key, + const uint8_t* starting_iv, vector* out_buffer); + void TestDecryptCTR(bool select_key_first = true, + OEMCryptoResult expected_result = OEMCrypto_SUCCESS); + void MakeRSACertificate( + struct RSAPrivateKeyMessage* encrypted, std::vector* signature, + uint32_t allowed_schemes, const vector& rsa_key); + void RewrapRSAKey(const struct RSAPrivateKeyMessage& encrypted, + const std::vector& signature, + vector* 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& message, const uint8_t* signature, + size_t signature_length, RSA_Padding_Scheme padding_scheme); + bool GenerateRSASessionKey(vector* enc_session_key); + void InstallRSASessionTestKey(const vector& 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& signature() { return signature_; } + + private: + bool open_; + bool forced_session_id_; + OEMCrypto_SESSION session_id_; + vector mac_key_server_; + vector mac_key_client_; + vector enc_key_; + uint32_t nonce_; + RSA* public_rsa_; + vector pst_report_buffer_; + MessageData license_; + MessageData encrypted_license_; + OEMCrypto_KeyObject key_array_[kNumKeys]; + std::vector signature_; +}; + +} // namespace wvoec + +#endif // CDM_OEC_SESSION_UTIL_H_ diff --git a/libwvdrmengine/oemcrypto/test/oec_test_data.h b/libwvdrmengine/oemcrypto/test/oec_test_data.h new file mode 100644 index 00000000..074123a8 --- /dev/null +++ b/libwvdrmengine/oemcrypto/test/oec_test_data.h @@ -0,0 +1,277 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Test data for OEMCrypto unit tests. +// +#ifndef CDM_OEC_TEST_DATA_H_ +#define CDM_OEC_TEST_DATA_H_ + +#include + +#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_ diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp index fb1c03db..b6d33a30 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp @@ -26,8 +26,10 @@ #include #include "log.h" +#include "oec_session_util.h" +#include "oec_test_data.h" #include "oemcrypto_key_mock.h" -#include "oemcrypto_test.h" +#include "oec_device_features.h" #include "OEMCryptoCENC.h" #include "properties.h" #include "string_conversions.h" @@ -39,1244 +41,7 @@ using ::testing::WithParamInterface; using ::testing::Range; using ::testing::Values; -// 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& value, std::ostream* os) { - *os << wvcdm::b2a_hex(value); -} - -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 PatternTestVariant& param, ::std::ostream* os) { - *os << ((param.mode == OEMCrypto_CipherMode_CTR) ? "CTR mode" : "CBC mode") - << ", encrypt=" << param.pattern.encrypt - << ", skip=" << param.pattern.skip; -} -} // namespace std - namespace wvoec { -namespace { -const size_t kNumKeys = 4; -#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; -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]; -}; - -const size_t kMaxTestRSAKeyLength = 2000; // Rough estimate. -struct RSAPrivateKeyMessage { - uint8_t rsa_key[kMaxTestRSAKeyLength]; - uint8_t rsa_key_iv[wvcdm::KEY_IV_SIZE]; - size_t rsa_key_length; - uint32_t nonce; -}; - -// 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 }; - -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, "*Certificate*"); - if (!loads_certificate) FilterOut(&filter, "*LoadsCert*"); - 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(dev_id), - reinterpret_cast(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; - } -} - -static 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"; - } -} - -// 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(NULL), iv); - uint64_t* counterBuffer = reinterpret_cast(&iv[8]); - (*counterBuffer) = - wvcdm::htonll64(wvcdm::ntohll64(*counterBuffer) + increaseBy); -} - -class Session { - public: - Session() - : open_(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() { - if (open_) close(); - if (public_rsa_) RSA_free(public_rsa_); - } - - uint32_t get_nonce() { return nonce_; } - - uint32_t session_id() { return (uint32_t)session_id_; } - - void open() { - EXPECT_FALSE(open_); - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_OpenSession(&session_id_)); - open_ = true; - } - - void close() { - EXPECT_TRUE(open_); - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CloseSession(session_id_)); - open_ = false; - } - - void GenerateNonce(uint32_t* nonce, int* error_counter = NULL) { - 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 FillDefaultContext(vector* mac_context, - vector* 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 GenerateDerivedKeysFromKeybox() { - GenerateNonce(&nonce_); - vector mac_context; - vector 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 GenerateDerivedKeysFromSessionKey() { // Uses test certificate. - GenerateNonce(&nonce_); - vector enc_session_key; - PreparePublicKey(); - ASSERT_TRUE(GenerateRSASessionKey(&enc_session_key)); - vector mac_context; - vector 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 GenerateTestSessionKeys() { - if (global_features.derive_key_method == - DeviceFeatures::LOAD_TEST_RSA_KEY) { - GenerateDerivedKeysFromSessionKey(); - } else { - GenerateDerivedKeysFromKeybox(); - } - } - - void LoadTestKeys(const std::string& pst = "", bool new_mac_keys = true) { - 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 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(&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(license_.keys[i].control.duration), - htonl(block.duration)) - << "For key " << i; - ASSERT_EQ(htonl(license_.keys[i].control.control_bits), - htonl(block.control_bits)) - << "For key " << i; - } - } - } - - void 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 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 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 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 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(&license_.keys[i].control), - reinterpret_cast(&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 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(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 - void ServerSignMessage(const T& data, std::vector* 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(&data), sizeof(data), - &(signature->front()), &md_len); - } - - void ClientSignMessage(const vector& data, - std::vector* 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 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(&data.keys[i].control); - key_array[i].cipher_mode = data.keys[i].cipher_mode; - } - } - - void 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(&encrypted_license_.keys[i].control); - } - } - - void EncryptCTR(const vector& in_buffer,const uint8_t *key, - const uint8_t* starting_iv, - vector* out_buffer) { - ASSERT_NE(static_cast(NULL), key); - ASSERT_NE(static_cast(NULL), starting_iv); - ASSERT_NE(static_cast(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 TestDecryptCTR(bool select_key_first = true, - OEMCryptoResult expected_result = OEMCrypto_SUCCESS) { - 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 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 encryptionIv(wvcdm::KEY_IV_SIZE); - EXPECT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_GetRandom(&encryptionIv[0], wvcdm::KEY_IV_SIZE)); - vector encryptedData(unencryptedData.size()); - EncryptCTR(unencryptedData, license_.keys[0].key_data, &encryptionIv[0], - &encryptedData); - - // Describe the output - vector 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 MakeRSACertificate(struct RSAPrivateKeyMessage* encrypted, - std::vector* signature, - uint32_t allowed_schemes, - const vector& rsa_key) { - // Dummy context for testing signature generation. - vector 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(32), gen_signature_length); - vector 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 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 RewrapRSAKey(const struct RSAPrivateKeyMessage& encrypted, - const std::vector& signature, - vector* wrapped_key, bool force) { - size_t wrapped_key_length = 0; - const uint8_t* message_ptr = reinterpret_cast(&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 PreparePublicKey(const uint8_t* rsa_key = NULL, - size_t rsa_key_length = 0) { - if (rsa_key == NULL) { - rsa_key = kTestRSAPKCS8PrivateKeyInfo2_2048; - rsa_key_length = sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048); - } - uint8_t* p = const_cast(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); - } - } - - static bool 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(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 VerifyRSASignature(const vector& 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(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 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 GenerateRSASessionKey(vector* enc_session_key) { - if (!public_rsa_) { - cout << "No public RSA key loaded in test code.\n"; - return false; - } - vector 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(RSA_size(public_rsa_)); - if (status != size) { - cout << "GenerateRSASessionKey error encrypting session key. "; - dump_openssl_error(); - return false; - } - return true; - } - - void InstallRSASessionTestKey(const vector& wrapped_rsa_key) { - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_LoadDeviceRSAKey(session_id(), &wrapped_rsa_key[0], - wrapped_rsa_key.size())); - GenerateDerivedKeysFromSessionKey(); - } - - void DisallowDeriveKeys() { - GenerateNonce(&nonce_); - vector enc_session_key; - PreparePublicKey(); - ASSERT_TRUE(GenerateRSASessionKey(&enc_session_key)); - vector mac_context; - vector 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 GenerateReport(const std::string& pst, bool expect_success = true, - Session* other = 0) { - 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(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(pst.c_str()), - pst.length(), pst_report(), &length); - if (!expect_success) { - ASSERT_NE(OEMCrypto_SUCCESS, sts); - return; - } - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - vector 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(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* pst_report() { - return reinterpret_cast(&pst_report_buffer_[0]); - } - - void 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 ForceDeleteEntry(const std::string& pst) { - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_ForceDeleteUsageEntry( - reinterpret_cast(pst.c_str()), pst.length())); - } - - MessageData& license() { return license_; } - MessageData& encrypted_license() { return encrypted_license_; } - const uint8_t* message_ptr() { - return reinterpret_cast(&encrypted_license_); - } - OEMCrypto_KeyObject* key_array() { return key_array_; } - std::vector& signature() { return signature_; } - - private: - bool open_; - OEMCrypto_SESSION session_id_; - vector mac_key_server_; - vector mac_key_client_; - vector enc_key_; - uint32_t nonce_; - RSA* public_rsa_; - vector pst_report_buffer_; - MessageData license_; - MessageData encrypted_license_; - OEMCrypto_KeyObject key_array_[kNumKeys]; - std::vector signature_; -}; class OEMCryptoClientTest : public ::testing::Test { protected: diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_test_main.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_test_main.cpp index a6d14959..e989bd90 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_test_main.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_test_main.cpp @@ -2,7 +2,7 @@ #include #include "log.h" -#include "oemcrypto_test.h" +#include "oec_device_features.h" #include "OEMCryptoCENC.h" #include "properties.h"