diff --git a/fuzzer/Android.bp b/fuzzer/Android.bp
index 2553b5bc..a44a711e 100644
--- a/fuzzer/Android.bp
+++ b/fuzzer/Android.bp
@@ -122,3 +122,9 @@ cc_fuzz {
srcs: ["cdm_engine_fuzzer.cpp"],
defaults: ["libcdm_fuzzer_defaults"],
}
+
+cc_fuzz {
+ name: "certificate_provisioning_fuzzer",
+ srcs: ["certificate_provisioning_fuzzer.cpp"],
+ defaults: ["libcdm_fuzzer_defaults"],
+}
diff --git a/fuzzer/README.md b/fuzzer/README.md
index 9a6f74df..9ab1e445 100644
--- a/fuzzer/README.md
+++ b/fuzzer/README.md
@@ -11,6 +11,7 @@
+ [crypto_session_fuzzer](#CryptoSession)
+ [buffer_reader_fuzzer](#BufferReader)
+ [cdm_engine_fuzzer](#CdmEngine)
++ [certificate_provisioning_fuzzer](#CertificateProvisioning)
# Fuzzer for PolicyEngine
@@ -259,3 +260,26 @@ CdmEngine supports the following parameters:
$ adb sync data
$ adb shell LD_LIBRARY_PATH=/vendor/lib64 /data/fuzz/arm64/cdm_engine_fuzzer/vendor/cdm_engine_fuzzer
```
+# Fuzzer for CertificateProvisioning
+
+CertificateProvisioning supports the following parameters:
+1. service_certificate (parameter name: "service_certificate")
+2. responseMessage (parameter name: "response")
+3. type (parameter name: "type")
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+|`service_certificate`| `String` |Value obtained from FuzzedDataProvider|
+|`responseMessage`| `String` |Value obtained from FuzzedDataProvider|
+|`type`| 1. `ResponseType::kNoError`
2. `ResponseType::kResponseTypeBase`
3. `ResponseType::kObjectNotInitialized`
4. `ResponseType::kParameterNull`
5. `ResponseType::kBasePathUnavailable`
6. `ResponseType::kFileOpenFailed`
7. `ResponseType::kFileWriteError`
8. `ResponseType::kFileReadError`
9. `ResponseType::kInvalidFileSize`
10. `ResponseType::kHashComputationFailed`
11. `ResponseType::kFileHashMismatch`
12. `ResponseType::kFileParseError1`
13. `ResponseType::kFileParseError2`
14. `ResponseType::kUnknownLicenseState`
15. `ResponseType::kIncorrectFileType`
16. `ResponseType::kIncorrectFileVersion`
17. `ResponseType::kLicenseNotPresent` |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+ $ mm -j$(nproc) certificate_provisioning_fuzzer
+```
+2. Run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/certificate_provisioning_fuzzer/vendor/certificate_provisioning_fuzzer
+```
diff --git a/fuzzer/certificate_provisioning_fuzzer.cpp b/fuzzer/certificate_provisioning_fuzzer.cpp
new file mode 100644
index 00000000..800752b4
--- /dev/null
+++ b/fuzzer/certificate_provisioning_fuzzer.cpp
@@ -0,0 +1,198 @@
+/*
+ * 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
+
+using namespace wvcdm;
+using namespace wvutil;
+using namespace video_widevine;
+
+static constexpr uint16_t kMaxByte = 256;
+static constexpr uint16_t kMaxVectorSize = 1000;
+static constexpr uint8_t kMinVectorSize = 0;
+static constexpr uint8_t kMinCdmCertificateType = 0;
+static constexpr uint8_t kMaxCdmCertificateType = 2;
+static constexpr uint8_t kMinKeySetId = 0;
+static constexpr uint8_t kMaxKeySetId = 100;
+
+static constexpr uint8_t kProvisioningType[] = {
+ SignedProvisioningMessage_ProvisioningType_PROVISIONING_TYPE_UNSPECIFIED,
+ SignedProvisioningMessage_ProvisioningType_SERVICE_CERTIFICATE_REQUEST,
+ SignedProvisioningMessage_ProvisioningType_PROVISIONING_20,
+ SignedProvisioningMessage_ProvisioningType_PROVISIONING_30,
+ SignedProvisioningMessage_ProvisioningType_PROVISIONING_40,
+ SignedProvisioningMessage_ProvisioningType_ARCPP_PROVISIONING,
+ SignedProvisioningMessage_ProvisioningType_ANDROID_ATTESTATION_KEYBOX_OTA,
+ SignedProvisioningMessage_ProvisioningType_INTEL_SIGMA_101,
+ SignedProvisioningMessage_ProvisioningType_INTEL_SIGMA_210};
+
+class CertificateProvisioningFuzzer {
+public:
+ CertificateProvisioningFuzzer(const uint8_t *data, size_t size)
+ : mFdp(data, size){};
+ void process();
+
+private:
+ FuzzedDataProvider mFdp;
+};
+
+void createResponseMessage(std::string &responseMessage,
+ FuzzedDataProvider &mFdp) {
+ if (mFdp.ConsumeBool()) {
+ DrmCertificate drmCertificate;
+
+ DrmCertificate_Algorithm algorithm =
+ (DrmCertificate_Algorithm)mFdp.ConsumeIntegralInRange(
+ DrmCertificate_Algorithm::
+ DrmCertificate_Algorithm_UNKNOWN_ALGORITHM,
+ DrmCertificate_Algorithm::DrmCertificate_Algorithm_ECC_SECP521R1);
+
+ drmCertificate.set_algorithm(algorithm);
+
+ std::string setDrm;
+ if (mFdp.ConsumeBool()) {
+ drmCertificate.SerializeToString(&setDrm);
+ } else {
+ setDrm = mFdp.ConsumeRandomLengthString(kMaxByte);
+ }
+
+ SignedDrmCertificate signedDrmCertificate;
+ signedDrmCertificate.set_drm_certificate(setDrm);
+
+ std::string setDevice;
+ if (mFdp.ConsumeBool()) {
+ signedDrmCertificate.SerializeToString(&setDevice);
+ } else {
+ setDevice = mFdp.ConsumeRandomLengthString(kMaxByte);
+ }
+
+ ProvisioningResponse provisioningResponse;
+ ProvisioningResponse_ProvisioningStatus status =
+ (ProvisioningResponse_ProvisioningStatus)mFdp.ConsumeIntegralInRange<
+ int32_t>(
+ ProvisioningResponse_ProvisioningStatus::
+ ProvisioningResponse_ProvisioningStatus_NO_ERROR,
+ ProvisioningResponse_ProvisioningStatus::
+ ProvisioningResponse_ProvisioningStatus_REVOKED_DEVICE_SERIES);
+
+ provisioningResponse.set_status(status);
+
+ if (mFdp.ConsumeBool()) {
+ provisioningResponse.set_device_certificate(setDevice);
+ }
+
+ std::string setMessage;
+ if (mFdp.ConsumeBool()) {
+ provisioningResponse.SerializeToString(&setMessage);
+ } else {
+ setMessage = mFdp.ConsumeRandomLengthString(kMaxByte);
+ }
+
+ SignedProvisioningMessage signedProvisioningMessage;
+ if (mFdp.ConsumeBool()) {
+ signedProvisioningMessage.set_message(setMessage);
+ } else {
+ signedProvisioningMessage.set_message(
+ mFdp.ConsumeRandomLengthString(kMaxByte));
+ }
+
+ signedProvisioningMessage.set_signature(
+ mFdp.ConsumeRandomLengthString(kMaxByte));
+ if (mFdp.ConsumeBool()) {
+ signedProvisioningMessage.set_provisioning_type(
+ (SignedProvisioningMessage_ProvisioningType)mFdp.PickValueInArray(
+ kProvisioningType));
+ } else {
+ signedProvisioningMessage.set_provisioning_type(
+ (SignedProvisioningMessage_ProvisioningType)
+ mFdp.ConsumeIntegral());
+ }
+
+ signedProvisioningMessage.set_oemcrypto_core_message(
+ mFdp.ConsumeRandomLengthString(kMaxByte));
+ if (mFdp.ConsumeBool()) {
+ signedProvisioningMessage.SerializeToString(&responseMessage);
+ } else {
+ responseMessage = mFdp.ConsumeRandomLengthString(kMaxByte);
+ }
+ }
+
+ responseMessage =
+ (mFdp.ConsumeBool() ? "\"signedResponse\": \"" : "") +
+ (mFdp.ConsumeBool() ? Base64SafeEncode(responseMessage) : "") +
+ (mFdp.ConsumeBool() ? "\"" : "");
+}
+
+void CertificateProvisioningFuzzer::process() {
+ FileSystem fileSystem;
+ metrics::CryptoMetrics cryptoMetrics;
+ CertificateProvisioning certificateProvisioning(&cryptoMetrics);
+ certificateProvisioning.Init(
+ mFdp.ConsumeRandomLengthString(kMaxByte) /* service_certificate */
+ );
+ while (mFdp.remaining_bytes()) {
+ auto invokeCertificateProvisioningAPI =
+ mFdp.PickValueInArray>(
+ {[&]() {
+ CdmProvisioningRequest request;
+ std::string defaultUrl;
+
+ certificateProvisioning.GetProvisioningRequest(
+ &fileSystem,
+ (RequestedSecurityLevel)mFdp.ConsumeBool()
+ ? kLevelDefault
+ : kLevel3, /* requested_security_level */
+ (CdmCertificateType)mFdp.ConsumeIntegralInRange(
+ kMinCdmCertificateType,
+ kMaxCdmCertificateType), /* cert_type */
+ mFdp.ConsumeRandomLengthString(
+ kMaxByte), /* cert_authority */
+ mFdp.ConsumeRandomLengthString(kMaxByte), /* origin */
+ mFdp.ConsumeRandomLengthString(kMaxByte), /* spoid */
+ mFdp.ConsumeBool() ? &request : nullptr, &defaultUrl);
+ },
+
+ [&]() {
+ CdmProvisioningResponse responseMessage;
+ createResponseMessage(responseMessage, mFdp);
+
+ std::string cert;
+ std::string wrappedKey;
+
+ certificateProvisioning.HandleProvisioningResponse(
+ &fileSystem, responseMessage, &cert, &wrappedKey);
+ },
+
+ [&]() {
+ std::string defaultUrl;
+
+ CertificateProvisioning::GetProvisioningServerUrl(
+ mFdp.ConsumeBool() ? &defaultUrl : nullptr);
+ }});
+
+ invokeCertificateProvisioningAPI();
+ }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ CertificateProvisioningFuzzer certificateProvisioningFuzzer(data, size);
+ certificateProvisioningFuzzer.process();
+ return 0;
+}