1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "drm_hal_common@1.2"
18
19 #include <android/hidl/allocator/1.0/IAllocator.h>
20 #include <gtest/gtest.h>
21 #include <hidl/HidlSupport.h>
22 #include <hidlmemory/mapping.h>
23 #include <log/log.h>
24 #include <openssl/aes.h>
25 #include <random>
26
27 #include "drm_hal_clearkey_module.h"
28 #include "drm_hal_common.h"
29
30 using ::android::hardware::drm::V1_0::BufferType;
31 using ::android::hardware::drm::V1_0::DestinationBuffer;
32 using ICryptoPluginV1_0 = ::android::hardware::drm::V1_0::ICryptoPlugin;
33 using IDrmPluginV1_0 = ::android::hardware::drm::V1_0::IDrmPlugin;
34 using ::android::hardware::drm::V1_0::KeyValue;
35 using ::android::hardware::drm::V1_0::SharedBuffer;
36 using StatusV1_0 = ::android::hardware::drm::V1_0::Status;
37
38 using ::android::hardware::drm::V1_1::KeyRequestType;
39
40 using ::android::hardware::drm::V1_2::KeySetId;
41 using ::android::hardware::drm::V1_2::OfflineLicenseState;
42 using StatusV1_2 = ::android::hardware::drm::V1_2::Status;
43
44 using ::android::hardware::hidl_string;
45 using ::android::hardware::hidl_memory;
46
47 using ::android::hidl::allocator::V1_0::IAllocator;
48
49 using std::random_device;
50 using std::mt19937;
51
52 namespace android {
53 namespace hardware {
54 namespace drm {
55 namespace V1_2 {
56 namespace vts {
57
58 const char *kCallbackLostState = "LostState";
59 const char *kCallbackKeysChange = "KeysChange";
60
61 drm_vts::VendorModules *DrmHalTest::gVendorModules = nullptr;
62
63 /**
64 * DrmHalPluginListener
65 */
66
sendSessionLostState(const hidl_vec<uint8_t> & sessionId)67 Return<void> DrmHalPluginListener::sendSessionLostState(const hidl_vec<uint8_t>& sessionId) {
68 ListenerEventArgs args;
69 args.sessionId = sessionId;
70 NotifyFromCallback(kCallbackLostState, args);
71 return Void();
72 }
73
sendKeysChange_1_2(const hidl_vec<uint8_t> & sessionId,const hidl_vec<KeyStatus> & keyStatusList,bool hasNewUsableKey)74 Return<void> DrmHalPluginListener::sendKeysChange_1_2(const hidl_vec<uint8_t>& sessionId,
75 const hidl_vec<KeyStatus>& keyStatusList, bool hasNewUsableKey) {
76 ListenerEventArgs args;
77 args.sessionId = sessionId;
78 args.keyStatusList = keyStatusList;
79 args.hasNewUsableKey = hasNewUsableKey;
80 NotifyFromCallback(kCallbackKeysChange, args);
81 return Void();
82 }
83
84 /**
85 * DrmHalTest
86 */
87
DrmHalTest()88 DrmHalTest::DrmHalTest()
89 : vendorModule(GetParam() == "clearkey"
90 ? new DrmHalVTSClearkeyModule()
91 : static_cast<DrmHalVTSVendorModule_V1*>(gVendorModules->getModule(GetParam()))),
92 contentConfigurations(vendorModule->getContentConfigurations()) {
93 }
94
SetUp()95 void DrmHalTest::SetUp() {
96 const ::testing::TestInfo* const test_info =
97 ::testing::UnitTest::GetInstance()->current_test_info();
98
99 ALOGD("Running test %s.%s from (vendor) module %s",
100 test_info->test_case_name(), test_info->name(),
101 GetParam().c_str());
102
103 string name = vendorModule->getServiceName();
104 drmFactory = VtsHalHidlTargetTestBase::getService<IDrmFactory>(name);
105 if (drmFactory == nullptr) {
106 drmFactory = VtsHalHidlTargetTestBase::getService<IDrmFactory>();
107 }
108 if (drmFactory != nullptr) {
109 drmPlugin = createDrmPlugin();
110 }
111
112 cryptoFactory = VtsHalHidlTargetTestBase::getService<ICryptoFactory>(name);
113 if (cryptoFactory == nullptr) {
114 cryptoFactory = VtsHalHidlTargetTestBase::getService<ICryptoFactory>();
115 }
116 if (cryptoFactory != nullptr) {
117 cryptoPlugin = createCryptoPlugin();
118 }
119
120 // If drm scheme not installed skip subsequent tests
121 if (!drmFactory->isCryptoSchemeSupported(getVendorUUID())) {
122 vendorModule->setInstalled(false);
123 return;
124 }
125
126 ASSERT_NE(nullptr, drmPlugin.get()) << "Can't find " << vendorModule->getServiceName() << " drm@1.2 plugin";
127 ASSERT_NE(nullptr, cryptoPlugin.get()) << "Can't find " << vendorModule->getServiceName() << " crypto@1.2 plugin";
128
129 }
130
createDrmPlugin()131 sp<IDrmPlugin> DrmHalTest::createDrmPlugin() {
132 if (drmFactory == nullptr) {
133 return nullptr;
134 }
135 sp<IDrmPlugin> plugin = nullptr;
136 hidl_string packageName("android.hardware.drm.test");
137 auto res = drmFactory->createPlugin(
138 getVendorUUID(), packageName,
139 [&](StatusV1_0 status, const sp<IDrmPluginV1_0>& pluginV1_0) {
140 EXPECT_EQ(StatusV1_0::OK, status);
141 plugin = IDrmPlugin::castFrom(pluginV1_0);
142 });
143
144 if (!res.isOk()) {
145 ALOGE("createDrmPlugin remote call failed");
146 }
147 return plugin;
148 }
149
createCryptoPlugin()150 sp<ICryptoPlugin> DrmHalTest::createCryptoPlugin() {
151 if (cryptoFactory == nullptr) {
152 return nullptr;
153 }
154 sp<ICryptoPlugin> plugin = nullptr;
155 hidl_vec<uint8_t> initVec;
156 auto res = cryptoFactory->createPlugin(
157 getVendorUUID(), initVec,
158 [&](StatusV1_0 status, const sp<ICryptoPluginV1_0>& pluginV1_0) {
159 EXPECT_EQ(StatusV1_0::OK, status);
160 plugin = ICryptoPlugin::castFrom(pluginV1_0);
161 });
162 if (!res.isOk()) {
163 ALOGE("createCryptoPlugin remote call failed");
164 }
165 return plugin;
166 }
167
getVendorUUID()168 hidl_array<uint8_t, 16> DrmHalTest::getVendorUUID() {
169 vector<uint8_t> uuid = vendorModule->getUUID();
170 return hidl_array<uint8_t, 16>(&uuid[0]);
171 }
172
173 /**
174 * Helper method to open a session and verify that a non-empty
175 * session ID is returned
176 */
openSession()177 SessionId DrmHalTest::openSession() {
178 SessionId sessionId;
179
180 auto res = drmPlugin->openSession([&](StatusV1_0 status, const hidl_vec<unsigned char> &id) {
181 EXPECT_EQ(StatusV1_0::OK, status);
182 EXPECT_NE(id.size(), 0u);
183 sessionId = id;
184 });
185 EXPECT_OK(res);
186 return sessionId;
187 }
188
189 /**
190 * Helper method to close a session
191 */
closeSession(const SessionId & sessionId)192 void DrmHalTest::closeSession(const SessionId& sessionId) {
193 StatusV1_0 status = drmPlugin->closeSession(sessionId);
194 EXPECT_EQ(StatusV1_0::OK, status);
195 }
196
getKeyRequest(const SessionId & sessionId,const DrmHalVTSVendorModule_V1::ContentConfiguration & configuration,const KeyType & type=KeyType::STREAMING)197 hidl_vec<uint8_t> DrmHalTest::getKeyRequest(
198 const SessionId& sessionId,
199 const DrmHalVTSVendorModule_V1::ContentConfiguration& configuration,
200 const KeyType& type = KeyType::STREAMING) {
201 hidl_vec<uint8_t> keyRequest;
202 auto res = drmPlugin->getKeyRequest_1_2(
203 sessionId, configuration.initData, configuration.mimeType, type,
204 toHidlKeyedVector(configuration.optionalParameters),
205 [&](Status status, const hidl_vec<uint8_t>& request,
206 KeyRequestType requestType, const hidl_string&) {
207 EXPECT_EQ(Status::OK, status) << "Failed to get "
208 "key request for configuration "
209 << configuration.name;
210 if (type == KeyType::RELEASE) {
211 EXPECT_EQ(KeyRequestType::RELEASE, requestType);
212 } else {
213 EXPECT_EQ(KeyRequestType::INITIAL, requestType);
214 }
215 EXPECT_NE(request.size(), 0u) << "Expected key request size"
216 " to have length > 0 bytes";
217 keyRequest = request;
218 });
219 EXPECT_OK(res);
220 return keyRequest;
221 }
222
getContent(const KeyType & type) const223 DrmHalVTSVendorModule_V1::ContentConfiguration DrmHalTest::getContent(const KeyType& type) const {
224 for (const auto& config : contentConfigurations) {
225 if (type != KeyType::OFFLINE || config.policy.allowOffline) {
226 return config;
227 }
228 }
229 EXPECT_TRUE(false) << "no content configurations found";
230 return {};
231 }
232
provideKeyResponse(const SessionId & sessionId,const hidl_vec<uint8_t> & keyResponse)233 hidl_vec<uint8_t> DrmHalTest::provideKeyResponse(
234 const SessionId& sessionId,
235 const hidl_vec<uint8_t>& keyResponse) {
236 hidl_vec<uint8_t> keySetId;
237 auto res = drmPlugin->provideKeyResponse(
238 sessionId, keyResponse,
239 [&](StatusV1_0 status, const hidl_vec<uint8_t>& myKeySetId) {
240 EXPECT_EQ(StatusV1_0::OK, status) << "Failure providing "
241 "key response for configuration ";
242 keySetId = myKeySetId;
243 });
244 EXPECT_OK(res);
245 return keySetId;
246 }
247
248 /**
249 * Helper method to load keys for subsequent decrypt tests.
250 * These tests use predetermined key request/response to
251 * avoid requiring a round trip to a license server.
252 */
loadKeys(const SessionId & sessionId,const DrmHalVTSVendorModule_V1::ContentConfiguration & configuration,const KeyType & type)253 hidl_vec<uint8_t> DrmHalTest::loadKeys(
254 const SessionId& sessionId,
255 const DrmHalVTSVendorModule_V1::ContentConfiguration& configuration,
256 const KeyType& type) {
257 hidl_vec<uint8_t> keyRequest = getKeyRequest(sessionId, configuration, type);
258
259 /**
260 * Get key response from vendor module
261 */
262 hidl_vec<uint8_t> keyResponse =
263 vendorModule->handleKeyRequest(keyRequest, configuration.serverUrl);
264 EXPECT_NE(keyResponse.size(), 0u) << "Expected key response size "
265 "to have length > 0 bytes";
266
267 return provideKeyResponse(sessionId, keyResponse);
268 }
269
loadKeys(const SessionId & sessionId,const KeyType & type)270 hidl_vec<uint8_t> DrmHalTest::loadKeys(
271 const SessionId& sessionId,
272 const KeyType& type) {
273 return loadKeys(sessionId, getContent(type), type);
274 }
275
toHidlKeyedVector(const map<string,string> & params)276 KeyedVector DrmHalTest::toHidlKeyedVector(
277 const map<string, string>& params) {
278 std::vector<KeyValue> stdKeyedVector;
279 for (auto it = params.begin(); it != params.end(); ++it) {
280 KeyValue keyValue;
281 keyValue.key = it->first;
282 keyValue.value = it->second;
283 stdKeyedVector.push_back(keyValue);
284 }
285 return KeyedVector(stdKeyedVector);
286 }
287
toHidlArray(const vector<uint8_t> & vec)288 hidl_array<uint8_t, 16> DrmHalTest::toHidlArray(const vector<uint8_t>& vec) {
289 EXPECT_EQ(16u, vec.size());
290 return hidl_array<uint8_t, 16>(&vec[0]);
291 }
292
293 /**
294 * getDecryptMemory allocates memory for decryption, then sets it
295 * as a shared buffer base in the crypto hal. The allocated and
296 * mapped IMemory is returned.
297 *
298 * @param size the size of the memory segment to allocate
299 * @param the index of the memory segment which will be used
300 * to refer to it for decryption.
301 */
getDecryptMemory(size_t size,size_t index)302 sp<IMemory> DrmHalTest::getDecryptMemory(size_t size, size_t index) {
303 sp<IAllocator> ashmemAllocator = IAllocator::getService("ashmem");
304 EXPECT_NE(nullptr, ashmemAllocator.get());
305
306 hidl_memory hidlMemory;
307 auto res = ashmemAllocator->allocate(
308 size, [&](bool success, const hidl_memory& memory) {
309 EXPECT_EQ(success, true);
310 EXPECT_EQ(memory.size(), size);
311 hidlMemory = memory;
312 });
313
314 EXPECT_OK(res);
315
316 sp<IMemory> mappedMemory = mapMemory(hidlMemory);
317 EXPECT_NE(nullptr, mappedMemory.get());
318 res = cryptoPlugin->setSharedBufferBase(hidlMemory, index);
319 EXPECT_OK(res);
320 return mappedMemory;
321 }
322
fillRandom(const sp<IMemory> & memory)323 void DrmHalTest::fillRandom(const sp<IMemory>& memory) {
324 random_device rd;
325 mt19937 rand(rd());
326 for (size_t i = 0; i < memory->getSize() / sizeof(uint32_t); i++) {
327 auto p = static_cast<uint32_t*>(
328 static_cast<void*>(memory->getPointer()));
329 p[i] = rand();
330 }
331 }
332
decrypt(Mode mode,bool isSecure,const hidl_array<uint8_t,16> & keyId,uint8_t * iv,const hidl_vec<SubSample> & subSamples,const Pattern & pattern,const vector<uint8_t> & key,StatusV1_2 expectedStatus)333 uint32_t DrmHalTest::decrypt(Mode mode, bool isSecure,
334 const hidl_array<uint8_t, 16>& keyId, uint8_t* iv,
335 const hidl_vec<SubSample>& subSamples, const Pattern& pattern,
336 const vector<uint8_t>& key, StatusV1_2 expectedStatus) {
337 const size_t kSegmentIndex = 0;
338
339 uint8_t localIv[AES_BLOCK_SIZE];
340 memcpy(localIv, iv, AES_BLOCK_SIZE);
341
342 size_t totalSize = 0;
343 for (size_t i = 0; i < subSamples.size(); i++) {
344 totalSize += subSamples[i].numBytesOfClearData;
345 totalSize += subSamples[i].numBytesOfEncryptedData;
346 }
347
348 // The first totalSize bytes of shared memory is the encrypted
349 // input, the second totalSize bytes (if exists) is the decrypted output.
350 size_t factor = expectedStatus == StatusV1_2::ERROR_DRM_FRAME_TOO_LARGE ? 1 : 2;
351 sp<IMemory> sharedMemory =
352 getDecryptMemory(totalSize * factor, kSegmentIndex);
353
354 const SharedBuffer sourceBuffer = {
355 .bufferId = kSegmentIndex, .offset = 0, .size = totalSize};
356 fillRandom(sharedMemory);
357
358 const DestinationBuffer destBuffer = {.type = BufferType::SHARED_MEMORY,
359 {.bufferId = kSegmentIndex,
360 .offset = totalSize,
361 .size = totalSize},
362 .secureMemory = nullptr};
363 const uint64_t offset = 0;
364 uint32_t bytesWritten = 0;
365 auto res = cryptoPlugin->decrypt_1_2(isSecure, keyId, localIv, mode, pattern,
366 subSamples, sourceBuffer, offset, destBuffer,
367 [&](StatusV1_2 status, uint32_t count, string detailedError) {
368 EXPECT_EQ(expectedStatus, status) << "Unexpected decrypt status " <<
369 detailedError;
370 bytesWritten = count;
371 });
372 EXPECT_OK(res);
373
374 if (bytesWritten != totalSize) {
375 return bytesWritten;
376 }
377 uint8_t* base = static_cast<uint8_t*>(
378 static_cast<void*>(sharedMemory->getPointer()));
379
380 // generate reference vector
381 vector<uint8_t> reference(totalSize);
382
383 memcpy(localIv, iv, AES_BLOCK_SIZE);
384 switch (mode) {
385 case Mode::UNENCRYPTED:
386 memcpy(&reference[0], base, totalSize);
387 break;
388 case Mode::AES_CTR:
389 aes_ctr_decrypt(&reference[0], base, localIv, subSamples, key);
390 break;
391 case Mode::AES_CBC:
392 aes_cbc_decrypt(&reference[0], base, localIv, subSamples, key);
393 break;
394 case Mode::AES_CBC_CTS:
395 EXPECT_TRUE(false) << "AES_CBC_CTS mode not supported";
396 break;
397 }
398
399 // compare reference to decrypted data which is at base + total size
400 EXPECT_EQ(0, memcmp(static_cast<void *>(&reference[0]),
401 static_cast<void*>(base + totalSize), totalSize))
402 << "decrypt data mismatch";
403 return totalSize;
404 }
405
406 /**
407 * Decrypt a list of clear+encrypted subsamples using the specified key
408 * in AES-CTR mode
409 */
aes_ctr_decrypt(uint8_t * dest,uint8_t * src,uint8_t * iv,const hidl_vec<SubSample> & subSamples,const vector<uint8_t> & key)410 void DrmHalTest::aes_ctr_decrypt(uint8_t* dest, uint8_t* src,
411 uint8_t* iv, const hidl_vec<SubSample>& subSamples,
412 const vector<uint8_t>& key) {
413 AES_KEY decryptionKey;
414 AES_set_encrypt_key(&key[0], 128, &decryptionKey);
415
416 size_t offset = 0;
417 unsigned int blockOffset = 0;
418 uint8_t previousEncryptedCounter[AES_BLOCK_SIZE];
419 memset(previousEncryptedCounter, 0, AES_BLOCK_SIZE);
420
421 for (size_t i = 0; i < subSamples.size(); i++) {
422 const SubSample& subSample = subSamples[i];
423
424 if (subSample.numBytesOfClearData > 0) {
425 memcpy(dest + offset, src + offset, subSample.numBytesOfClearData);
426 offset += subSample.numBytesOfClearData;
427 }
428
429 if (subSample.numBytesOfEncryptedData > 0) {
430 AES_ctr128_encrypt(src + offset, dest + offset,
431 subSample.numBytesOfEncryptedData, &decryptionKey,
432 iv, previousEncryptedCounter, &blockOffset);
433 offset += subSample.numBytesOfEncryptedData;
434 }
435 }
436 }
437
438 /**
439 * Decrypt a list of clear+encrypted subsamples using the specified key
440 * in AES-CBC mode
441 */
aes_cbc_decrypt(uint8_t * dest,uint8_t * src,uint8_t * iv,const hidl_vec<SubSample> & subSamples,const vector<uint8_t> & key)442 void DrmHalTest::aes_cbc_decrypt(uint8_t* dest, uint8_t* src,
443 uint8_t* iv, const hidl_vec<SubSample>& subSamples,
444 const vector<uint8_t>& key) {
445 AES_KEY decryptionKey;
446 AES_set_encrypt_key(&key[0], 128, &decryptionKey);
447
448 size_t offset = 0;
449 for (size_t i = 0; i < subSamples.size(); i++) {
450 memcpy(dest + offset, src + offset, subSamples[i].numBytesOfClearData);
451 offset += subSamples[i].numBytesOfClearData;
452
453 AES_cbc_encrypt(src + offset, dest + offset, subSamples[i].numBytesOfEncryptedData,
454 &decryptionKey, iv, 0 /* decrypt */);
455 offset += subSamples[i].numBytesOfEncryptedData;
456 }
457 }
458
459 /**
460 * Helper method to test decryption with invalid keys is returned
461 */
decryptWithInvalidKeys(hidl_vec<uint8_t> & invalidResponse,vector<uint8_t> & iv,const Pattern & noPattern,const vector<SubSample> & subSamples)462 void DrmHalClearkeyTest::decryptWithInvalidKeys(
463 hidl_vec<uint8_t>& invalidResponse,
464 vector<uint8_t>& iv,
465 const Pattern& noPattern,
466 const vector<SubSample>& subSamples) {
467 DrmHalVTSVendorModule_V1::ContentConfiguration content = getContent();
468 if (content.keys.empty()) {
469 FAIL() << "no keys";
470 }
471
472 const auto& key = content.keys[0];
473 auto sessionId = openSession();
474 auto res = drmPlugin->provideKeyResponse(
475 sessionId, invalidResponse,
476 [&](StatusV1_0 status, const hidl_vec<uint8_t>& myKeySetId) {
477 EXPECT_EQ(StatusV1_0::OK, status);
478 EXPECT_EQ(0u, myKeySetId.size());
479 });
480 EXPECT_OK(res);
481
482 EXPECT_TRUE(cryptoPlugin->setMediaDrmSession(sessionId).isOk());
483
484 uint32_t byteCount = decrypt(Mode::AES_CTR, key.isSecure,
485 toHidlArray(key.keyId), &iv[0], subSamples, noPattern,
486 key.clearContentKey, Status::ERROR_DRM_NO_LICENSE);
487 EXPECT_EQ(0u, byteCount);
488
489 closeSession(sessionId);
490 }
491
492 } // namespace vts
493 } // namespace V1_2
494 } // namespace drm
495 } // namespace hardware
496 } // namespace android
497