• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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