Merge changes If8132ed6,I1be1f040 into main

* changes:
  Added content_decryption_fuzzer
  Added policy_engine_fuzzer
This commit is contained in:
Ayushi Khopkar
2023-10-04 04:08:13 +00:00
committed by Android (Google) Code Review
4 changed files with 825 additions and 0 deletions

77
fuzzer/Android.bp Normal file
View File

@@ -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"],
}

53
fuzzer/README.md Normal file
View File

@@ -0,0 +1,53 @@
# Fuzzers for libcdm
## Table of contents
+ [policy_engine_fuzzer](#PolicyEngine)
+ [content_decryption_fuzzer](#ContentDecryption)
# <a name="PolicyEngine"></a> 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
```
# <a name="ContentDecryption"></a> 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
```

View File

@@ -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 <fuzzer/FuzzedDataProvider.h>
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<int32_t>();
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<WvContentDecryptionModule>::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<uint32_t>();
mCdmIdentifier.user_id = mFdp.ConsumeIntegral<uint32_t>();
}
mDecryptor->OpenSession(KEY_SYSTEM, mFuzzCdmClientPropertySet.get(),
mCdmIdentifier, &fuzzWvCdmEventListener,
&mSessionId);
};
~ContentDecryptionFuzzer() { mDecryptor->CloseSession(mSessionId); }
void process();
private:
FuzzedDataProvider mFdp;
std::unique_ptr<FuzzCdmClientPropertySet> mFuzzCdmClientPropertySet;
CdmSessionId mSessionId;
CdmIdentifier mCdmIdentifier;
sp<WvContentDecryptionModule> mDecryptor;
void invokeDecryptorSessionAPIs();
void invokeProvisionAPIs();
};
void ContentDecryptionFuzzer::invokeDecryptorSessionAPIs() {
CdmKeySetId keySetId = mFdp.ConsumeRandomLengthString(kMaxByte);
while (mFdp.remaining_bytes()) {
auto invokeDecryptionSessionAPI =
mFdp.PickValueInArray<const std::function<void()>>({
[&]() { mDecryptor->IsOpenSession(mSessionId); },
[&]() {
CdmAppParameterMap appParameters;
int32_t maxSize =
mFdp.ConsumeIntegralInRange<int32_t>(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<int32_t>(
kLicenseTypeOffline, kLicenseTypeEmbeddedKeyData);
CdmKeyRequest keyRequest;
keyRequest.message = mFdp.ConsumeRandomLengthString(kMaxByte);
keyRequest.type =
(CdmKeyRequestType)mFdp.ConsumeIntegralInRange<int32_t>(
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<uint32_t>();
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<int32_t>(
kSecurityLevelUninitialized, kSecurityLevelUnknown);
mDecryptor->IsSecurityLevelSupported(level);
},
});
invokeDecryptionSessionAPI();
}
}
void ContentDecryptionFuzzer::invokeProvisionAPIs() {
while (mFdp.remaining_bytes()) {
auto invokeProvisionAPI =
mFdp.PickValueInArray<const std::function<void()>>({
[&]() {
CdmSecurityLevel level =
(CdmSecurityLevel)mFdp.ConsumeIntegralInRange<int32_t>(
kSecurityLevelUninitialized, kSecurityLevelUnknown);
mDecryptor->Unprovision(level, mCdmIdentifier);
},
[&]() {
CdmKeyMessage keyMsg;
CdmCertificateType certificateType =
(CdmCertificateType)mFdp.ConsumeIntegral<int32_t>();
std::string certAuthority =
mFdp.ConsumeRandomLengthString(kMaxByte);
RequestedSecurityLevel securityLevel =
(RequestedSecurityLevel)mFdp.ConsumeIntegral<uint32_t>();
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<uint32_t>();
std::string cert, wrappedKey;
mDecryptor->HandleProvisioningResponse(
mCdmIdentifier, response, securityLevel,
(mFdp.ConsumeBool() ? nullptr : &cert),
(mFdp.ConsumeBool() ? nullptr : &wrappedKey));
},
[&]() {
CdmSecurityLevel level =
(CdmSecurityLevel)mFdp.ConsumeIntegralInRange<int32_t>(
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<const std::function<void()>>({
[&]() { invokeDecryptorSessionAPIs(); },
[&]() { invokeProvisionAPIs(); },
});
invokeContentDecryptionAPI();
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
ContentDecryptionFuzzer contentDecryptionFuzzer(data, size);
contentDecryptionFuzzer.process();
return 0;
}

View File

@@ -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 <fuzzer/FuzzedDataProvider.h>
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<void(bool)> function,
FuzzedDataProvider *fdp) {
if (fdp->ConsumeBool()) {
function(fdp->ConsumeBool());
}
}
void policySetInt64(std::function<void(int64_t)> function,
FuzzedDataProvider *fdp) {
if (fdp->ConsumeBool()) {
function(fdp->ConsumeIntegral<int64_t>());
}
}
void PolicyEngineFuzzer::setUp() {
License::KeyContainer *key = mLicense.add_key();
int32_t keyType = mFdp.ConsumeIntegralInRange<uint8_t>(
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<int64_t>());
}
if (mFdp.ConsumeBool()) {
License_KeyContainer_OutputProtection *outputProtection =
key->mutable_required_protection();
License_KeyContainer_OutputProtection_HDCP hdcpLevel =
(License_KeyContainer_OutputProtection_HDCP)mFdp
.ConsumeIntegralInRange<uint8_t>(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<uint8_t>(
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<uint8_t>(
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<uint8_t>(
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<uint8_t>(
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<uint8_t>(
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> cryptoSession(
wvcdm::CryptoSession::MakeCryptoSession(&crypto_metrics));
std::unique_ptr<PolicyEngine> policyEngine(new PolicyEngine(
sessionId, &fuzzWvCdmEventListener, cryptoSession.get()));
while (mFdp.remaining_bytes()) {
auto invokePolicyEngineAPI =
mFdp.PickValueInArray<const std::function<void()>>({
[&]() { policyEngine->CanDecryptContent(mKeyId); },
[&]() { policyEngine->CanUseKeyForSecurityLevel(mKeyId); },
[&]() { policyEngine->OnTimerEvent(); },
[&]() {
policyEngine->SetLicense(
mLicense, mFdp.ConsumeBool() /*defer_license_state_update*/);
},
[&]() {
int32_t maxEntitledKey =
mFdp.ConsumeIntegralInRange<uint8_t>(1, kMaxEntitledKey);
std::vector<WidevinePsshData_EntitledKey> 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<int64_t>() /*current_time*/);
},
[&]() {
int32_t width = mFdp.ConsumeIntegralInRange<int32_t>(
kMinResolution, kMaxResolution);
int32_t height = mFdp.ConsumeIntegralInRange<int32_t>(
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<int64_t>() /*playback_start_time*/,
mFdp.ConsumeIntegral<int64_t>() /*last_playback_time*/,
mFdp.ConsumeIntegral<int64_t>() /*grace_period_end_time*/);
},
[&]() {
policyEngine->HasLicenseOrRentalOrPlaybackDurationExpired(
mFdp.ConsumeIntegral<int64_t>());
},
});
invokePolicyEngineAPI();
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
PolicyEngineFuzzer policyEngineFuzzer(data, size);
policyEngineFuzzer.process();
return 0;
}