Refactor generic crypto unit tests
Refactor the generic crypto oemcrypto unit tests into a separate file. Bug: 253779846 Merged from https://widevine-internal-review.googlesource.com/176730 Change-Id: I343ee19ef979a9bedbc528a4533711a137ffb5e9
This commit is contained in:
@@ -18,6 +18,7 @@ LOCAL_SRC_FILES:= \
|
||||
oemcrypto_session_tests_helper.cpp \
|
||||
oemcrypto_basic_test.cpp \
|
||||
oemcrypto_decrypt_test.cpp \
|
||||
oemcrypto_generic_crypto_test.cpp \
|
||||
oemcrypto_license_test.cpp \
|
||||
oemcrypto_provisioning_test.cpp \
|
||||
oemcrypto_usage_table_test.cpp \
|
||||
|
||||
577
libwvdrmengine/oemcrypto/test/oemcrypto_generic_crypto_test.cpp
Normal file
577
libwvdrmengine/oemcrypto/test/oemcrypto_generic_crypto_test.cpp
Normal file
@@ -0,0 +1,577 @@
|
||||
// Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine
|
||||
// License Agreement.
|
||||
//
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "oemcrypto_usage_table_test.h"
|
||||
|
||||
using ::testing::Range;
|
||||
|
||||
namespace wvoec {
|
||||
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyLoad) { EncryptAndLoadKeys(); }
|
||||
|
||||
// Test that the Generic_Encrypt function works correctly.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyEncrypt) {
|
||||
EncryptAndLoadKeys();
|
||||
unsigned int key_index = 0;
|
||||
vector<uint8_t> expected_encrypted;
|
||||
EncryptBuffer(key_index, clear_buffer_, &expected_encrypted);
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
vector<uint8_t> encrypted(clear_buffer_.size());
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
GenericEncrypt(key_handle.data(), key_handle.size(),
|
||||
clear_buffer_.data(), clear_buffer_.size(), iv_,
|
||||
OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data()));
|
||||
ASSERT_EQ(expected_encrypted, encrypted);
|
||||
}
|
||||
|
||||
// Test that the Generic_Encrypt function fails when not allowed.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyBadEncrypt) {
|
||||
EncryptAndLoadKeys();
|
||||
BadEncrypt(0, OEMCrypto_HMAC_SHA256, buffer_size_);
|
||||
// The buffer size must be a multiple of 16, so subtracting 10 is bad.
|
||||
BadEncrypt(0, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_ - 10);
|
||||
BadEncrypt(1, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_);
|
||||
BadEncrypt(2, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_);
|
||||
BadEncrypt(3, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_);
|
||||
}
|
||||
|
||||
// Test that the Generic_Encrypt works if the input and output buffers are the
|
||||
// same.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyEncryptSameBufferAPI12) {
|
||||
EncryptAndLoadKeys();
|
||||
unsigned int key_index = 0;
|
||||
vector<uint8_t> expected_encrypted;
|
||||
EncryptBuffer(key_index, clear_buffer_, &expected_encrypted);
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
// Input and output are same buffer:
|
||||
vector<uint8_t> buffer = clear_buffer_;
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
GenericEncrypt(key_handle.data(), key_handle.size(), buffer.data(),
|
||||
buffer.size(), iv_, OEMCrypto_AES_CBC_128_NO_PADDING,
|
||||
buffer.data()));
|
||||
ASSERT_EQ(expected_encrypted, buffer);
|
||||
}
|
||||
|
||||
TEST_P(
|
||||
OEMCryptoGenericCryptoTest,
|
||||
OEMCryptoMemoryGenericKeyEncryptForHugeBufferWithBufferLengthNotMultipleOf16) {
|
||||
EncryptAndLoadKeys();
|
||||
unsigned int key_index = 0;
|
||||
vector<uint8_t> expected_encrypted;
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
vector<uint8_t> buffer(17);
|
||||
ASSERT_NO_FATAL_FAILURE(OEMCrypto_Generic_Encrypt(
|
||||
key_handle.data(), key_handle.size(), buffer.data(), buffer.size(), iv_,
|
||||
OEMCrypto_AES_CBC_128_NO_PADDING, buffer.data()));
|
||||
}
|
||||
|
||||
// Test Generic_Decrypt works correctly.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyDecrypt) {
|
||||
EncryptAndLoadKeys();
|
||||
unsigned int key_index = 1;
|
||||
vector<uint8_t> encrypted;
|
||||
EncryptBuffer(key_index, clear_buffer_, &encrypted);
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
vector<uint8_t> resultant(encrypted.size());
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
GenericDecrypt(key_handle.data(), key_handle.size(),
|
||||
encrypted.data(), encrypted.size(), iv_,
|
||||
OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data()));
|
||||
ASSERT_EQ(clear_buffer_, resultant);
|
||||
}
|
||||
|
||||
// Test that Generic_Decrypt works correctly when the input and output buffers
|
||||
// are the same.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyDecryptSameBufferAPI12) {
|
||||
EncryptAndLoadKeys();
|
||||
unsigned int key_index = 1;
|
||||
vector<uint8_t> encrypted;
|
||||
EncryptBuffer(key_index, clear_buffer_, &encrypted);
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
vector<uint8_t> buffer = encrypted;
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
GenericDecrypt(key_handle.data(), key_handle.size(), buffer.data(),
|
||||
buffer.size(), iv_, OEMCrypto_AES_CBC_128_NO_PADDING,
|
||||
buffer.data()));
|
||||
ASSERT_EQ(clear_buffer_, buffer);
|
||||
}
|
||||
|
||||
// Test that Generic_Decrypt fails to decrypt to an insecure buffer if the key
|
||||
// requires a secure data path.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericSecureToClear) {
|
||||
license_messages_.set_control(wvoec::kControlObserveDataPath |
|
||||
wvoec::kControlDataPathSecure);
|
||||
license_messages_.CreateResponseWithGenericCryptoKeys();
|
||||
EncryptAndLoadKeys();
|
||||
unsigned int key_index = 1;
|
||||
vector<uint8_t> encrypted;
|
||||
EncryptBuffer(key_index, clear_buffer_, &encrypted);
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
vector<uint8_t> resultant(encrypted.size());
|
||||
ASSERT_NE(OEMCrypto_SUCCESS,
|
||||
GenericDecrypt(key_handle.data(), key_handle.size(),
|
||||
encrypted.data(), encrypted.size(), iv_,
|
||||
OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data()));
|
||||
ASSERT_NE(clear_buffer_, resultant);
|
||||
}
|
||||
|
||||
// Test that the Generic_Decrypt function fails when not allowed.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyBadDecrypt) {
|
||||
EncryptAndLoadKeys();
|
||||
BadDecrypt(1, OEMCrypto_HMAC_SHA256, buffer_size_);
|
||||
// The buffer size must be a multiple of 16, so subtracting 10 is bad.
|
||||
BadDecrypt(1, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_ - 10);
|
||||
BadDecrypt(0, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_);
|
||||
BadDecrypt(2, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_);
|
||||
BadDecrypt(3, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_);
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeySign) {
|
||||
EncryptAndLoadKeys();
|
||||
unsigned int key_index = 2;
|
||||
vector<uint8_t> expected_signature;
|
||||
SignBuffer(key_index, clear_buffer_, &expected_signature);
|
||||
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
size_t gen_signature_length = 0;
|
||||
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
|
||||
GenericSign(key_handle.data(), key_handle.size(),
|
||||
clear_buffer_.data(), clear_buffer_.size(),
|
||||
OEMCrypto_HMAC_SHA256, nullptr, &gen_signature_length));
|
||||
ASSERT_EQ(static_cast<size_t>(SHA256_DIGEST_LENGTH), gen_signature_length);
|
||||
vector<uint8_t> signature(SHA256_DIGEST_LENGTH);
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GenericSign(key_handle.data(), key_handle.size(), clear_buffer_.data(),
|
||||
clear_buffer_.size(), OEMCrypto_HMAC_SHA256, signature.data(),
|
||||
&gen_signature_length));
|
||||
ASSERT_EQ(expected_signature, signature);
|
||||
}
|
||||
|
||||
// Test that the Generic_Sign function fails when not allowed.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyBadSign) {
|
||||
EncryptAndLoadKeys();
|
||||
BadSign(0, OEMCrypto_HMAC_SHA256); // Can't sign with encrypt key.
|
||||
BadSign(1, OEMCrypto_HMAC_SHA256); // Can't sign with decrypt key.
|
||||
BadSign(3, OEMCrypto_HMAC_SHA256); // Can't sign with verify key.
|
||||
BadSign(2, OEMCrypto_AES_CBC_128_NO_PADDING); // Bad signing algorithm.
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyVerify) {
|
||||
EncryptAndLoadKeys();
|
||||
unsigned int key_index = 3;
|
||||
vector<uint8_t> signature;
|
||||
SignBuffer(key_index, clear_buffer_, &signature);
|
||||
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GenericVerify(key_handle.data(), key_handle.size(), clear_buffer_.data(),
|
||||
clear_buffer_.size(), OEMCrypto_HMAC_SHA256,
|
||||
signature.data(), signature.size()));
|
||||
}
|
||||
|
||||
// Test that the Generic_Verify function fails when not allowed.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyBadVerify) {
|
||||
EncryptAndLoadKeys();
|
||||
BadVerify(0, OEMCrypto_HMAC_SHA256, SHA256_DIGEST_LENGTH, false);
|
||||
BadVerify(1, OEMCrypto_HMAC_SHA256, SHA256_DIGEST_LENGTH, false);
|
||||
BadVerify(2, OEMCrypto_HMAC_SHA256, SHA256_DIGEST_LENGTH, false);
|
||||
BadVerify(3, OEMCrypto_HMAC_SHA256, SHA256_DIGEST_LENGTH, true);
|
||||
BadVerify(3, OEMCrypto_HMAC_SHA256, SHA256_DIGEST_LENGTH - 1, false);
|
||||
BadVerify(3, OEMCrypto_HMAC_SHA256, SHA256_DIGEST_LENGTH + 1, false);
|
||||
BadVerify(3, OEMCrypto_AES_CBC_128_NO_PADDING, SHA256_DIGEST_LENGTH, false);
|
||||
}
|
||||
|
||||
// Test Generic_Encrypt with the maximum buffer size.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyEncryptLargeBuffer) {
|
||||
ResizeBuffer(GetResourceValue(kMaxGenericBuffer));
|
||||
EncryptAndLoadKeys();
|
||||
unsigned int key_index = 0;
|
||||
vector<uint8_t> expected_encrypted;
|
||||
EncryptBuffer(key_index, clear_buffer_, &expected_encrypted);
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
vector<uint8_t> encrypted(clear_buffer_.size());
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
GenericEncrypt(key_handle.data(), key_handle.size(),
|
||||
clear_buffer_.data(), clear_buffer_.size(), iv_,
|
||||
OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data()));
|
||||
ASSERT_EQ(expected_encrypted, encrypted);
|
||||
}
|
||||
|
||||
// Test Generic_Decrypt with the maximum buffer size.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyDecryptLargeBuffer) {
|
||||
// Some applications are known to pass in a block that is almost 400k.
|
||||
ResizeBuffer(GetResourceValue(kMaxGenericBuffer));
|
||||
EncryptAndLoadKeys();
|
||||
unsigned int key_index = 1;
|
||||
vector<uint8_t> encrypted;
|
||||
EncryptBuffer(key_index, clear_buffer_, &encrypted);
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
vector<uint8_t> resultant(encrypted.size());
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
GenericDecrypt(key_handle.data(), key_handle.size(),
|
||||
encrypted.data(), encrypted.size(), iv_,
|
||||
OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data()));
|
||||
ASSERT_EQ(clear_buffer_, resultant);
|
||||
}
|
||||
|
||||
// Test Generic_Sign with the maximum buffer size.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeySignLargeBuffer) {
|
||||
ResizeBuffer(GetResourceValue(kMaxGenericBuffer));
|
||||
EncryptAndLoadKeys();
|
||||
unsigned int key_index = 2;
|
||||
vector<uint8_t> expected_signature;
|
||||
SignBuffer(key_index, clear_buffer_, &expected_signature);
|
||||
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
size_t gen_signature_length = 0;
|
||||
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
|
||||
GenericSign(key_handle.data(), key_handle.size(),
|
||||
clear_buffer_.data(), clear_buffer_.size(),
|
||||
OEMCrypto_HMAC_SHA256, nullptr, &gen_signature_length));
|
||||
ASSERT_EQ(static_cast<size_t>(SHA256_DIGEST_LENGTH), gen_signature_length);
|
||||
vector<uint8_t> signature(SHA256_DIGEST_LENGTH);
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GenericSign(key_handle.data(), key_handle.size(), clear_buffer_.data(),
|
||||
clear_buffer_.size(), OEMCrypto_HMAC_SHA256, signature.data(),
|
||||
&gen_signature_length));
|
||||
ASSERT_EQ(expected_signature, signature);
|
||||
}
|
||||
|
||||
// Test Generic_Verify with the maximum buffer size.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyVerifyLargeBuffer) {
|
||||
ResizeBuffer(GetResourceValue(kMaxGenericBuffer));
|
||||
EncryptAndLoadKeys();
|
||||
unsigned int key_index = 3;
|
||||
vector<uint8_t> signature;
|
||||
SignBuffer(key_index, clear_buffer_, &signature);
|
||||
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GenericVerify(key_handle.data(), key_handle.size(), clear_buffer_.data(),
|
||||
clear_buffer_.size(), OEMCrypto_HMAC_SHA256,
|
||||
signature.data(), signature.size()));
|
||||
}
|
||||
|
||||
// Test Generic_Encrypt when the key duration has expired.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, KeyDurationEncrypt) {
|
||||
license_messages_.core_response()
|
||||
.timer_limits.total_playback_duration_seconds = kDuration;
|
||||
license_messages_.CreateResponseWithGenericCryptoKeys();
|
||||
EncryptAndLoadKeys();
|
||||
vector<uint8_t> expected_encrypted;
|
||||
EncryptBuffer(0, clear_buffer_, &expected_encrypted);
|
||||
unsigned int key_index = 0;
|
||||
vector<uint8_t> encrypted(clear_buffer_.size());
|
||||
|
||||
vector<uint8_t> key_handle;
|
||||
// Should be valid key at the start.
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
GenericEncrypt(key_handle.data(), key_handle.size(),
|
||||
clear_buffer_.data(), clear_buffer_.size(), iv_,
|
||||
OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data()));
|
||||
ASSERT_EQ(expected_encrypted, encrypted);
|
||||
|
||||
wvutil::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key.
|
||||
encrypted.assign(clear_buffer_.size(), 0);
|
||||
OEMCryptoResult status = OEMCrypto_Generic_Encrypt(
|
||||
key_handle.data(), key_handle.size(), clear_buffer_.data(),
|
||||
clear_buffer_.size(), iv_, OEMCrypto_AES_CBC_128_NO_PADDING,
|
||||
encrypted.data());
|
||||
ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status);
|
||||
ASSERT_NE(encrypted, expected_encrypted);
|
||||
ASSERT_NO_FATAL_FAILURE(session_.TestGetKeyHandleExpired(key_index));
|
||||
}
|
||||
|
||||
// Test Generic_Decrypt when the key duration has expired.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, KeyDurationDecrypt) {
|
||||
license_messages_.core_response()
|
||||
.timer_limits.total_playback_duration_seconds = kDuration;
|
||||
license_messages_.CreateResponseWithGenericCryptoKeys();
|
||||
EncryptAndLoadKeys();
|
||||
|
||||
// Should be valid key at the start.
|
||||
unsigned int key_index = 1;
|
||||
vector<uint8_t> encrypted;
|
||||
EncryptBuffer(key_index, clear_buffer_, &encrypted);
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
vector<uint8_t> resultant(encrypted.size());
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
GenericDecrypt(key_handle.data(), key_handle.size(),
|
||||
encrypted.data(), encrypted.size(), iv_,
|
||||
OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data()));
|
||||
ASSERT_EQ(clear_buffer_, resultant);
|
||||
|
||||
wvutil::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key.
|
||||
resultant.assign(encrypted.size(), 0);
|
||||
OEMCryptoResult status = GenericDecrypt(
|
||||
key_handle.data(), key_handle.size(), encrypted.data(), encrypted.size(),
|
||||
iv_, OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data());
|
||||
ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status);
|
||||
ASSERT_NE(clear_buffer_, resultant);
|
||||
ASSERT_NO_FATAL_FAILURE(session_.TestGetKeyHandleExpired(key_index));
|
||||
}
|
||||
|
||||
// Test Generic_Sign when the key duration has expired.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, KeyDurationSign) {
|
||||
license_messages_.core_response()
|
||||
.timer_limits.total_playback_duration_seconds = kDuration;
|
||||
license_messages_.CreateResponseWithGenericCryptoKeys();
|
||||
EncryptAndLoadKeys();
|
||||
|
||||
unsigned int key_index = 2;
|
||||
vector<uint8_t> expected_signature;
|
||||
vector<uint8_t> signature(SHA256_DIGEST_LENGTH);
|
||||
size_t signature_length = signature.size();
|
||||
SignBuffer(key_index, clear_buffer_, &expected_signature);
|
||||
|
||||
vector<uint8_t> key_handle;
|
||||
// Should be valid key at the start.
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GenericSign(key_handle.data(), key_handle.size(), clear_buffer_.data(),
|
||||
clear_buffer_.size(), OEMCrypto_HMAC_SHA256, signature.data(),
|
||||
&signature_length));
|
||||
ASSERT_EQ(expected_signature, signature);
|
||||
|
||||
wvutil::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key.
|
||||
signature.assign(SHA256_DIGEST_LENGTH, 0);
|
||||
OEMCryptoResult status =
|
||||
GenericSign(key_handle.data(), key_handle.size(), clear_buffer_.data(),
|
||||
clear_buffer_.size(), OEMCrypto_HMAC_SHA256, signature.data(),
|
||||
&signature_length);
|
||||
ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status);
|
||||
ASSERT_NE(expected_signature, signature);
|
||||
ASSERT_NO_FATAL_FAILURE(session_.TestGetKeyHandleExpired(key_index));
|
||||
}
|
||||
|
||||
// Test Generic_Verify when the key duration has expired.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, KeyDurationVerify) {
|
||||
license_messages_.core_response()
|
||||
.timer_limits.total_playback_duration_seconds = kDuration;
|
||||
license_messages_.CreateResponseWithGenericCryptoKeys();
|
||||
EncryptAndLoadKeys();
|
||||
|
||||
unsigned int key_index = 3;
|
||||
vector<uint8_t> signature;
|
||||
SignBuffer(key_index, clear_buffer_, &signature);
|
||||
|
||||
vector<uint8_t> key_handle;
|
||||
// Should be valid key at the start.
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GenericVerify(key_handle.data(), key_handle.size(), clear_buffer_.data(),
|
||||
clear_buffer_.size(), OEMCrypto_HMAC_SHA256,
|
||||
signature.data(), signature.size()));
|
||||
|
||||
wvutil::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key.
|
||||
OEMCryptoResult status = OEMCrypto_Generic_Verify(
|
||||
key_handle.data(), key_handle.size(), clear_buffer_.data(),
|
||||
clear_buffer_.size(), OEMCrypto_HMAC_SHA256, signature.data(),
|
||||
signature.size());
|
||||
ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status);
|
||||
ASSERT_NO_FATAL_FAILURE(session_.TestGetKeyHandleExpired(key_index));
|
||||
}
|
||||
|
||||
const unsigned int kLongKeyId = 2;
|
||||
|
||||
// Test that short key ids are allowed.
|
||||
class OEMCryptoGenericCryptoKeyIdLengthTest
|
||||
: public OEMCryptoGenericCryptoTest {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
OEMCryptoGenericCryptoTest::SetUp();
|
||||
license_messages_.set_num_keys(5);
|
||||
license_messages_.set_control(wvoec::kControlAllowDecrypt);
|
||||
license_messages_.core_response()
|
||||
.timer_limits.total_playback_duration_seconds = kDuration;
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
SetUniformKeyIdLength(16); // Start with all key ids being 16 bytes.
|
||||
// But, we are testing that the key ids do not have to have the same
|
||||
// length.
|
||||
// 12 bytes (common key id length).
|
||||
license_messages_.SetKeyId(0, "123456789012");
|
||||
license_messages_.SetKeyId(1, "12345"); // short key id.
|
||||
// 16 byte key id. (default)
|
||||
license_messages_.SetKeyId(2, "1234567890123456");
|
||||
license_messages_.SetKeyId(3, "12345678901234"); // 14 byte. (uncommon)
|
||||
license_messages_.SetKeyId(4, "1"); // very short key id.
|
||||
ASSERT_EQ(2u, kLongKeyId);
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.FillCoreResponseSubstrings());
|
||||
}
|
||||
|
||||
// Make all four keys have the same length.
|
||||
void SetUniformKeyIdLength(size_t key_id_length) {
|
||||
for (size_t i = 0; i < license_messages_.num_keys(); i++) {
|
||||
string key_id;
|
||||
key_id.resize(key_id_length, i + 'a');
|
||||
license_messages_.SetKeyId(i, key_id);
|
||||
}
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.FillCoreResponseSubstrings());
|
||||
}
|
||||
|
||||
void TestWithKey(unsigned int key_index) {
|
||||
ASSERT_LT(key_index, license_messages_.num_keys());
|
||||
EncryptAndLoadKeys();
|
||||
vector<uint8_t> encrypted;
|
||||
// To make sure OEMCrypto is not expecting the key_id to be zero padded,
|
||||
// we will create a buffer that is padded with 'Z'. Then, we use fill
|
||||
// the buffer with the longer of the three keys. If OEMCrypto is paying
|
||||
// attention to the key id length, it should pick out the correct key.
|
||||
vector<uint8_t> key_id_buffer(
|
||||
session_.license().keys[kLongKeyId].key_id_length + 5,
|
||||
'Z'); // Fill a bigger buffer with letter 'Z'.
|
||||
memcpy(key_id_buffer.data(), session_.license().keys[kLongKeyId].key_id,
|
||||
session_.license().keys[kLongKeyId].key_id_length);
|
||||
EncryptBuffer(key_index, clear_buffer_, &encrypted);
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(), key_id_buffer.data(),
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
vector<uint8_t> resultant(encrypted.size());
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
OEMCrypto_Generic_Decrypt(key_handle.data(), key_handle.size(),
|
||||
encrypted.data(), encrypted.size(), iv_,
|
||||
OEMCrypto_AES_CBC_128_NO_PADDING,
|
||||
resultant.data()));
|
||||
ASSERT_EQ(clear_buffer_, resultant);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(OEMCryptoGenericCryptoKeyIdLengthTest, MediumKeyId) { TestWithKey(0); }
|
||||
|
||||
TEST_P(OEMCryptoGenericCryptoKeyIdLengthTest, ShortKeyId) { TestWithKey(1); }
|
||||
|
||||
TEST_P(OEMCryptoGenericCryptoKeyIdLengthTest, LongKeyId) { TestWithKey(2); }
|
||||
|
||||
TEST_P(OEMCryptoGenericCryptoKeyIdLengthTest, FourteenByteKeyId) {
|
||||
TestWithKey(3);
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoGenericCryptoKeyIdLengthTest, VeryShortKeyId) {
|
||||
TestWithKey(4);
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoGenericCryptoKeyIdLengthTest, UniformShortKeyId) {
|
||||
SetUniformKeyIdLength(5);
|
||||
TestWithKey(2);
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoGenericCryptoKeyIdLengthTest, UniformLongKeyId) {
|
||||
SetUniformKeyIdLength(kTestKeyIdMaxLength);
|
||||
TestWithKey(2);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoGenericCryptoTest,
|
||||
Range<uint32_t>(kCoreMessagesAPI, kCurrentAPI + 1));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoGenericCryptoKeyIdLengthTest,
|
||||
Range<uint32_t>(kCoreMessagesAPI, kCurrentAPI + 1));
|
||||
|
||||
/// @}
|
||||
} // namespace wvoec
|
||||
@@ -2781,570 +2781,4 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_20) {
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// @addtogroup generic
|
||||
/// @{
|
||||
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyLoad) { EncryptAndLoadKeys(); }
|
||||
|
||||
// Test that the Generic_Encrypt function works correctly.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyEncrypt) {
|
||||
EncryptAndLoadKeys();
|
||||
unsigned int key_index = 0;
|
||||
vector<uint8_t> expected_encrypted;
|
||||
EncryptBuffer(key_index, clear_buffer_, &expected_encrypted);
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
vector<uint8_t> encrypted(clear_buffer_.size());
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
GenericEncrypt(key_handle.data(), key_handle.size(),
|
||||
clear_buffer_.data(), clear_buffer_.size(), iv_,
|
||||
OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data()));
|
||||
ASSERT_EQ(expected_encrypted, encrypted);
|
||||
}
|
||||
|
||||
// Test that the Generic_Encrypt function fails when not allowed.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyBadEncrypt) {
|
||||
EncryptAndLoadKeys();
|
||||
BadEncrypt(0, OEMCrypto_HMAC_SHA256, buffer_size_);
|
||||
// The buffer size must be a multiple of 16, so subtracting 10 is bad.
|
||||
BadEncrypt(0, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_ - 10);
|
||||
BadEncrypt(1, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_);
|
||||
BadEncrypt(2, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_);
|
||||
BadEncrypt(3, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_);
|
||||
}
|
||||
|
||||
// Test that the Generic_Encrypt works if the input and output buffers are the
|
||||
// same.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyEncryptSameBufferAPI12) {
|
||||
EncryptAndLoadKeys();
|
||||
unsigned int key_index = 0;
|
||||
vector<uint8_t> expected_encrypted;
|
||||
EncryptBuffer(key_index, clear_buffer_, &expected_encrypted);
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
// Input and output are same buffer:
|
||||
vector<uint8_t> buffer = clear_buffer_;
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
GenericEncrypt(key_handle.data(), key_handle.size(), buffer.data(),
|
||||
buffer.size(), iv_, OEMCrypto_AES_CBC_128_NO_PADDING,
|
||||
buffer.data()));
|
||||
ASSERT_EQ(expected_encrypted, buffer);
|
||||
}
|
||||
|
||||
TEST_P(
|
||||
OEMCryptoGenericCryptoTest,
|
||||
OEMCryptoMemoryGenericKeyEncryptForHugeBufferWithBufferLengthNotMultipleOf16) {
|
||||
EncryptAndLoadKeys();
|
||||
unsigned int key_index = 0;
|
||||
vector<uint8_t> expected_encrypted;
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
vector<uint8_t> buffer(17);
|
||||
ASSERT_NO_FATAL_FAILURE(OEMCrypto_Generic_Encrypt(
|
||||
key_handle.data(), key_handle.size(), buffer.data(), buffer.size(), iv_,
|
||||
OEMCrypto_AES_CBC_128_NO_PADDING, buffer.data()));
|
||||
}
|
||||
|
||||
// Test Generic_Decrypt works correctly.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyDecrypt) {
|
||||
EncryptAndLoadKeys();
|
||||
unsigned int key_index = 1;
|
||||
vector<uint8_t> encrypted;
|
||||
EncryptBuffer(key_index, clear_buffer_, &encrypted);
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
vector<uint8_t> resultant(encrypted.size());
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
GenericDecrypt(key_handle.data(), key_handle.size(),
|
||||
encrypted.data(), encrypted.size(), iv_,
|
||||
OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data()));
|
||||
ASSERT_EQ(clear_buffer_, resultant);
|
||||
}
|
||||
|
||||
// Test that Generic_Decrypt works correctly when the input and output buffers
|
||||
// are the same.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyDecryptSameBufferAPI12) {
|
||||
EncryptAndLoadKeys();
|
||||
unsigned int key_index = 1;
|
||||
vector<uint8_t> encrypted;
|
||||
EncryptBuffer(key_index, clear_buffer_, &encrypted);
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
vector<uint8_t> buffer = encrypted;
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
GenericDecrypt(key_handle.data(), key_handle.size(), buffer.data(),
|
||||
buffer.size(), iv_, OEMCrypto_AES_CBC_128_NO_PADDING,
|
||||
buffer.data()));
|
||||
ASSERT_EQ(clear_buffer_, buffer);
|
||||
}
|
||||
|
||||
// Test that Generic_Decrypt fails to decrypt to an insecure buffer if the key
|
||||
// requires a secure data path.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericSecureToClear) {
|
||||
license_messages_.set_control(wvoec::kControlObserveDataPath |
|
||||
wvoec::kControlDataPathSecure);
|
||||
license_messages_.CreateResponseWithGenericCryptoKeys();
|
||||
EncryptAndLoadKeys();
|
||||
unsigned int key_index = 1;
|
||||
vector<uint8_t> encrypted;
|
||||
EncryptBuffer(key_index, clear_buffer_, &encrypted);
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
vector<uint8_t> resultant(encrypted.size());
|
||||
ASSERT_NE(OEMCrypto_SUCCESS,
|
||||
GenericDecrypt(key_handle.data(), key_handle.size(),
|
||||
encrypted.data(), encrypted.size(), iv_,
|
||||
OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data()));
|
||||
ASSERT_NE(clear_buffer_, resultant);
|
||||
}
|
||||
|
||||
// Test that the Generic_Decrypt function fails when not allowed.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyBadDecrypt) {
|
||||
EncryptAndLoadKeys();
|
||||
BadDecrypt(1, OEMCrypto_HMAC_SHA256, buffer_size_);
|
||||
// The buffer size must be a multiple of 16, so subtracting 10 is bad.
|
||||
BadDecrypt(1, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_ - 10);
|
||||
BadDecrypt(0, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_);
|
||||
BadDecrypt(2, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_);
|
||||
BadDecrypt(3, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_);
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeySign) {
|
||||
EncryptAndLoadKeys();
|
||||
unsigned int key_index = 2;
|
||||
vector<uint8_t> expected_signature;
|
||||
SignBuffer(key_index, clear_buffer_, &expected_signature);
|
||||
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
size_t gen_signature_length = 0;
|
||||
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
|
||||
GenericSign(key_handle.data(), key_handle.size(),
|
||||
clear_buffer_.data(), clear_buffer_.size(),
|
||||
OEMCrypto_HMAC_SHA256, nullptr, &gen_signature_length));
|
||||
ASSERT_EQ(static_cast<size_t>(SHA256_DIGEST_LENGTH), gen_signature_length);
|
||||
vector<uint8_t> signature(SHA256_DIGEST_LENGTH);
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GenericSign(key_handle.data(), key_handle.size(), clear_buffer_.data(),
|
||||
clear_buffer_.size(), OEMCrypto_HMAC_SHA256, signature.data(),
|
||||
&gen_signature_length));
|
||||
ASSERT_EQ(expected_signature, signature);
|
||||
}
|
||||
|
||||
// Test that the Generic_Sign function fails when not allowed.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyBadSign) {
|
||||
EncryptAndLoadKeys();
|
||||
BadSign(0, OEMCrypto_HMAC_SHA256); // Can't sign with encrypt key.
|
||||
BadSign(1, OEMCrypto_HMAC_SHA256); // Can't sign with decrypt key.
|
||||
BadSign(3, OEMCrypto_HMAC_SHA256); // Can't sign with verify key.
|
||||
BadSign(2, OEMCrypto_AES_CBC_128_NO_PADDING); // Bad signing algorithm.
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyVerify) {
|
||||
EncryptAndLoadKeys();
|
||||
unsigned int key_index = 3;
|
||||
vector<uint8_t> signature;
|
||||
SignBuffer(key_index, clear_buffer_, &signature);
|
||||
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GenericVerify(key_handle.data(), key_handle.size(), clear_buffer_.data(),
|
||||
clear_buffer_.size(), OEMCrypto_HMAC_SHA256,
|
||||
signature.data(), signature.size()));
|
||||
}
|
||||
|
||||
// Test that the Generic_Verify function fails when not allowed.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyBadVerify) {
|
||||
EncryptAndLoadKeys();
|
||||
BadVerify(0, OEMCrypto_HMAC_SHA256, SHA256_DIGEST_LENGTH, false);
|
||||
BadVerify(1, OEMCrypto_HMAC_SHA256, SHA256_DIGEST_LENGTH, false);
|
||||
BadVerify(2, OEMCrypto_HMAC_SHA256, SHA256_DIGEST_LENGTH, false);
|
||||
BadVerify(3, OEMCrypto_HMAC_SHA256, SHA256_DIGEST_LENGTH, true);
|
||||
BadVerify(3, OEMCrypto_HMAC_SHA256, SHA256_DIGEST_LENGTH - 1, false);
|
||||
BadVerify(3, OEMCrypto_HMAC_SHA256, SHA256_DIGEST_LENGTH + 1, false);
|
||||
BadVerify(3, OEMCrypto_AES_CBC_128_NO_PADDING, SHA256_DIGEST_LENGTH, false);
|
||||
}
|
||||
|
||||
// Test Generic_Encrypt with the maximum buffer size.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyEncryptLargeBuffer) {
|
||||
ResizeBuffer(GetResourceValue(kMaxGenericBuffer));
|
||||
EncryptAndLoadKeys();
|
||||
unsigned int key_index = 0;
|
||||
vector<uint8_t> expected_encrypted;
|
||||
EncryptBuffer(key_index, clear_buffer_, &expected_encrypted);
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
vector<uint8_t> encrypted(clear_buffer_.size());
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
GenericEncrypt(key_handle.data(), key_handle.size(),
|
||||
clear_buffer_.data(), clear_buffer_.size(), iv_,
|
||||
OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data()));
|
||||
ASSERT_EQ(expected_encrypted, encrypted);
|
||||
}
|
||||
|
||||
// Test Generic_Decrypt with the maximum buffer size.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyDecryptLargeBuffer) {
|
||||
// Some applications are known to pass in a block that is almost 400k.
|
||||
ResizeBuffer(GetResourceValue(kMaxGenericBuffer));
|
||||
EncryptAndLoadKeys();
|
||||
unsigned int key_index = 1;
|
||||
vector<uint8_t> encrypted;
|
||||
EncryptBuffer(key_index, clear_buffer_, &encrypted);
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
vector<uint8_t> resultant(encrypted.size());
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
GenericDecrypt(key_handle.data(), key_handle.size(),
|
||||
encrypted.data(), encrypted.size(), iv_,
|
||||
OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data()));
|
||||
ASSERT_EQ(clear_buffer_, resultant);
|
||||
}
|
||||
|
||||
// Test Generic_Sign with the maximum buffer size.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeySignLargeBuffer) {
|
||||
ResizeBuffer(GetResourceValue(kMaxGenericBuffer));
|
||||
EncryptAndLoadKeys();
|
||||
unsigned int key_index = 2;
|
||||
vector<uint8_t> expected_signature;
|
||||
SignBuffer(key_index, clear_buffer_, &expected_signature);
|
||||
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
size_t gen_signature_length = 0;
|
||||
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
|
||||
GenericSign(key_handle.data(), key_handle.size(),
|
||||
clear_buffer_.data(), clear_buffer_.size(),
|
||||
OEMCrypto_HMAC_SHA256, nullptr, &gen_signature_length));
|
||||
ASSERT_EQ(static_cast<size_t>(SHA256_DIGEST_LENGTH), gen_signature_length);
|
||||
vector<uint8_t> signature(SHA256_DIGEST_LENGTH);
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GenericSign(key_handle.data(), key_handle.size(), clear_buffer_.data(),
|
||||
clear_buffer_.size(), OEMCrypto_HMAC_SHA256, signature.data(),
|
||||
&gen_signature_length));
|
||||
ASSERT_EQ(expected_signature, signature);
|
||||
}
|
||||
|
||||
// Test Generic_Verify with the maximum buffer size.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyVerifyLargeBuffer) {
|
||||
ResizeBuffer(GetResourceValue(kMaxGenericBuffer));
|
||||
EncryptAndLoadKeys();
|
||||
unsigned int key_index = 3;
|
||||
vector<uint8_t> signature;
|
||||
SignBuffer(key_index, clear_buffer_, &signature);
|
||||
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GenericVerify(key_handle.data(), key_handle.size(), clear_buffer_.data(),
|
||||
clear_buffer_.size(), OEMCrypto_HMAC_SHA256,
|
||||
signature.data(), signature.size()));
|
||||
}
|
||||
|
||||
// Test Generic_Encrypt when the key duration has expired.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, KeyDurationEncrypt) {
|
||||
license_messages_.core_response()
|
||||
.timer_limits.total_playback_duration_seconds = kDuration;
|
||||
license_messages_.CreateResponseWithGenericCryptoKeys();
|
||||
EncryptAndLoadKeys();
|
||||
vector<uint8_t> expected_encrypted;
|
||||
EncryptBuffer(0, clear_buffer_, &expected_encrypted);
|
||||
unsigned int key_index = 0;
|
||||
vector<uint8_t> encrypted(clear_buffer_.size());
|
||||
|
||||
vector<uint8_t> key_handle;
|
||||
// Should be valid key at the start.
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
GenericEncrypt(key_handle.data(), key_handle.size(),
|
||||
clear_buffer_.data(), clear_buffer_.size(), iv_,
|
||||
OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data()));
|
||||
ASSERT_EQ(expected_encrypted, encrypted);
|
||||
|
||||
wvutil::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key.
|
||||
encrypted.assign(clear_buffer_.size(), 0);
|
||||
OEMCryptoResult status = OEMCrypto_Generic_Encrypt(
|
||||
key_handle.data(), key_handle.size(), clear_buffer_.data(),
|
||||
clear_buffer_.size(), iv_, OEMCrypto_AES_CBC_128_NO_PADDING,
|
||||
encrypted.data());
|
||||
ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status);
|
||||
ASSERT_NE(encrypted, expected_encrypted);
|
||||
ASSERT_NO_FATAL_FAILURE(session_.TestGetKeyHandleExpired(key_index));
|
||||
}
|
||||
|
||||
// Test Generic_Decrypt when the key duration has expired.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, KeyDurationDecrypt) {
|
||||
license_messages_.core_response()
|
||||
.timer_limits.total_playback_duration_seconds = kDuration;
|
||||
license_messages_.CreateResponseWithGenericCryptoKeys();
|
||||
EncryptAndLoadKeys();
|
||||
|
||||
// Should be valid key at the start.
|
||||
unsigned int key_index = 1;
|
||||
vector<uint8_t> encrypted;
|
||||
EncryptBuffer(key_index, clear_buffer_, &encrypted);
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
vector<uint8_t> resultant(encrypted.size());
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
GenericDecrypt(key_handle.data(), key_handle.size(),
|
||||
encrypted.data(), encrypted.size(), iv_,
|
||||
OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data()));
|
||||
ASSERT_EQ(clear_buffer_, resultant);
|
||||
|
||||
wvutil::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key.
|
||||
resultant.assign(encrypted.size(), 0);
|
||||
OEMCryptoResult status = GenericDecrypt(
|
||||
key_handle.data(), key_handle.size(), encrypted.data(), encrypted.size(),
|
||||
iv_, OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data());
|
||||
ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status);
|
||||
ASSERT_NE(clear_buffer_, resultant);
|
||||
ASSERT_NO_FATAL_FAILURE(session_.TestGetKeyHandleExpired(key_index));
|
||||
}
|
||||
|
||||
// Test Generic_Sign when the key duration has expired.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, KeyDurationSign) {
|
||||
license_messages_.core_response()
|
||||
.timer_limits.total_playback_duration_seconds = kDuration;
|
||||
license_messages_.CreateResponseWithGenericCryptoKeys();
|
||||
EncryptAndLoadKeys();
|
||||
|
||||
unsigned int key_index = 2;
|
||||
vector<uint8_t> expected_signature;
|
||||
vector<uint8_t> signature(SHA256_DIGEST_LENGTH);
|
||||
size_t signature_length = signature.size();
|
||||
SignBuffer(key_index, clear_buffer_, &expected_signature);
|
||||
|
||||
vector<uint8_t> key_handle;
|
||||
// Should be valid key at the start.
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GenericSign(key_handle.data(), key_handle.size(), clear_buffer_.data(),
|
||||
clear_buffer_.size(), OEMCrypto_HMAC_SHA256, signature.data(),
|
||||
&signature_length));
|
||||
ASSERT_EQ(expected_signature, signature);
|
||||
|
||||
wvutil::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key.
|
||||
signature.assign(SHA256_DIGEST_LENGTH, 0);
|
||||
OEMCryptoResult status =
|
||||
GenericSign(key_handle.data(), key_handle.size(), clear_buffer_.data(),
|
||||
clear_buffer_.size(), OEMCrypto_HMAC_SHA256, signature.data(),
|
||||
&signature_length);
|
||||
ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status);
|
||||
ASSERT_NE(expected_signature, signature);
|
||||
ASSERT_NO_FATAL_FAILURE(session_.TestGetKeyHandleExpired(key_index));
|
||||
}
|
||||
|
||||
// Test Generic_Verify when the key duration has expired.
|
||||
TEST_P(OEMCryptoGenericCryptoTest, KeyDurationVerify) {
|
||||
license_messages_.core_response()
|
||||
.timer_limits.total_playback_duration_seconds = kDuration;
|
||||
license_messages_.CreateResponseWithGenericCryptoKeys();
|
||||
EncryptAndLoadKeys();
|
||||
|
||||
unsigned int key_index = 3;
|
||||
vector<uint8_t> signature;
|
||||
SignBuffer(key_index, clear_buffer_, &signature);
|
||||
|
||||
vector<uint8_t> key_handle;
|
||||
// Should be valid key at the start.
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GenericVerify(key_handle.data(), key_handle.size(), clear_buffer_.data(),
|
||||
clear_buffer_.size(), OEMCrypto_HMAC_SHA256,
|
||||
signature.data(), signature.size()));
|
||||
|
||||
wvutil::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key.
|
||||
OEMCryptoResult status = OEMCrypto_Generic_Verify(
|
||||
key_handle.data(), key_handle.size(), clear_buffer_.data(),
|
||||
clear_buffer_.size(), OEMCrypto_HMAC_SHA256, signature.data(),
|
||||
signature.size());
|
||||
ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status);
|
||||
ASSERT_NO_FATAL_FAILURE(session_.TestGetKeyHandleExpired(key_index));
|
||||
}
|
||||
|
||||
const unsigned int kLongKeyId = 2;
|
||||
|
||||
// Test that short key ids are allowed.
|
||||
class OEMCryptoGenericCryptoKeyIdLengthTest
|
||||
: public OEMCryptoGenericCryptoTest {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
OEMCryptoGenericCryptoTest::SetUp();
|
||||
license_messages_.set_num_keys(5);
|
||||
license_messages_.set_control(wvoec::kControlAllowDecrypt);
|
||||
license_messages_.core_response()
|
||||
.timer_limits.total_playback_duration_seconds = kDuration;
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
SetUniformKeyIdLength(16); // Start with all key ids being 16 bytes.
|
||||
// But, we are testing that the key ids do not have to have the same
|
||||
// length.
|
||||
// 12 bytes (common key id length).
|
||||
license_messages_.SetKeyId(0, "123456789012");
|
||||
license_messages_.SetKeyId(1, "12345"); // short key id.
|
||||
// 16 byte key id. (default)
|
||||
license_messages_.SetKeyId(2, "1234567890123456");
|
||||
license_messages_.SetKeyId(3, "12345678901234"); // 14 byte. (uncommon)
|
||||
license_messages_.SetKeyId(4, "1"); // very short key id.
|
||||
ASSERT_EQ(2u, kLongKeyId);
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.FillCoreResponseSubstrings());
|
||||
}
|
||||
|
||||
// Make all four keys have the same length.
|
||||
void SetUniformKeyIdLength(size_t key_id_length) {
|
||||
for (size_t i = 0; i < license_messages_.num_keys(); i++) {
|
||||
string key_id;
|
||||
key_id.resize(key_id_length, i + 'a');
|
||||
license_messages_.SetKeyId(i, key_id);
|
||||
}
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.FillCoreResponseSubstrings());
|
||||
}
|
||||
|
||||
void TestWithKey(unsigned int key_index) {
|
||||
ASSERT_LT(key_index, license_messages_.num_keys());
|
||||
EncryptAndLoadKeys();
|
||||
vector<uint8_t> encrypted;
|
||||
// To make sure OEMCrypto is not expecting the key_id to be zero padded,
|
||||
// we will create a buffer that is padded with 'Z'. Then, we use fill
|
||||
// the buffer with the longer of the three keys. If OEMCrypto is paying
|
||||
// attention to the key id length, it should pick out the correct key.
|
||||
vector<uint8_t> key_id_buffer(
|
||||
session_.license().keys[kLongKeyId].key_id_length + 5,
|
||||
'Z'); // Fill a bigger buffer with letter 'Z'.
|
||||
memcpy(key_id_buffer.data(), session_.license().keys[kLongKeyId].key_id,
|
||||
session_.license().keys[kLongKeyId].key_id_length);
|
||||
EncryptBuffer(key_index, clear_buffer_, &encrypted);
|
||||
vector<uint8_t> key_handle;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
GetKeyHandleIntoVector(session_.session_id(), key_id_buffer.data(),
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle));
|
||||
vector<uint8_t> resultant(encrypted.size());
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
OEMCrypto_Generic_Decrypt(key_handle.data(), key_handle.size(),
|
||||
encrypted.data(), encrypted.size(), iv_,
|
||||
OEMCrypto_AES_CBC_128_NO_PADDING,
|
||||
resultant.data()));
|
||||
ASSERT_EQ(clear_buffer_, resultant);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(OEMCryptoGenericCryptoKeyIdLengthTest, MediumKeyId) { TestWithKey(0); }
|
||||
|
||||
TEST_P(OEMCryptoGenericCryptoKeyIdLengthTest, ShortKeyId) { TestWithKey(1); }
|
||||
|
||||
TEST_P(OEMCryptoGenericCryptoKeyIdLengthTest, LongKeyId) { TestWithKey(2); }
|
||||
|
||||
TEST_P(OEMCryptoGenericCryptoKeyIdLengthTest, FourteenByteKeyId) {
|
||||
TestWithKey(3);
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoGenericCryptoKeyIdLengthTest, VeryShortKeyId) {
|
||||
TestWithKey(4);
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoGenericCryptoKeyIdLengthTest, UniformShortKeyId) {
|
||||
SetUniformKeyIdLength(5);
|
||||
TestWithKey(2);
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoGenericCryptoKeyIdLengthTest, UniformLongKeyId) {
|
||||
SetUniformKeyIdLength(kTestKeyIdMaxLength);
|
||||
TestWithKey(2);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoGenericCryptoTest,
|
||||
Range<uint32_t>(kCoreMessagesAPI, kCurrentAPI + 1));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoGenericCryptoKeyIdLengthTest,
|
||||
Range<uint32_t>(kCoreMessagesAPI, kCurrentAPI + 1));
|
||||
/// @}
|
||||
} // namespace wvoec
|
||||
|
||||
Reference in New Issue
Block a user