/* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include #include #include #include #include using namespace wvcdm; using namespace video_widevine; using namespace wvutil; static constexpr int32_t kMaxByte = 20; static constexpr int32_t kMinSize = 0; static constexpr int32_t kMaxSize = 1000; const std::string kInitDataTypes[] = { HLS_INIT_DATA_FORMAT, ISO_BMFF_VIDEO_MIME_TYPE, ISO_BMFF_AUDIO_MIME_TYPE, CENC_INIT_DATA_FORMAT, WEBM_VIDEO_MIME_TYPE, WEBM_AUDIO_MIME_TYPE, WEBM_INIT_DATA_FORMAT, }; const std::string kHlsMethod[] = {HLS_METHOD_AES_128, HLS_METHOD_NONE, HLS_METHOD_SAMPLE_AES}; const std::string kOemCryptoWithoutEntitlements = "13"; const std::string kOemCryptoWithEntitlements = "14"; const std::string kInitDataVersions[] = { kOemCryptoWithoutEntitlements, kOemCryptoWithEntitlements, }; const std::string kMultipleWidevinePsshBox = wvutil::a2bs_hex( // first PSSH box, Widevine with single keys "00000042" // atom size "70737368" // atom type "pssh" "00000000" // v0, flags=0 "edef8ba979d64acea3c827dcd51d21ed" // system id (Widevine) "00000022" // data size // data: "08011a0d7769646576696e655f74657374220f73747265616d696e675f636c697031" // second PSSH box, Widevine with entitled keys "000001fb" // atom size "70737368" // atom type="pssh" "00000000" // v0, flags=0 "edef8ba979d64acea3c827dcd51d21ed" // system id (Widevine) "000001db" // data size // data: "220b47726f7570563254657374381448" "e3dc959b065002580272580a10668093" "381a8c5be48a0168ce372726ac1210c8" "326486bb5d5c4a958f00b1111afc811a" "20082cd9d3aed3ebe6239d30fbcf0b22" "1d28cbb0360ea1295c2363973346ec00" "512210914781334e864c8eb7f768cf26" "49073872580a10f872d11d5b1052f2bd" "a94e60a0e383021210450897c987a85c" "2e9579f968554a12991a2097e603ceea" "f35ed8cef1029eae7a0a54701e3d6db6" "80e7da1de3b22a8db347fb2210b41c34" "29b7bb96972bbaf6587bc0ddf172580a" "10bac58b9fce9e5929a42a180e529f19" "4712103f11f22988d25659b145ce4854" "3e6b141a20416e22768e5a57b08d155e" "5210d00658056947ff06d626668bceb3" "5eb01c6b57221081fb2ff3fef79d332f" "f98be46233596972580a101261c8036d" "ae5c8caa968858aa0ca9cc12106d583c" "b37c1456519843a81cf49912221a20c2" "1116bb54a226e8d879a4cd41d8879920" "2ae85b80d83b1b4447e5d7fcad6f6a22" "100b27a4c3f44771d2b0c7c34c66af35" "b572580a10ab1c8c259c6b5967991389" "65bff5ac0c1210b5b4473658565d3786" "efaf4b85d8e6e21a203ce6a9085285c2" "ece0b650dc83dd7aa8ac849611a8e3f8" "3c8f389223c0f3621522101946f0c2a3" "d543101cc842bbec2d0b30"); const std::string kHLSData = "EXT-X-KEY: METHOD=SAMPLE-AES, " "URI=”data:text/plain;base64,eyANCiAgICJwcm92aWRlciI6Im1sYmFtaGJvIiwNCiAg" "ICJjb250ZW50X2lkIjoiMjAxNV9UZWFycyIsDQogICAia2V5X2lkcyI6DQogICBbDQo" "gICAgICAiMzcxZTEzNWUxYTk4NWQ3NWQxOThhN2Y0MTAyMGRjMjMiDQogICBdDQp9DQ" "o=, " "IV=0x6df49213a781e338628d0e9c812d328e, " "KEYFORMAT=”com.widevine”, " "KEYFORMATVERSIONS=”1”"; const std::string kHLSMethodParse = "EXT-X-KEY: METHOD="; const std::string KUriParse = "\"URI=\"data:text/plain;base64,"; const std::string kIVParse = "\"IV="; const std::string kKeyFormatParse = "\"KEYFORMAT=\""; const std::string kKeyFormatVersionParse = "\"KEYFORMATVERSIONS=\""; class BufferReaderFuzzer { public: BufferReaderFuzzer(const uint8_t *data, size_t size) : mFdp(data, size){}; void process(); std::string setPartialRandomHLSData(); std::string setRandomHLSData(); private: FuzzedDataProvider mFdp; }; std::string BufferReaderFuzzer::setPartialRandomHLSData() { std::string hlsMethod = kHLSMethodParse + (mFdp.ConsumeBool() ? mFdp.ConsumeRandomLengthString(kMaxByte) : mFdp.PickValueInArray(kHlsMethod)) + ", \""; std::string uri = KUriParse + (mFdp.ConsumeBool() ? mFdp.ConsumeRandomLengthString(kMaxByte) : "eyANCiAgICJwcm92aWRlciI6Im1sYmFtaGJvIiwNCiAg\" \ \"ICJjb250ZW50X2lkIjoiMjAxNV9UZWFycyIsDQogICAia2V5X2lkcyI6DQogICBbDQo\" \ \"gICAgICAiMzcxZTEzNWUxYTk4NWQ3NWQxOThhN2Y0MTAyMGRjMjMiDQogICBdDQp9DQ\" \ \"o=") + ", \""; std::string iv = kIVParse + ((mFdp.ConsumeBool() ? mFdp.ConsumeRandomLengthString(kMaxByte) : "0x6df49213a781e338628d0e9c812d328e,")) + "\""; std::string keyFormat = kKeyFormatParse + (mFdp.ConsumeBool() ? ("\"" + mFdp.ConsumeRandomLengthString(kMaxByte) + "\"") : "com.widevine\", \""); std::string keyFormatVersion = kKeyFormatVersionParse + (mFdp.ConsumeBool() ? mFdp.ConsumeRandomLengthString(kMaxByte) : "\"1\""); std::string result = hlsMethod + uri + iv + keyFormat + keyFormatVersion; return result; } std::string BufferReaderFuzzer::setRandomHLSData() { std::string hlsMethod; if(mFdp.ConsumeBool()){ hlsMethod = kHLSMethodParse; } hlsMethod += mFdp.ConsumeRandomLengthString(kMaxByte) + ", \""; std::string uri; if(mFdp.ConsumeBool()){ uri = KUriParse; } uri += mFdp.ConsumeRandomLengthString(kMaxByte) + ", \""; std::string iv; if(mFdp.ConsumeBool()){ iv = kIVParse; } iv += mFdp.ConsumeRandomLengthString(kMaxByte) + "\""; std::string keyFormat; if(mFdp.ConsumeBool()){ keyFormat = kKeyFormatParse; } keyFormat += mFdp.ConsumeRandomLengthString(kMaxByte) + "\""; std::string keyFormatVersion; if(mFdp.ConsumeBool()){ keyFormatVersion = kKeyFormatVersionParse; } keyFormatVersion += mFdp.ConsumeRandomLengthString(kMaxByte); std::string result = hlsMethod + uri + iv + keyFormat + keyFormatVersion; return result; } void BufferReaderFuzzer::process() { std::vector rawData = mFdp.ConsumeBytes(mFdp.ConsumeIntegral()); BufferReader reader(rawData.data(), rawData.size()); std::string type = mFdp.PickValueInArray(kInitDataTypes); std::string data; if (type == ISO_BMFF_VIDEO_MIME_TYPE || type == ISO_BMFF_AUDIO_MIME_TYPE || type == CENC_INIT_DATA_FORMAT) { data = mFdp.ConsumeBool() ? wvutil::a2bs_hex(mFdp.ConsumeRandomLengthString(kMaxByte)) : kMultipleWidevinePsshBox; } else if (type == HLS_INIT_DATA_FORMAT) { data = mFdp.PickValueInArray({kHLSData, setPartialRandomHLSData(), setRandomHLSData()}); } else { data = mFdp.ConsumeRandomLengthString(kMaxByte); } std::string initDataType = mFdp.ConsumeBool() ? mFdp.ConsumeRandomLengthString(kMaxByte) : type; std::string version = mFdp.ConsumeBool() ? mFdp.PickValueInArray(kInitDataVersions) : ""; InitializationData initData(initDataType, data, version); while (mFdp.remaining_bytes()) { auto invokeBufferReaderAPIs = mFdp.PickValueInArray>({ [&]() { uint8_t placeholder; mFdp.ConsumeBool() ? reader.Read1(&placeholder) : reader.Read1(nullptr); }, [&]() { uint16_t placeholder; mFdp.ConsumeBool() ? reader.Read2(&placeholder) : reader.Read2(nullptr); }, [&]() { int16_t placeholder; mFdp.ConsumeBool() ? reader.Read2s(&placeholder) : reader.Read2s(nullptr); }, [&]() { int64_t placeholder; mFdp.ConsumeBool() ? reader.Read8s(&placeholder) : reader.Read8s(nullptr); }, [&]() { uint64_t placeholder; mFdp.ConsumeBool() ? reader.Read8(&placeholder) : reader.Read8(nullptr); }, [&]() { int64_t placeholder; mFdp.ConsumeBool() ? reader.Read4sInto8s(&placeholder) : reader.Read4sInto8s(nullptr); }, [&]() { std::string placeholder; mFdp.ConsumeBool() ? reader.ReadString(&placeholder, mFdp.ConsumeIntegralInRange(kMinSize, kMaxSize)) : reader.ReadString(nullptr, mFdp.ConsumeIntegralInRange(kMinSize, kMaxSize)); }, [&]() { std::vector placeholder; mFdp.ConsumeBool() ? reader.ReadVec(&placeholder, mFdp.ConsumeIntegralInRange(kMinSize, kMaxSize)) : reader.ReadVec(nullptr, mFdp.ConsumeIntegralInRange(kMinSize, kMaxSize)); }, [&]() { initData.ExtractWrappedKeys(); }, [&]() { initData.DumpToLogs(); }, [&]() { initData.WidevineSystemID(); }, }); invokeBufferReaderAPIs(); } } extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { BufferReaderFuzzer bufferReaderFuzzer(data, size); bufferReaderFuzzer.process(); return 0; }