diff --git a/fuzzer/Android.bp b/fuzzer/Android.bp
new file mode 100644
index 00000000..5d1da141
--- /dev/null
+++ b/fuzzer/Android.bp
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+cc_defaults {
+ name: "libcdm_fuzzer_defaults",
+ cflags: [
+ "-DDYNAMIC_ADAPTER",
+ ],
+ static_libs: [
+ "libcdm",
+ "libcdm_protos",
+ "libcdm_utils",
+ "libwvlevel3",
+ "libwv_odk",
+ "libjsmn",
+ ],
+ shared_libs: [
+ "libcrypto",
+ "libprotobuf-cpp-lite",
+ "libbinder_ndk",
+ "liblog",
+ "libbase",
+ "libutils",
+ ],
+ include_dirs: [
+ "vendor/widevine/libwvdrmengine/cdm/core/include",
+ "vendor/widevine/libwvdrmengine/cdm/metrics/include",
+ "vendor/widevine/libwvdrmengine/cdm/util/include",
+ "vendor/widevine/libwvdrmengine/cdm/include",
+ "vendor/widevine/libwvdrmengine/oemcrypto/include",
+ "vendor/widevine/libwvdrmengine/oemcrypto/odk/include",
+ "external/jsmn",
+ "external/protobuf/src"
+ ],
+ header_libs: ["libutils_headers"],
+ fuzz_config: {
+ cc: [
+ "android-media-fuzzing-reports@google.com",
+ ],
+ componentid: 59148,
+ untrusted_data: true,
+ critical: false,
+ hotlists: ["4593311"],
+ description: "The fuzzers target the APIs of all widevine modules",
+ vector: "local_no_privileges_required",
+ service_privilege: "privileged",
+ users: "single_user",
+ fuzzed_code_usage: "shipped"
+ },
+ proprietary: true,
+ vendor: true,
+}
+
+cc_fuzz {
+ name: "policy_engine_fuzzer",
+ srcs: ["policy_engine_fuzzer.cpp"],
+ defaults: ["libcdm_fuzzer_defaults"],
+}
+
+cc_fuzz {
+ name: "content_decryption_fuzzer",
+ srcs: ["content_decryption_fuzzer.cpp"],
+ defaults: ["libcdm_fuzzer_defaults"],
+}
diff --git a/fuzzer/README.md b/fuzzer/README.md
new file mode 100644
index 00000000..adce4395
--- /dev/null
+++ b/fuzzer/README.md
@@ -0,0 +1,53 @@
+# Fuzzers for libcdm
+
+## Table of contents
++ [policy_engine_fuzzer](#PolicyEngine)
++ [content_decryption_fuzzer](#ContentDecryption)
+
+# Fuzzer for PolicyEngine
+
+PolicyEngine supports the following parameters:
+1. SigningKeyId (parameter name: "kSigningKeyId")
+2. RenewalServerUrl (parameter name: "kRenewalServerUrl")
+3. EntitlementKeyId (parameter name: "kEntitlementKeyId")
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+|`kSigningKeyId`| `String` |Value obtained from FuzzedDataProvider|
+|`kRenewalServerUrl`| `String` |Value obtained from FuzzedDataProvider|
+|`kEntitlementKeyId`| `String` |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+ $ mm -j$(nproc) policy_engine_fuzzer
+```
+2. Run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/policy_engine_fuzzer/vendor/policy_engine_fuzzer
+```
+
+# Fuzzer for ContentDecryption
+
+ContentDecryption supports the following parameters:
+1. Cert Authority (parameter name: "certAuthority")
+2. Server Url (parameter name: "serverUrl")
+3. Service Certificate (parameter name: "serviceCertificate")
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+|`certAuthority`| `String` |Value obtained from FuzzedDataProvider|
+|`serverUrl`| `String` |Value obtained from FuzzedDataProvider|
+|`serviceCertificate`| `String` |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+ $ mm -j$(nproc) content_decryption_fuzzer
+```
+2. Run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/content_decryption_fuzzer/vendor/content_decryption_fuzzer
+```
diff --git a/fuzzer/content_decryption_fuzzer.cpp b/fuzzer/content_decryption_fuzzer.cpp
new file mode 100644
index 00000000..68b22b7b
--- /dev/null
+++ b/fuzzer/content_decryption_fuzzer.cpp
@@ -0,0 +1,342 @@
+/*
+ * 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 "cdm_client_property_set.h"
+#include "cdm_identifier.h"
+#include "wv_cdm_constants.h"
+#include "wv_cdm_event_listener.h"
+#include "wv_content_decryption_module.h"
+#include
+
+using namespace wvcdm;
+using namespace android;
+
+const std::string kAppId = "com.example.test";
+static constexpr int32_t kMaxByte = 256;
+static constexpr int32_t kMinSetId = 1;
+static constexpr int32_t kMaxSetId = 100;
+static constexpr int32_t kMinSize = 1;
+static constexpr int32_t kMaxSize = 1024;
+static constexpr int32_t kMaxAppParamSize = 10;
+
+const std::string kSecurityLevel[] = {"QUERY_VALUE_SECURITY_LEVEL_L1",
+ "QUERY_VALUE_SECURITY_LEVEL_L2",
+ "QUERY_VALUE_SECURITY_LEVEL_L3"};
+
+const std::string kQueryLevel[] = {
+ "QUERY_KEY_SECURITY_LEVEL",
+ "QUERY_KEY_CURRENT_HDCP_LEVEL",
+ "QUERY_KEY_MAX_HDCP_LEVEL",
+ "QUERY_KEY_USAGE_SUPPORT",
+ "QUERY_KEY_NUMBER_OF_OPEN_SESSIONS",
+ "QUERY_KEY_MAX_NUMBER_OF_SESSIONS",
+ "QUERY_KEY_OEMCRYPTO_API_VERSION",
+ "QUERY_KEY_CURRENT_SRM_VERSION",
+ "QUERY_KEY_SRM_UPDATE_SUPPORT",
+ "QUERY_KEY_WVCDM_VERSION",
+ "QUERY_KEY_RESOURCE_RATING_TIER",
+ "QUERY_KEY_OEMCRYPTO_BUILD_INFORMATION",
+ "QUERY_KEY_DECRYPT_HASH_SUPPORT",
+ "QUERY_KEY_PROVISIONING_MODEL",
+ "QUERY_KEY_MAX_USAGE_TABLE_ENTRIES",
+ "QUERY_KEY_OEMCRYPTO_API_MINOR_VERSION",
+ "QUERY_KEY_ANALOG_OUTPUT_CAPABILITIES",
+ "QUERY_KEY_CAN_DISABLE_ANALOG_OUTPUT",
+ "QUERY_KEY_WATERMARKING_SUPPORT",
+ "QUERY_KEY_PRODUCTION_READY",
+ "QUERY_KEY_SYSTEM_ID",
+ "QUERY_KEY_DEBUG_BOOT_CERTIFICATE_CHAIN",
+ "QUERY_KEY_DEVICE_ID",
+ "QUERY_KEY_PROVISIONING_ID",
+};
+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,
+};
+
+class FuzzWvCdmEventListener : public WvCdmEventListener {
+public:
+ void OnSessionRenewalNeeded(const CdmSessionId & /*session_id*/) {}
+ void OnSessionKeysChange(const CdmSessionId & /*session_id*/,
+ const CdmKeyStatusMap & /*keys_status*/,
+ bool /*has_new_usable_key*/) {}
+ void OnExpirationUpdate(const CdmSessionId & /*session_id*/,
+ int64_t /*new_expiry_time_seconds*/) {}
+};
+
+class FuzzCdmClientPropertySet : public CdmClientPropertySet {
+public:
+ FuzzCdmClientPropertySet(FuzzedDataProvider *fdp) {
+ mFdp = fdp;
+ mSecurityLevel = fdp->ConsumeBool()
+ ? fdp->ConsumeRandomLengthString(kMaxByte)
+ : fdp->PickValueInArray(kSecurityLevel);
+ mUsePrivacyMode = fdp->ConsumeBool();
+ mIsSessionSharingEnabled = fdp->ConsumeBool();
+ mSessionSharingId = fdp->ConsumeIntegral();
+ mAppId =
+ fdp->ConsumeBool() ? kAppId : fdp->ConsumeRandomLengthString(kMaxByte);
+ }
+
+ const std::string &security_level() const override { return mSecurityLevel; }
+
+ bool use_privacy_mode() const override { return mUsePrivacyMode; }
+
+ const std::string &service_certificate() const override {
+ return mRawServiceCertificate;
+ }
+
+ void set_service_certificate(const std::string &cert) override {
+ if (mFdp->ConsumeBool()) {
+ mRawServiceCertificate = cert;
+ }
+ }
+
+ bool is_session_sharing_enabled() const override {
+ return mIsSessionSharingEnabled;
+ }
+
+ uint32_t session_sharing_id() const override {
+ uint32_t sessionId = 0;
+ if (mFdp->ConsumeBool()) {
+ sessionId = mSessionSharingId;
+ }
+ return sessionId;
+ }
+
+ bool use_atsc_mode() const override { return false; }
+
+ void set_session_sharing_id(uint32_t id) override {
+ if (mFdp->ConsumeBool()) {
+ mSessionSharingId = id;
+ }
+ }
+
+ const std::string &app_id() const override { return mAppId; }
+
+ void enable_privacy_mode() {
+ if (mFdp->ConsumeBool()) {
+ mUsePrivacyMode = true;
+ }
+ }
+
+private:
+ FuzzedDataProvider *mFdp;
+ std::string mSecurityLevel;
+ std::string mRawServiceCertificate;
+ std::string mAppId;
+ uint32_t mSessionSharingId;
+ bool mUsePrivacyMode;
+ bool mIsSessionSharingEnabled;
+};
+
+class ContentDecryptionFuzzer {
+public:
+ ContentDecryptionFuzzer(const uint8_t *data, size_t size) : mFdp(data, size) {
+ mDecryptor = sp::make();
+ FuzzWvCdmEventListener fuzzWvCdmEventListener;
+ mFuzzCdmClientPropertySet.reset(new FuzzCdmClientPropertySet(&mFdp));
+
+ if (mFdp.ConsumeBool()) {
+ mCdmIdentifier = kDefaultCdmIdentifier;
+ } else {
+ mCdmIdentifier.spoid = mFdp.ConsumeRandomLengthString(kMaxByte);
+ mCdmIdentifier.origin = mFdp.ConsumeRandomLengthString(kMaxByte);
+ mCdmIdentifier.app_package_name =
+ mFdp.ConsumeRandomLengthString(kMaxByte);
+ mCdmIdentifier.unique_id = mFdp.ConsumeIntegral();
+ mCdmIdentifier.user_id = mFdp.ConsumeIntegral();
+ }
+ mDecryptor->OpenSession(KEY_SYSTEM, mFuzzCdmClientPropertySet.get(),
+ mCdmIdentifier, &fuzzWvCdmEventListener,
+ &mSessionId);
+ };
+ ~ContentDecryptionFuzzer() { mDecryptor->CloseSession(mSessionId); }
+ void process();
+
+private:
+ FuzzedDataProvider mFdp;
+ std::unique_ptr mFuzzCdmClientPropertySet;
+ CdmSessionId mSessionId;
+ CdmIdentifier mCdmIdentifier;
+ sp mDecryptor;
+ void invokeDecryptorSessionAPIs();
+ void invokeProvisionAPIs();
+};
+
+void ContentDecryptionFuzzer::invokeDecryptorSessionAPIs() {
+ CdmKeySetId keySetId = mFdp.ConsumeRandomLengthString(kMaxByte);
+ while (mFdp.remaining_bytes()) {
+ auto invokeDecryptionSessionAPI =
+ mFdp.PickValueInArray>({
+ [&]() { mDecryptor->IsOpenSession(mSessionId); },
+ [&]() {
+ CdmAppParameterMap appParameters;
+ int32_t maxSize =
+ mFdp.ConsumeIntegralInRange(0, kMaxAppParamSize);
+ for (size_t i = 0; i < maxSize; ++i) {
+ std::string key = mFdp.ConsumeRandomLengthString(kMaxByte);
+ std::string value = mFdp.ConsumeRandomLengthString(kMaxByte);
+ std::string cdmKey(key.c_str(), key.size());
+ std::string cdmValue(value.c_str(), value.size());
+ appParameters[cdmKey] = cdmValue;
+ }
+
+ std::string initDataType = mFdp.PickValueInArray(kInitDataTypes);
+
+ CdmInitData initData = mFdp.ConsumeRandomLengthString(kMaxByte);
+
+ CdmLicenseType licenseType =
+ (CdmLicenseType)mFdp.ConsumeIntegralInRange(
+ kLicenseTypeOffline, kLicenseTypeEmbeddedKeyData);
+
+ CdmKeyRequest keyRequest;
+ keyRequest.message = mFdp.ConsumeRandomLengthString(kMaxByte);
+
+ keyRequest.type =
+ (CdmKeyRequestType)mFdp.ConsumeIntegralInRange(
+ kKeyRequestTypeUnknown, kKeyRequestTypeUpdate);
+
+ keyRequest.url = mFdp.ConsumeRandomLengthString(kMaxByte);
+
+ FuzzCdmClientPropertySet *propertySet =
+ mFdp.ConsumeBool() ? mFuzzCdmClientPropertySet.get()
+ : nullptr;
+
+ mDecryptor->GenerateKeyRequest(
+ mSessionId, keySetId, initDataType, initData, licenseType,
+ appParameters, propertySet, mCdmIdentifier,
+ (mFdp.ConsumeBool() ? nullptr : &keyRequest));
+ },
+ [&]() {
+ CdmKeyResponse response =
+ mFdp.ConsumeRandomLengthString(kMaxByte);
+ mDecryptor->AddKey(mSessionId, response, &keySetId);
+ },
+ [&]() { mDecryptor->RestoreKey(mSessionId, keySetId); },
+ [&]() { mDecryptor->RemoveKeys(mSessionId); },
+ [&]() {
+ RequestedSecurityLevel securityLevel =
+ (RequestedSecurityLevel)mFdp.ConsumeIntegral();
+ std::string outputStr;
+ std::string queryToken =
+ mFdp.ConsumeBool() ? mFdp.ConsumeRandomLengthString(kMaxByte)
+ : mFdp.PickValueInArray(kQueryLevel);
+ ;
+ mDecryptor->QueryStatus(
+ securityLevel, queryToken.c_str(),
+ (mFdp.ConsumeBool() ? nullptr : &outputStr));
+ },
+ [&]() {
+ CdmQueryMap keyInfo;
+ mDecryptor->QuerySessionStatus(
+ mSessionId, (mFdp.ConsumeBool() ? nullptr : &keyInfo));
+ },
+ [&]() {
+ CdmQueryMap keyInfo;
+ mDecryptor->QueryKeyStatus(
+ mSessionId, (mFdp.ConsumeBool() ? nullptr : &keyInfo));
+ },
+ [&]() {
+ CdmQueryMap keyInfo;
+ mDecryptor->QueryOemCryptoSessionId(
+ mSessionId, (mFdp.ConsumeBool() ? nullptr : &keyInfo));
+ },
+ [&]() {
+ CdmSecurityLevel level =
+ (CdmSecurityLevel)mFdp.ConsumeIntegralInRange(
+ kSecurityLevelUninitialized, kSecurityLevelUnknown);
+ mDecryptor->IsSecurityLevelSupported(level);
+ },
+
+ });
+ invokeDecryptionSessionAPI();
+ }
+}
+
+void ContentDecryptionFuzzer::invokeProvisionAPIs() {
+
+ while (mFdp.remaining_bytes()) {
+ auto invokeProvisionAPI =
+ mFdp.PickValueInArray>({
+ [&]() {
+ CdmSecurityLevel level =
+ (CdmSecurityLevel)mFdp.ConsumeIntegralInRange(
+ kSecurityLevelUninitialized, kSecurityLevelUnknown);
+ mDecryptor->Unprovision(level, mCdmIdentifier);
+ },
+ [&]() {
+ CdmKeyMessage keyMsg;
+ CdmCertificateType certificateType =
+ (CdmCertificateType)mFdp.ConsumeIntegral();
+
+ std::string certAuthority =
+ mFdp.ConsumeRandomLengthString(kMaxByte);
+
+ RequestedSecurityLevel securityLevel =
+ (RequestedSecurityLevel)mFdp.ConsumeIntegral();
+
+ std::string serverUrl = mFdp.ConsumeRandomLengthString(kMaxByte);
+
+ std::string serviceCertificate =
+ mFdp.ConsumeRandomLengthString(kMaxByte);
+
+ mDecryptor->GetProvisioningRequest(
+ certificateType, certAuthority, mCdmIdentifier,
+ serviceCertificate, securityLevel,
+ (mFdp.ConsumeBool() ? nullptr : &keyMsg),
+ (mFdp.ConsumeBool() ? nullptr : &serverUrl));
+ },
+ [&]() {
+ std::string response = mFdp.ConsumeRandomLengthString(kMaxByte);
+ RequestedSecurityLevel securityLevel =
+ (RequestedSecurityLevel)mFdp.ConsumeIntegral();
+ std::string cert, wrappedKey;
+ mDecryptor->HandleProvisioningResponse(
+ mCdmIdentifier, response, securityLevel,
+ (mFdp.ConsumeBool() ? nullptr : &cert),
+ (mFdp.ConsumeBool() ? nullptr : &wrappedKey));
+ },
+ [&]() {
+ CdmSecurityLevel level =
+ (CdmSecurityLevel)mFdp.ConsumeIntegralInRange(
+ kSecurityLevelUninitialized, kSecurityLevelUnknown);
+ std::string origin = mFdp.ConsumeRandomLengthString(kMaxByte);
+ std::string spoid = mFdp.ConsumeRandomLengthString(kMaxByte);
+ mDecryptor->IsProvisioned(
+ level, origin, spoid,
+ mFdp.ConsumeBool() /*atsc_mode_enabled*/);
+ },
+ });
+ invokeProvisionAPI();
+ }
+}
+
+void ContentDecryptionFuzzer::process() {
+ auto invokeContentDecryptionAPI =
+ mFdp.PickValueInArray>({
+ [&]() { invokeDecryptorSessionAPIs(); },
+ [&]() { invokeProvisionAPIs(); },
+ });
+ invokeContentDecryptionAPI();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ ContentDecryptionFuzzer contentDecryptionFuzzer(data, size);
+ contentDecryptionFuzzer.process();
+ return 0;
+}
diff --git a/fuzzer/policy_engine_fuzzer.cpp b/fuzzer/policy_engine_fuzzer.cpp
new file mode 100644
index 00000000..435b7f97
--- /dev/null
+++ b/fuzzer/policy_engine_fuzzer.cpp
@@ -0,0 +1,353 @@
+/*
+ * 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 "policy_engine.h"
+#include "wv_cdm_event_listener.h"
+#include
+
+using namespace wvcdm;
+using namespace wvcdm::metrics;
+using namespace video_widevine;
+
+static constexpr int32_t kLicenseIDVersion = 1;
+static constexpr int32_t kMaxByte = 256;
+static constexpr int32_t kMinResolution = 1;
+static constexpr int32_t kMaxResolution = 1024;
+static constexpr int32_t kMaxEntitledKey = 5;
+const KeyId kSigningKeyId = "signing_key";
+const KeyId kEntitlementKeyId = "entitlementkeyid";
+const char *kRenewalServerUrl =
+ "https://test.google.com/license/GetCencLicense";
+
+class FuzzWvCdmEventListener : public WvCdmEventListener {
+ void OnSessionRenewalNeeded(const CdmSessionId & /*session_id*/) {}
+ void OnSessionKeysChange(const CdmSessionId & /*session_id*/,
+ const CdmKeyStatusMap & /*keys_status*/,
+ bool /*has_new_usable_key*/) {}
+ void OnExpirationUpdate(const CdmSessionId & /*session_id*/,
+ int64_t /*new_expiry_time_seconds*/) {}
+};
+
+class PolicyEngineFuzzer {
+public:
+ PolicyEngineFuzzer(const uint8_t *data, size_t size) : mFdp(data, size){};
+ void process();
+
+private:
+ FuzzedDataProvider mFdp;
+ KeyId mKeyId;
+ License mLicense;
+ void setUp();
+};
+
+void policySetBool(std::function function,
+ FuzzedDataProvider *fdp) {
+ if (fdp->ConsumeBool()) {
+ function(fdp->ConsumeBool());
+ }
+}
+
+void policySetInt64(std::function function,
+ FuzzedDataProvider *fdp) {
+ if (fdp->ConsumeBool()) {
+ function(fdp->ConsumeIntegral());
+ }
+}
+
+void PolicyEngineFuzzer::setUp() {
+
+ License::KeyContainer *key = mLicense.add_key();
+ int32_t keyType = mFdp.ConsumeIntegralInRange(
+ License::KeyContainer::SIGNING, License::KeyContainer::ENTITLEMENT);
+ key->set_type((License_KeyContainer_KeyType)keyType);
+ mKeyId = mFdp.ConsumeRandomLengthString(kMaxByte);
+
+ LicenseIdentification *id = mLicense.mutable_id();
+ if (mFdp.ConsumeBool()) {
+ id->set_version(kLicenseIDVersion);
+ }
+ if (mFdp.ConsumeBool()) {
+ id->set_type(mFdp.ConsumeBool() ? STREAMING : OFFLINE);
+ }
+ if (mFdp.ConsumeBool()) {
+ id->set_provider_session_token(mFdp.ConsumeRandomLengthString(kMaxByte));
+ }
+
+ if (mFdp.ConsumeBool()) {
+ mLicense.set_license_start_time(mFdp.ConsumeIntegral());
+ }
+
+ if (mFdp.ConsumeBool()) {
+ License_KeyContainer_OutputProtection *outputProtection =
+ key->mutable_required_protection();
+ License_KeyContainer_OutputProtection_HDCP hdcpLevel =
+ (License_KeyContainer_OutputProtection_HDCP)mFdp
+ .ConsumeIntegralInRange(HDCP_NONE, HDCP_NO_DIGITAL_OUTPUT);
+ outputProtection->set_hdcp(hdcpLevel);
+ }
+
+ if (mFdp.ConsumeBool()) {
+ const std::string ivString = mFdp.ConsumeRandomLengthString(kMaxByte);
+ key->set_iv(ivString);
+ }
+
+ switch (keyType) {
+ case License::KeyContainer::SIGNING: {
+ if (mFdp.ConsumeBool()) {
+ mKeyId = mFdp.ConsumeBool() ? kSigningKeyId : mKeyId;
+ key->set_id(mKeyId);
+ }
+ break;
+ }
+ case License::KeyContainer::CONTENT: {
+ if (mFdp.ConsumeBool()) {
+ key->set_id(mKeyId);
+ }
+ if (mFdp.ConsumeBool()) {
+ int32_t level = mFdp.ConsumeIntegralInRange(
+ License::KeyContainer::SW_SECURE_CRYPTO,
+ License::KeyContainer::HW_SECURE_ALL);
+ key->set_level((License_KeyContainer_SecurityLevel)level);
+ }
+
+ License_Policy *policy = mLicense.mutable_policy();
+ policySetBool(
+ std::bind(&License_Policy::set_can_play, policy, std::placeholders::_1),
+ &mFdp);
+ policySetBool(std::bind(&License_Policy::set_can_persist, policy,
+ std::placeholders::_1), &mFdp);
+ policySetBool(std::bind(&License_Policy::set_can_renew, policy,
+ std::placeholders::_1), &mFdp);
+ policySetBool(std::bind(&License_Policy::set_renew_with_usage, policy,
+ std::placeholders::_1), &mFdp);
+ policySetBool(std::bind(&License_Policy::set_soft_enforce_rental_duration,
+ policy, std::placeholders::_1), &mFdp);
+ policySetBool(std::bind(&License_Policy::set_soft_enforce_playback_duration,
+ policy, std::placeholders::_1), &mFdp);
+
+ policySetInt64(std::bind(&License_Policy::set_rental_duration_seconds,
+ policy, std::placeholders::_1), &mFdp);
+ policySetInt64(std::bind(&License_Policy::set_playback_duration_seconds,
+ policy, std::placeholders::_1), &mFdp);
+ policySetInt64(std::bind(&License_Policy::set_license_duration_seconds,
+ policy, std::placeholders::_1), &mFdp);
+ policySetInt64(
+ std::bind(&License_Policy::set_renewal_recovery_duration_seconds,
+ policy, std::placeholders::_1), &mFdp);
+ policySetInt64(
+ std::bind(&License_Policy::set_renewal_retry_interval_seconds, policy,
+ std::placeholders::_1), &mFdp);
+ policySetInt64(
+ std::bind(&License_Policy::set_renewal_delay_seconds, policy,
+ std::placeholders::_1), &mFdp);
+
+ if (mFdp.ConsumeBool()) {
+ video_widevine::License::Policy::TimerDelayBase timeDelayBase =
+ (video_widevine::License::Policy::TimerDelayBase)mFdp.ConsumeIntegralInRange(
+ License_Policy_TimerDelayBase_TIMER_DELAY_BASE_UNSPECIFIED ,
+ License_Policy_TimerDelayBase_FIRST_DECRYPT);
+ policy->set_initial_renewal_delay_base(timeDelayBase);
+ }
+
+ if (mFdp.ConsumeBool()) {
+ std::string serverUrl = mFdp.ConsumeBool()
+ ? kRenewalServerUrl
+ : mFdp.ConsumeRandomLengthString(kMaxByte);
+ policy->set_renewal_server_url(serverUrl);
+ }
+ break;
+ }
+ case License::KeyContainer::KEY_CONTROL: {
+ key->set_type(License::KeyContainer::KEY_CONTROL);
+ // No control bits for this type of key container used for license
+ break;
+ }
+ case License::KeyContainer::OPERATOR_SESSION: {
+ key->set_type(License::KeyContainer::OPERATOR_SESSION);
+
+ if (mFdp.ConsumeBool()) {
+ key->set_id(mKeyId);
+ }
+
+ if (mFdp.ConsumeBool()) {
+ int32_t level = mFdp.ConsumeIntegralInRange(
+ License::KeyContainer::SW_SECURE_CRYPTO,
+ License::KeyContainer::HW_SECURE_ALL);
+ key->set_level((License_KeyContainer_SecurityLevel)level);
+ }
+
+ if (mFdp.ConsumeBool()) {
+ policySetBool(std::bind(&License_Policy::set_can_persist, mLicense.mutable_policy(),
+ std::placeholders::_1), &mFdp);
+ }
+
+ License::KeyContainer::OperatorSessionKeyPermissions *permissions =
+ key->mutable_operator_session_key_permissions();
+ policySetBool(
+ std::bind(&License::KeyContainer::OperatorSessionKeyPermissions::
+ set_allow_encrypt,
+ permissions, std::placeholders::_1), &mFdp);
+ policySetBool(
+ std::bind(&License::KeyContainer::OperatorSessionKeyPermissions::
+ set_allow_decrypt,
+ permissions, std::placeholders::_1), &mFdp);
+ policySetBool(std::bind(&License::KeyContainer::
+ OperatorSessionKeyPermissions::set_allow_sign,
+ permissions, std::placeholders::_1), &mFdp);
+ policySetBool(
+ std::bind(&License::KeyContainer::OperatorSessionKeyPermissions::
+ set_allow_signature_verify,
+ permissions, std::placeholders::_1), &mFdp);
+ break;
+ }
+ case License::KeyContainer::ENTITLEMENT:
+ default: {
+ if (mFdp.ConsumeBool()) {
+ mKeyId = mFdp.ConsumeBool() ? kEntitlementKeyId : mKeyId;
+ key->set_id(mKeyId);
+ }
+ if (mFdp.ConsumeBool()) {
+ int32_t level = mFdp.ConsumeIntegralInRange(
+ License::KeyContainer::SW_SECURE_CRYPTO,
+ License::KeyContainer::HW_SECURE_ALL);
+ key->set_level((License_KeyContainer_SecurityLevel)level);
+ }
+
+ License_Policy *policy = mLicense.mutable_policy();
+ policySetBool(
+ std::bind(&License_Policy::set_can_play, policy, std::placeholders::_1),
+ &mFdp);
+ policySetBool(std::bind(&License_Policy::set_can_persist, policy,
+ std::placeholders::_1), &mFdp);
+ policySetBool(std::bind(&License_Policy::set_can_renew, policy,
+ std::placeholders::_1), &mFdp);
+ policySetBool(std::bind(&License_Policy::set_renew_with_usage, policy,
+ std::placeholders::_1), &mFdp);
+ policySetBool(std::bind(&License_Policy::set_soft_enforce_rental_duration,
+ policy, std::placeholders::_1), &mFdp);
+ policySetBool(std::bind(&License_Policy::set_soft_enforce_playback_duration,
+ policy, std::placeholders::_1), &mFdp);
+
+ policySetInt64(std::bind(&License_Policy::set_rental_duration_seconds,
+ policy, std::placeholders::_1), &mFdp);
+ policySetInt64(std::bind(&License_Policy::set_playback_duration_seconds,
+ policy, std::placeholders::_1), &mFdp);
+ policySetInt64(std::bind(&License_Policy::set_license_duration_seconds,
+ policy, std::placeholders::_1), &mFdp);
+ policySetInt64(
+ std::bind(&License_Policy::set_renewal_recovery_duration_seconds,
+ policy, std::placeholders::_1), &mFdp);
+ policySetInt64(
+ std::bind(&License_Policy::set_renewal_retry_interval_seconds, policy,
+ std::placeholders::_1), &mFdp);
+ policySetInt64(
+ std::bind(&License_Policy::set_renewal_delay_seconds, policy,
+ std::placeholders::_1), &mFdp);
+
+ if (mFdp.ConsumeBool()) {
+ video_widevine::License::Policy::TimerDelayBase timeDelayBase = (video_widevine::License::Policy::TimerDelayBase)mFdp.ConsumeIntegralInRange(
+ License_Policy_TimerDelayBase_TIMER_DELAY_BASE_UNSPECIFIED ,
+ License_Policy_TimerDelayBase_FIRST_DECRYPT);
+ policy->set_initial_renewal_delay_base(timeDelayBase);
+ }
+ break;
+ }
+ }
+}
+
+void PolicyEngineFuzzer::process() {
+ setUp();
+ FuzzWvCdmEventListener fuzzWvCdmEventListener;
+ CdmSessionId sessionId = mFdp.ConsumeRandomLengthString(kMaxByte);
+ metrics::CryptoMetrics crypto_metrics;
+ std::unique_ptr cryptoSession(
+ wvcdm::CryptoSession::MakeCryptoSession(&crypto_metrics));
+ std::unique_ptr policyEngine(new PolicyEngine(
+ sessionId, &fuzzWvCdmEventListener, cryptoSession.get()));
+
+ while (mFdp.remaining_bytes()) {
+ auto invokePolicyEngineAPI =
+ mFdp.PickValueInArray>({
+ [&]() { policyEngine->CanDecryptContent(mKeyId); },
+ [&]() { policyEngine->CanUseKeyForSecurityLevel(mKeyId); },
+ [&]() { policyEngine->OnTimerEvent(); },
+ [&]() {
+ policyEngine->SetLicense(
+ mLicense, mFdp.ConsumeBool() /*defer_license_state_update*/);
+ },
+ [&]() {
+ int32_t maxEntitledKey =
+ mFdp.ConsumeIntegralInRange(1, kMaxEntitledKey);
+ std::vector entitled_keys(
+ maxEntitledKey);
+ for (int i = 0; i < maxEntitledKey; ++i) {
+ entitled_keys[i].set_entitlement_key_id(
+ mFdp.ConsumeRandomLengthString(kMaxByte));
+ entitled_keys[i].set_key_id(
+ mFdp.ConsumeBool()
+ ? mFdp.ConsumeRandomLengthString(kMaxByte)
+ : mKeyId);
+ }
+ policyEngine->SetEntitledLicenseKeys(entitled_keys);
+ },
+ [&]() { policyEngine->SetLicenseForRelease(mLicense); },
+ [&]() { policyEngine->BeginDecryption(); },
+ [&]() { policyEngine->DecryptionEvent(); },
+ [&]() {
+ policyEngine->UpdateLicense(
+ mLicense, mFdp.ConsumeBool() /*defer_license_state_update*/);
+ },
+ [&]() {
+ policyEngine->UpdateLicenseState(
+ mFdp.ConsumeIntegral() /*current_time*/);
+ },
+ [&]() {
+ int32_t width = mFdp.ConsumeIntegralInRange(
+ kMinResolution, kMaxResolution);
+ int32_t height = mFdp.ConsumeIntegralInRange(
+ kMinResolution, kMaxResolution);
+ policyEngine->NotifyResolution(width, height);
+ },
+ [&]() { policyEngine->NotifySessionExpiration(); },
+ [&]() {
+ CdmQueryMap query_info;
+ policyEngine->Query(&query_info);
+ },
+ [&]() {
+ CdmKeyAllowedUsage key_usage;
+ policyEngine->QueryKeyAllowedUsage(
+ mKeyId, (mFdp.ConsumeBool() ? nullptr : &key_usage));
+ },
+ [&]() {
+ policyEngine->RestorePlaybackTimes(
+ mFdp.ConsumeIntegral() /*playback_start_time*/,
+ mFdp.ConsumeIntegral() /*last_playback_time*/,
+ mFdp.ConsumeIntegral() /*grace_period_end_time*/);
+ },
+ [&]() {
+ policyEngine->HasLicenseOrRentalOrPlaybackDurationExpired(
+ mFdp.ConsumeIntegral());
+ },
+ });
+ invokePolicyEngineAPI();
+ }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ PolicyEngineFuzzer policyEngineFuzzer(data, size);
+ policyEngineFuzzer.process();
+ return 0;
+}