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