diff options
| author | Edwin Wong <edwinwong@google.com> | 2017-10-06 18:08:27 -0700 |
|---|---|---|
| committer | Nikoli Cartagena <dargeren@google.com> | 2017-11-28 21:36:02 -0800 |
| commit | f3e2975416e043ff71935272e0480df9b58d7b28 (patch) | |
| tree | 5b4b7aeb8383972c46c580ac6f581c54d17a14ee | |
| parent | 3d522614ec13d9d3911a81789c6776332b82cb43 (diff) | |
| download | android_hardware_interfaces-f3e2975416e043ff71935272e0480df9b58d7b28.tar.gz android_hardware_interfaces-f3e2975416e043ff71935272e0480df9b58d7b28.tar.bz2 android_hardware_interfaces-f3e2975416e043ff71935272e0480df9b58d7b28.zip | |
Add tests to validate key length for clearkey plugin.
AesCtrDecryptor::decrypt() doesn't check whether the size of "key" is
equal to 16 bytes, which may lead to an OOB read problem in the context
of mediadrmserver. The fix is in clearkey plugin. Add tests to validate
the fix.
Test: VTS test
adb shell /data/nativetest/VtsHalDrmV1_0TargetTest/VtsHalDrmV1_0TargetTest
bug: 63982768
Change-Id: Ife2da17e7f39d8031bc36b83c3b27ba5e9d83eb7
(cherry picked from commit 9663fbbb22819b257fd13846b7414fc78fe8d26a)
| -rw-r--r-- | drm/1.0/vts/functional/drm_hal_clearkey_test.cpp | 124 |
1 files changed, 112 insertions, 12 deletions
diff --git a/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp b/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp index 4652c76d5..0fa4157a7 100644 --- a/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp +++ b/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp @@ -89,6 +89,10 @@ static const uint8_t kInvalidUUID[16] = { 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80}; +static const uint32_t k256SubSampleByteCount = 256; +static const uint32_t k512SubSampleClearBytes = 512; +static const uint32_t k512SubSampleEncryptedBytes = 512; + class DrmHalClearkeyFactoryTest : public ::testing::VtsHalHidlTargetTestBase { public: virtual void SetUp() override { @@ -1119,16 +1123,14 @@ TEST_F(DrmHalClearkeyDecryptTest, TestQueryKeyStatus) { closeSession(sessionId); } - /** * Positive decrypt test. "Decrypt" a single clear segment */ TEST_F(DrmHalClearkeyDecryptTest, ClearSegmentTest) { vector<uint8_t> iv(AES_BLOCK_SIZE, 0); const Pattern noPattern = {0, 0}; - const uint32_t kByteCount = 256; const vector<SubSample> subSamples = { - {.numBytesOfClearData = kByteCount, + {.numBytesOfClearData = k256SubSampleByteCount, .numBytesOfEncryptedData = 0}}; auto sessionId = openSession(); loadKeys(sessionId); @@ -1138,7 +1140,7 @@ TEST_F(DrmHalClearkeyDecryptTest, ClearSegmentTest) { uint32_t byteCount = decrypt(Mode::UNENCRYPTED, &iv[0], subSamples, noPattern, Status::OK); - EXPECT_EQ(kByteCount, byteCount); + EXPECT_EQ(k256SubSampleByteCount, byteCount); closeSession(sessionId); } @@ -1150,12 +1152,9 @@ TEST_F(DrmHalClearkeyDecryptTest, ClearSegmentTest) { TEST_F(DrmHalClearkeyDecryptTest, EncryptedAesCtrSegmentTest) { vector<uint8_t> iv(AES_BLOCK_SIZE, 0); const Pattern noPattern = {0, 0}; - const uint32_t kClearBytes = 512; - const uint32_t kEncryptedBytes = 512; const vector<SubSample> subSamples = { - {.numBytesOfClearData = kClearBytes, - .numBytesOfEncryptedData = kEncryptedBytes - }}; + {.numBytesOfClearData = k512SubSampleClearBytes, + .numBytesOfEncryptedData = k512SubSampleEncryptedBytes}}; auto sessionId = openSession(); loadKeys(sessionId); @@ -1164,10 +1163,11 @@ TEST_F(DrmHalClearkeyDecryptTest, EncryptedAesCtrSegmentTest) { uint32_t byteCount = decrypt(Mode::AES_CTR, &iv[0], subSamples, noPattern, Status::OK); - EXPECT_EQ(kClearBytes + kEncryptedBytes, byteCount); + EXPECT_EQ(k512SubSampleClearBytes + k512SubSampleEncryptedBytes, byteCount); closeSession(sessionId); } + /** * Negative decrypt test. Decrypt without loading keys. */ @@ -1175,8 +1175,8 @@ TEST_F(DrmHalClearkeyDecryptTest, EncryptedAesCtrSegmentTestNoKeys) { vector<uint8_t> iv(AES_BLOCK_SIZE, 0); const Pattern noPattern = {0, 0}; const vector<SubSample> subSamples = { - {.numBytesOfClearData = 256, - .numBytesOfEncryptedData = 256}}; + {.numBytesOfClearData = k256SubSampleByteCount, + .numBytesOfEncryptedData = k256SubSampleByteCount}}; auto sessionId = openSession(); Status status = cryptoPlugin->setMediaDrmSession(sessionId); @@ -1188,3 +1188,103 @@ TEST_F(DrmHalClearkeyDecryptTest, EncryptedAesCtrSegmentTestNoKeys) { closeSession(sessionId); } + +/** + * Negative decrypt test. Decrypt with invalid key. + */ +TEST_F(DrmHalClearkeyDecryptTest, DecryptWithEmptyKey) { + vector<uint8_t> iv(AES_BLOCK_SIZE, 0); + const Pattern noPattern = {0, 0}; + const vector<SubSample> subSamples = { + {.numBytesOfClearData = k512SubSampleClearBytes, + .numBytesOfEncryptedData = k512SubSampleEncryptedBytes}}; + + // base 64 encoded JSON response string, must not contain padding character '=' + const hidl_string emptyKeyResponse = + "{\"keys\":[" \ + "{" \ + "\"kty\":\"oct\"" \ + "\"alg\":\"A128KW2\"" \ + "\"k\":\"SGVsbG8gRnJpZW5kIQ\"" \ + "\"kid\":\"Y2xlYXJrZXlrZXlpZDAyAy\"" \ + "}" \ + "{" \ + "\"kty\":\"oct\"," \ + "\"alg\":\"A128KW2\"" \ + "\"kid\":\"Y2xlYXJrZXlrZXlpZDAzAy\"," \ + // empty key follows + "\"k\":\"R\"" \ + "}]" \ + "}"; + const size_t kEmptyKeyResponseSize = emptyKeyResponse.size(); + + hidl_vec<uint8_t> invalidResponse; + invalidResponse.resize(kEmptyKeyResponseSize); + memcpy(invalidResponse.data(), emptyKeyResponse.c_str(), kEmptyKeyResponseSize); + + auto sessionId = openSession(); + + auto res = drmPlugin->provideKeyResponse( + sessionId, invalidResponse, + [&](Status status, const hidl_vec<uint8_t>& myKeySetId) { + EXPECT_EQ(Status::OK, status); + EXPECT_EQ(0u, myKeySetId.size()); + }); + EXPECT_OK(res); + + Status status = cryptoPlugin->setMediaDrmSession(sessionId); + EXPECT_EQ(Status::OK, status); + + uint32_t byteCount = decrypt(Mode::AES_CTR, &iv[0], subSamples, + noPattern, Status::ERROR_DRM_NO_LICENSE); + EXPECT_EQ(0u, byteCount); + + closeSession(sessionId); +} + +/** + * Negative decrypt test. Decrypt with a key exceeds AES_BLOCK_SIZE. + */ +TEST_F(DrmHalClearkeyDecryptTest, DecryptWithKeyTooLong) { + vector<uint8_t> iv(AES_BLOCK_SIZE, 0); + const Pattern noPattern = {0, 0}; + const vector<SubSample> subSamples = { + {.numBytesOfClearData = k512SubSampleClearBytes, + .numBytesOfEncryptedData = k512SubSampleEncryptedBytes}}; + + // base 64 encoded JSON response string, must not contain padding character '=' + const hidl_string keyTooLongResponse = + "{\"keys\":[" \ + "{" \ + "\"kty\":\"oct\"," \ + "\"alg\":\"A128KW2\"" \ + "\"kid\":\"Y2xlYXJrZXlrZXlpZDAzAy\"," \ + // key too long + "\"k\":\"V2lubmllIHRoZSBwb29oIVdpbm5pZSB0aGUgcG9vaCE=\"" \ + "}]" \ + "}"; + const size_t kKeyTooLongResponseSize = keyTooLongResponse.size(); + + hidl_vec<uint8_t> invalidResponse; + invalidResponse.resize(kKeyTooLongResponseSize); + memcpy(invalidResponse.data(), keyTooLongResponse.c_str(), kKeyTooLongResponseSize); + + auto sessionId = openSession(); + + auto res = drmPlugin->provideKeyResponse( + sessionId, invalidResponse, + [&](Status status, const hidl_vec<uint8_t>& myKeySetId) { + EXPECT_EQ(Status::OK, status); + EXPECT_EQ(0u, myKeySetId.size()); + }); + EXPECT_OK(res); + + Status status = cryptoPlugin->setMediaDrmSession(sessionId); + EXPECT_EQ(Status::OK, status); + + uint32_t byteCount = decrypt(Mode::AES_CTR, &iv[0], subSamples, + noPattern, Status::ERROR_DRM_NO_LICENSE); + EXPECT_EQ(0u, byteCount); + + closeSession(sessionId); +} |
