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