1 /******************************************************************************
2 *
3 * Copyright (C) 2020 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *****************************************************************************
18 * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
19 */
20
21 #include <binder/MemoryDealer.h>
22 #include <hidlmemory/FrameworkUtils.h>
23 #include <mediadrm/CryptoHal.h>
24 #include <mediadrm/DrmHal.h>
25 #include <utils/String8.h>
26 #include "fuzzer/FuzzedDataProvider.h"
27
28 #define AES_BLOCK_SIZE 16
29 #define UNUSED_PARAM __attribute__((unused))
30
31 using namespace std;
32 using namespace android;
33 using android::hardware::fromHeap;
34 using ::android::os::PersistableBundle;
35 using drm::V1_0::BufferType;
36
37 enum {
38 INVALID_UUID = 0,
39 PSSH_BOX_UUID,
40 CLEARKEY_UUID,
41 };
42
43 static const uint8_t kInvalidUUID[16] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80,
44 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80};
45
46 static const uint8_t kCommonPsshBoxUUID[16] = {0x10, 0x77, 0xEF, 0xEC, 0xC0, 0xB2, 0x4D, 0x02,
47 0xAC, 0xE3, 0x3C, 0x1E, 0x52, 0xE2, 0xFB, 0x4B};
48
49 static const uint8_t kClearKeyUUID[16] = {0xE2, 0x71, 0x9D, 0x58, 0xA9, 0x85, 0xB3, 0xC9,
50 0x78, 0x1A, 0xB0, 0x30, 0xAF, 0x78, 0xD3, 0x0E};
51
52 static const uint32_t kUUID[] = {INVALID_UUID, PSSH_BOX_UUID, CLEARKEY_UUID};
53
54 const DrmPlugin::SecurityLevel kSecurityLevel[] = {
55 DrmPlugin::kSecurityLevelUnknown, DrmPlugin::kSecurityLevelMax,
56 DrmPlugin::kSecurityLevelSwSecureCrypto, DrmPlugin::kSecurityLevelSwSecureDecode,
57 DrmPlugin::kSecurityLevelHwSecureCrypto, DrmPlugin::kSecurityLevelHwSecureDecode,
58 DrmPlugin::kSecurityLevelHwSecureAll};
59
60 const char *kMimeType[] = {"video/mp4", "video/mpeg", "video/x-flv", "video/mj2",
61 "video/3gp2", "video/3gpp", "video/3gpp2", "audio/mp4",
62 "audio/mpeg", "audio/aac", "audio/3gp2", "audio/3gpp",
63 "audio/3gpp2", "video/unknown", "audio/unknown"};
64
65 const DrmPlugin::KeyType kKeyType[] = {DrmPlugin::kKeyType_Offline, DrmPlugin::kKeyType_Streaming,
66 DrmPlugin::kKeyType_Release};
67
68 const CryptoPlugin::Mode kCryptoMode[] = {CryptoPlugin::kMode_Unencrypted,
69 CryptoPlugin::kMode_AES_CTR, CryptoPlugin::kMode_AES_WV,
70 CryptoPlugin::kMode_AES_CBC};
71
72 const char *kCipherAlgorithm[] = {"AES/CBC/NoPadding", ""};
73 const char *kMacAlgorithm[] = {"HmacSHA256", ""};
74 const char *kRSAAlgorithm[] = {"RSASSA-PSS-SHA1", ""};
75 const size_t kNumSecurityLevel = size(kSecurityLevel);
76 const size_t kNumMimeType = size(kMimeType);
77 const size_t kNumKeyType = size(kKeyType);
78 const size_t kNumCryptoMode = size(kCryptoMode);
79 const size_t kNumUUID = size(kUUID);
80 const size_t kMaxStringLength = 100;
81 const size_t kMaxSubSamples = 10;
82 const size_t kMaxNumBytes = 1000;
83
84 struct DrmListener : virtual public IDrmClient {
85 public:
sendEventDrmListener86 void sendEvent(DrmPlugin::EventType eventType UNUSED_PARAM,
87 const hardware::hidl_vec<uint8_t> &sessionId UNUSED_PARAM,
88 const hardware::hidl_vec<uint8_t> &data UNUSED_PARAM) override {}
89
sendExpirationUpdateDrmListener90 void sendExpirationUpdate(const hardware::hidl_vec<uint8_t> &sessionId UNUSED_PARAM,
91 int64_t expiryTimeInMS UNUSED_PARAM) override {}
92
sendKeysChangeDrmListener93 void sendKeysChange(const hardware::hidl_vec<uint8_t> &sessionId UNUSED_PARAM,
94 const std::vector<DrmKeyStatus> &keyStatusList UNUSED_PARAM,
95 bool hasNewUsableKey UNUSED_PARAM) override {}
96
sendSessionLostStateDrmListener97 void sendSessionLostState(const hardware::hidl_vec<uint8_t> &) override {}
DrmListenerDrmListener98 DrmListener() {}
99
100 private:
101 DISALLOW_EVIL_CONSTRUCTORS(DrmListener);
102 };
103
104 class DrmFuzzer {
105 public:
106 void process(const uint8_t *data, size_t size);
107
108 private:
109 void invokeDrm(const uint8_t *data, size_t size);
110 bool initDrm();
111 void invokeDrmCreatePlugin();
112 void invokeDrmOpenSession();
113 void invokeDrmSetListener();
114 void invokeDrmSetAlgorithmAPI();
115 void invokeDrmPropertyAPI();
116 void invokeDrmDecryptEncryptAPI(const uint8_t *data, size_t size);
117 void invokeDrmSecureStopAPI();
118 void invokeDrmOfflineLicenseAPI();
119 void invokeDrmCloseSession();
120 void invokeDrmDestroyPlugin();
121 void invokeCrypto(const uint8_t *data);
122 bool initCrypto();
123 void invokeCryptoCreatePlugin();
124 void invokeCryptoDecrypt(const uint8_t *data);
125 void invokeCryptoDestroyPlugin();
126 sp<DrmHal> mDrm = nullptr;
127 sp<CryptoHal> mCrypto = nullptr;
128 Vector<uint8_t> mSessionId = {};
129 FuzzedDataProvider *mFuzzedDataProvider = nullptr;
130 };
131
initDrm()132 bool DrmFuzzer::initDrm() {
133 mDrm = new DrmHal();
134 if (!mDrm) {
135 return false;
136 }
137 return true;
138 }
139
invokeDrmCreatePlugin()140 void DrmFuzzer::invokeDrmCreatePlugin() {
141 mDrm->initCheck();
142 String8 packageName(mFuzzedDataProvider->ConsumeRandomLengthString(kMaxStringLength).c_str());
143 uint32_t uuidEnum = kUUID[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, kNumUUID - 1)];
144 switch (uuidEnum) {
145 case INVALID_UUID:
146 mDrm->createPlugin(kInvalidUUID, packageName);
147 break;
148 case PSSH_BOX_UUID:
149 mDrm->createPlugin(kCommonPsshBoxUUID, packageName);
150 break;
151 case CLEARKEY_UUID:
152 mDrm->createPlugin(kClearKeyUUID, packageName);
153 break;
154 default:
155 break;
156 }
157 }
158
invokeDrmDestroyPlugin()159 void DrmFuzzer::invokeDrmDestroyPlugin() { mDrm->destroyPlugin(); }
160
invokeDrmOpenSession()161 void DrmFuzzer::invokeDrmOpenSession() {
162 DrmPlugin::SecurityLevel securityLevel;
163 bool shouldPassRandomSecurityLevel = mFuzzedDataProvider->ConsumeBool();
164 if (shouldPassRandomSecurityLevel) {
165 securityLevel =
166 static_cast<DrmPlugin::SecurityLevel>(mFuzzedDataProvider->ConsumeIntegral<size_t>());
167 } else {
168 securityLevel = kSecurityLevel[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
169 0, kNumSecurityLevel - 1)];
170 }
171 mDrm->openSession(securityLevel, mSessionId);
172 }
173
invokeDrmCloseSession()174 void DrmFuzzer::invokeDrmCloseSession() { mDrm->closeSession(mSessionId); }
175
invokeDrmSetListener()176 void DrmFuzzer::invokeDrmSetListener() {
177 sp<DrmListener> listener = new DrmListener();
178 mDrm->setListener(listener);
179 }
180
invokeDrmSetAlgorithmAPI()181 void DrmFuzzer::invokeDrmSetAlgorithmAPI() {
182 mDrm->setCipherAlgorithm(mSessionId,
183 String8(kCipherAlgorithm[mFuzzedDataProvider->ConsumeBool()]));
184 mDrm->setMacAlgorithm(mSessionId, String8(kMacAlgorithm[mFuzzedDataProvider->ConsumeBool()]));
185 }
186
invokeDrmPropertyAPI()187 void DrmFuzzer::invokeDrmPropertyAPI() {
188 mDrm->setPropertyString(String8("property"), String8("value"));
189 String8 stringValue;
190 mDrm->getPropertyString(String8("property"), stringValue);
191 Vector<uint8_t> value = {};
192 mDrm->setPropertyByteArray(String8("property"), value);
193 Vector<uint8_t> byteValue;
194 mDrm->getPropertyByteArray(String8("property"), byteValue);
195 }
196
invokeDrmDecryptEncryptAPI(const uint8_t * data,size_t size)197 void DrmFuzzer::invokeDrmDecryptEncryptAPI(const uint8_t *data, size_t size) {
198 uint32_t openSessions = 0;
199 uint32_t maxSessions = 0;
200 mDrm->getNumberOfSessions(&openSessions, &maxSessions);
201
202 DrmPlugin::HdcpLevel connected;
203 DrmPlugin::HdcpLevel max;
204 mDrm->getHdcpLevels(&connected, &max);
205
206 DrmPlugin::SecurityLevel securityLevel;
207 mDrm->getSecurityLevel(mSessionId, &securityLevel);
208
209 // isCryptoSchemeSupported() shall fill isSupported
210 bool isSupported;
211 String8 mimeType(
212 kMimeType[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, kNumMimeType - 1)]);
213 mDrm->isCryptoSchemeSupported(kClearKeyUUID, mimeType, securityLevel, &isSupported);
214
215 // getProvisionRequest() shall fill legacyRequest and legacyDefaultUrl
216 String8 certificateType(
217 mFuzzedDataProvider->ConsumeRandomLengthString(kMaxStringLength).c_str());
218 String8 certAuthority(mFuzzedDataProvider->ConsumeRandomLengthString(kMaxStringLength).c_str());
219 Vector<uint8_t> legacyRequest = {};
220 String8 legacyDefaultUrl;
221 mDrm->getProvisionRequest(certificateType, certAuthority, legacyRequest, legacyDefaultUrl);
222
223 // provideProvisionResponse() shall fill certificate and wrappedKey
224 Vector<uint8_t> provisionResponse = {};
225 Vector<uint8_t> certificate = {};
226 Vector<uint8_t> wrappedKey = {};
227 mDrm->provideProvisionResponse(provisionResponse, certificate, wrappedKey);
228
229 // getKeyRequest() shall fill keyRequest, defaultUrl and keyRequestType
230 Vector<uint8_t> initData = {};
231 initData.appendArray(data, size);
232 DrmPlugin::KeyType keyType;
233 bool shouldPassRandomKeyType = mFuzzedDataProvider->ConsumeBool();
234 if (shouldPassRandomKeyType) {
235 keyType = static_cast<DrmPlugin::KeyType>(mFuzzedDataProvider->ConsumeIntegral<size_t>());
236 } else {
237 keyType = kKeyType[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, kNumKeyType - 1)];
238 }
239 KeyedVector<String8, String8> mdOptionalParameters = {};
240 Vector<uint8_t> keyRequest = {};
241 String8 defaultUrl;
242 DrmPlugin::KeyRequestType keyRequestType;
243 mDrm->getKeyRequest(mSessionId, initData, mimeType, keyType, mdOptionalParameters, keyRequest,
244 defaultUrl, &keyRequestType);
245
246 // provideKeyResponse() shall fill keySetId
247 Vector<uint8_t> keyResponse = {};
248 keyResponse.appendArray(data, size);
249 Vector<uint8_t> keySetId = {};
250 mDrm->provideKeyResponse(mSessionId, keyResponse, keySetId);
251
252 // restoreKeys
253 mDrm->restoreKeys(mSessionId, keySetId);
254
255 // queryKeyStatus() shall fill infoMap
256 KeyedVector<String8, String8> infoMap = {};
257 mDrm->queryKeyStatus(mSessionId, infoMap);
258
259 // decrypt() shall fill outputVec
260 Vector<uint8_t> keyIdVec = {};
261 keyIdVec.appendArray(data, size);
262
263 Vector<uint8_t> inputVec = {};
264 inputVec.appendArray(data, size);
265
266 Vector<uint8_t> ivVec = {};
267 ivVec.appendArray(data, size);
268
269 Vector<uint8_t> outputVec = {};
270 mDrm->decrypt(mSessionId, keyIdVec, inputVec, ivVec, outputVec);
271
272 // encrypt() shall fill outputVec
273 mDrm->encrypt(mSessionId, keyIdVec, inputVec, ivVec, outputVec);
274
275 // sign() shall fill signature
276 Vector<uint8_t> message = {};
277 message.appendArray(data, size);
278 Vector<uint8_t> signature = {};
279 mDrm->sign(mSessionId, keyIdVec, message, signature);
280
281 // verify() shall fill match
282 bool match;
283 mDrm->verify(mSessionId, keyIdVec, message, signature, match);
284
285 // signRSA() shall fill signature
286 mDrm->signRSA(mSessionId, String8(kRSAAlgorithm[mFuzzedDataProvider->ConsumeBool()]), message,
287 wrappedKey, signature);
288
289 mDrm->removeKeys(mSessionId);
290 }
291
invokeDrmSecureStopAPI()292 void DrmFuzzer::invokeDrmSecureStopAPI() {
293 // getSecureStops() shall fill secureStops
294 List<Vector<uint8_t>> secureStops = {};
295 mDrm->getSecureStops(secureStops);
296
297 // getSecureStopIds() shall fill secureStopIds
298 List<Vector<uint8_t>> secureStopIds = {};
299 mDrm->getSecureStopIds(secureStopIds);
300
301 // getSecureStop() shall fill secureStop
302 Vector<uint8_t> ssid = {};
303 Vector<uint8_t> secureStop = {};
304 mDrm->getSecureStop(ssid, secureStop);
305
306 mDrm->removeSecureStop(ssid);
307
308 mDrm->releaseSecureStops(ssid);
309
310 mDrm->removeAllSecureStops();
311 }
312
invokeDrmOfflineLicenseAPI()313 void DrmFuzzer::invokeDrmOfflineLicenseAPI() {
314 // getOfflineLicenseKeySetIds() shall keySetIds
315 List<Vector<uint8_t>> keySetIds = {};
316 mDrm->getOfflineLicenseKeySetIds(keySetIds);
317
318 // getOfflineLicenseState() shall fill state
319 Vector<uint8_t> const keySetIdOfflineLicense = {};
320 DrmPlugin::OfflineLicenseState state;
321 mDrm->getOfflineLicenseState(keySetIdOfflineLicense, &state);
322
323 mDrm->removeOfflineLicense(keySetIdOfflineLicense);
324 }
325
initCrypto()326 bool DrmFuzzer::initCrypto() {
327 mCrypto = new CryptoHal();
328 if (!mCrypto) {
329 return false;
330 }
331 return true;
332 }
333
invokeCryptoCreatePlugin()334 void DrmFuzzer::invokeCryptoCreatePlugin() {
335 mCrypto->initCheck();
336
337 mCrypto->isCryptoSchemeSupported(kClearKeyUUID);
338 mCrypto->createPlugin(kClearKeyUUID, NULL, 0);
339 }
340
invokeCryptoDestroyPlugin()341 void DrmFuzzer::invokeCryptoDestroyPlugin() { mCrypto->destroyPlugin(); }
342
invokeCryptoDecrypt(const uint8_t * data)343 void DrmFuzzer::invokeCryptoDecrypt(const uint8_t *data) {
344 mCrypto->requiresSecureDecoderComponent(
345 kMimeType[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, kNumMimeType - 1)]);
346
347 uint32_t width = mFuzzedDataProvider->ConsumeIntegral<uint32_t>();
348 uint32_t height = mFuzzedDataProvider->ConsumeIntegral<uint32_t>();
349 mCrypto->notifyResolution(width, height);
350
351 mCrypto->setMediaDrmSession(mSessionId);
352
353 const CryptoPlugin::Pattern pattern = {0, 0};
354
355 size_t totalSize = 0;
356 size_t numSubSamples = mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(1, kMaxSubSamples);
357
358 CryptoPlugin::SubSample subSamples[numSubSamples];
359
360 for (size_t i = 0; i < numSubSamples; ++i) {
361 uint32_t clearBytes =
362 mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(1, kMaxNumBytes);
363 uint32_t encryptedBytes =
364 mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(1, kMaxNumBytes);
365 subSamples[i].mNumBytesOfClearData = clearBytes;
366 subSamples[i].mNumBytesOfEncryptedData = encryptedBytes;
367 totalSize += subSamples[i].mNumBytesOfClearData;
368 totalSize += subSamples[i].mNumBytesOfEncryptedData;
369 }
370
371 size_t heapSize = totalSize * 2;
372 sp<MemoryDealer> dealer = new MemoryDealer(heapSize, "DrmFuzzerMemory");
373 if (!dealer) {
374 return;
375 }
376
377 sp<HidlMemory> heap = fromHeap(dealer->getMemoryHeap());
378 if (!heap) {
379 return;
380 }
381 int heapSeqNum = mCrypto->setHeap(heap);
382 if (heapSeqNum < 0) {
383 return;
384 }
385
386 const size_t segmentIndex = 0;
387 const uint8_t keyId[AES_BLOCK_SIZE] = {};
388 memcpy((void *)keyId, data, AES_BLOCK_SIZE);
389
390 const uint8_t iv[AES_BLOCK_SIZE] = {};
391 memset((void *)iv, 0, AES_BLOCK_SIZE);
392
393 const SharedBuffer sourceBuffer = {.bufferId = segmentIndex, .offset = 0, .size = totalSize};
394
395 const DestinationBuffer destBuffer = {
396 .type = BufferType::SHARED_MEMORY,
397 {.bufferId = segmentIndex, .offset = totalSize, .size = totalSize},
398 .secureMemory = nullptr};
399
400 const uint64_t offset = 0;
401 AString *errorDetailMsg = nullptr;
402 CryptoPlugin::Mode mode;
403 bool shouldPassRandomCryptoMode = mFuzzedDataProvider->ConsumeBool();
404 if (shouldPassRandomCryptoMode) {
405 mode = static_cast<CryptoPlugin::Mode>(mFuzzedDataProvider->ConsumeIntegral<size_t>());
406 } else {
407 mode =
408 kCryptoMode[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, kNumCryptoMode - 1)];
409 }
410 mCrypto->decrypt(keyId, iv, mode, pattern, sourceBuffer, offset, subSamples, numSubSamples,
411 destBuffer, errorDetailMsg);
412
413 if (heapSeqNum >= 0) {
414 mCrypto->unsetHeap(heapSeqNum);
415 }
416 heap.clear();
417 }
418
invokeDrm(const uint8_t * data,size_t size)419 void DrmFuzzer::invokeDrm(const uint8_t *data, size_t size) {
420 if (!initDrm()) {
421 return;
422 }
423 invokeDrmCreatePlugin();
424 invokeDrmOpenSession();
425 invokeDrmSetAlgorithmAPI();
426 invokeDrmSetListener();
427 invokeDrmPropertyAPI();
428 invokeDrmDecryptEncryptAPI(data, size);
429 invokeDrmSecureStopAPI();
430 invokeDrmOfflineLicenseAPI();
431 invokeDrmCloseSession();
432 invokeDrmDestroyPlugin();
433 }
434
invokeCrypto(const uint8_t * data)435 void DrmFuzzer::invokeCrypto(const uint8_t *data) {
436 if (!initCrypto()) {
437 return;
438 }
439 invokeCryptoCreatePlugin();
440 invokeCryptoDecrypt(data);
441 invokeCryptoDestroyPlugin();
442 }
443
process(const uint8_t * data,size_t size)444 void DrmFuzzer::process(const uint8_t *data, size_t size) {
445 mFuzzedDataProvider = new FuzzedDataProvider(data, size);
446 invokeDrm(data, size);
447 invokeCrypto(data);
448 delete mFuzzedDataProvider;
449 }
450
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)451 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
452 if (size < AES_BLOCK_SIZE) {
453 return 0;
454 }
455 DrmFuzzer drmFuzzer;
456 drmFuzzer.process(data, size);
457 return 0;
458 }
459