Added fuzzers for libkeymaster4support
This patch adds following fuzz targets: keymaster4_attestation_fuzzer, keymaster4_authSet_fuzzer and keymaster4_utils_fuzzer
Test: ./keymaster4_attestation_fuzzer
Test: ./keymaster4_authSet_fuzzer
Test: ./keymaster4_utils_fuzzer
Bug: 189053968
Change-Id: Ieca5ba012f395a25cca9e37856d197031daf7dd9
diff --git a/keymaster/4.0/support/fuzzer/Android.bp b/keymaster/4.0/support/fuzzer/Android.bp
new file mode 100644
index 0000000..57a2d26
--- /dev/null
+++ b/keymaster/4.0/support/fuzzer/Android.bp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2021 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: "keymaster4_fuzzer_defaults",
+ static_libs: [
+ "libbase",
+ "liblog",
+ "libkeymaster4support",
+ "libutils",
+ ],
+ shared_libs: [
+ "android.hardware.keymaster@4.0",
+ "libcrypto",
+ "libhidlbase",
+ ],
+ fuzz_config: {
+ cc: [
+ "android-media-fuzzing-reports@google.com",
+ ],
+ componentid: 533764,
+ },
+}
+
+cc_fuzz {
+ name: "keymaster4_attestation_fuzzer",
+ defaults: [
+ "keymaster4_fuzzer_defaults",
+ ],
+ srcs: [
+ "keymaster4_attestation_fuzzer.cpp",
+ ],
+}
+
+cc_fuzz {
+ name: "keymaster4_authSet_fuzzer",
+ defaults: [
+ "keymaster4_fuzzer_defaults",
+ ],
+ srcs: [
+ "keymaster4_authSet_fuzzer.cpp",
+ ],
+}
+
+cc_fuzz {
+ name: "keymaster4_utils_fuzzer",
+ defaults: [
+ "keymaster4_fuzzer_defaults",
+ ],
+ srcs: [
+ "keymaster4_utils_fuzzer.cpp",
+ ],
+}
diff --git a/keymaster/4.0/support/fuzzer/README.md b/keymaster/4.0/support/fuzzer/README.md
new file mode 100644
index 0000000..bf4af25
--- /dev/null
+++ b/keymaster/4.0/support/fuzzer/README.md
@@ -0,0 +1,58 @@
+# Fuzzers for libkeymaster4support
+
+## Plugin Design Considerations
+The fuzzer plugins for libkeymaster4support are designed based on the understanding of the
+source code and try to achieve the following:
+
+##### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzers.
+
+libkeymaster4support supports the following parameters:
+1. Security Level (parameter name: `securityLevel`)
+2. Ec Curve (parameter name: `ecCurve`)
+3. Padding Mode (parameter name: `paddingMode`)
+4. Digest (parameter name: `digest`)
+5. Tag (parameter name: `tag`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `securityLevel` | 0.`SecurityLevel::SOFTWARE` 1.`SecurityLevel::TRUSTED_ENVIRONMENT` 2.`SecurityLevel::STRONGBOX`| Value obtained from FuzzedDataProvider|
+| `ecCurve` | 0.`EcCurve::P_224` 1.`EcCurve::P_256` 2.`EcCurve::P_384` 3. `EcCurve::P_521`| Value obtained from FuzzedDataProvider|
+| `paddingMode` | 0.`PaddingMode::NONE` 1.`PaddingMode::RSA_OAEP` 2.`PaddingMode::RSA_PSS` 3. `PaddingMode::RSA_PKCS1_1_5_ENCRYPT` 4.`PaddingMode::RSA_PKCS1_1_5_SIGN` 5.`PaddingMode::PKCS7`| Value obtained from FuzzedDataProvider|
+| `digest` | 1. `Digest::NONE` 2.`Digest::MD5` 3.`Digest::SHA1` 4.`Digest::SHA_2_224` 5.`Digest::SHA_2_256` 6.`Digest::SHA_2_384` 7.`Digest::SHA_2_512`| Value obtained from FuzzedDataProvider|
+| `tag` | 1. `Tag::INVALID` 2.`Tag::PURPOSE` 3.`Tag::ALGORITHM` 4.`Tag::KEY_SIZE` 5.`Tag::BLOCK_MODE` 6.`Tag::DIGEST` 7.`Tag::PADDING` 8.`Tag::CALLER_NONCE` 9.`Tag::MIN_MAC_LENGTH` 10.`Tag::EC_CURVE` 11.`Tag::RSA_PUBLIC_EXPONENT` 12.`Tag::INCLUDE_UNIQUE_ID` 13. `Tag::BLOB_USAGE_REQUIREMENTS` 14.`Tag::BOOTLOADER_ONLY` 15.`Tag::ROLLBACK_RESISTANCE` 16.`Tag::HARDWARE_TYPE` 17.`Tag::ACTIVE_DATETIME` 18. `Tag::ORIGINATION_EXPIRE_DATETIME` 19.`Tag::USAGE_EXPIRE_DATETIME` 20.`Tag::MIN_SECONDS_BETWEEN_OPS` 21.`Tag::MAX_USES_PER_BOOT` 22.`Tag::USER_ID` 23.` Tag::USER_SECURE_ID` 24.`Tag::NO_AUTH_REQUIRED` 25.`Tag::USER_AUTH_TYPE` 26.`Tag::AUTH_TIMEOUT` 27.`Tag::ALLOW_WHILE_ON_BODY` 28.`Tag::TRUSTED_USER_PRESENCE_REQUIRED` 29.`Tag::TRUSTED_CONFIRMATION_REQUIRED` 30.`Tag::UNLOCKED_DEVICE_REQUIRED` 31.`Tag::APPLICATION_ID` 32.`Tag::APPLICATION_DATA` 33.`Tag::CREATION_DATETIME` 34.`Tag::ORIGIN` 35.`Tag::ROOT_OF_TRUST` 36.`Tag::OS_VERSION` 37.`Tag::OS_PATCHLEVEL` 38.`Tag::UNIQUE_ID` 39.`Tag::ATTESTATION_CHALLENGE` 40.`Tag::ATTESTATION_APPLICATION_ID` 41.`Tag::ATTESTATION_ID_BRAND` 42.`Tag::ATTESTATION_ID_DEVICE` 43.`Tag::ATTESTATION_ID_PRODUCT` 44.`Tag::ATTESTATION_ID_SERIAL` 45.`Tag::ATTESTATION_ID_IMEI` 46.`Tag::ATTESTATION_ID_MEID` 47.`Tag::ATTESTATION_ID_MANUFACTURER` 48.`Tag::ATTESTATION_ID_MODEL` 49.`Tag::VENDOR_PATCHLEVEL` 50.`Tag::BOOT_PATCHLEVEL` 51.`Tag::ASSOCIATED_DATA` 52.`Tag::NONCE` 53.`Tag::MAC_LENGTH` 54.`Tag::RESET_SINCE_ID_ROTATION` 55.`Tag::CONFIRMATION_TOKEN`| Value obtained from FuzzedDataProvider|
+
+This also ensures that the plugins are always deterministic for any given input.
+
+##### Maximize utilization of input data
+The plugins feed the entire input data to the module.
+This ensures that the plugins tolerate any kind of input (empty, huge,
+malformed, etc) and dont `exit()` on any input and thereby increasing the
+chance of identifying vulnerabilities.
+
+## Build
+
+This describes steps to build keymaster4_attestation_fuzzer, keymaster4_authSet_fuzzer and keymaster4_utils_fuzzer binaries
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+ $ mm -j$(nproc) keymaster4_attestation_fuzzer
+ $ mm -j$(nproc) keymaster4_authSet_fuzzer
+ $ mm -j$(nproc) keymaster4_utils_fuzzer
+```
+#### Steps to run
+To run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/${TARGET_ARCH}/keymaster4_attestation_fuzzer/keymaster4_attestation_fuzzer
+ $ adb shell /data/fuzz/${TARGET_ARCH}/keymaster4_authSet_fuzzer/keymaster4_authSet_fuzzer
+ $ adb shell /data/fuzz/${TARGET_ARCH}/keymaster4_utils_fuzzer/keymaster4_utils_fuzzer
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/keymaster/4.0/support/fuzzer/keymaster4_attestation_fuzzer.cpp b/keymaster/4.0/support/fuzzer/keymaster4_attestation_fuzzer.cpp
new file mode 100644
index 0000000..b8b858d
--- /dev/null
+++ b/keymaster/4.0/support/fuzzer/keymaster4_attestation_fuzzer.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2021 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 <android/hardware/keymaster/4.0/IKeymasterDevice.h>
+#include <keymasterV4_0/attestation_record.h>
+#include <keymasterV4_0/openssl_utils.h>
+#include "keymaster4_common.h"
+
+namespace android::hardware::keymaster::V4_0::fuzzer {
+
+constexpr size_t kMinBytes = 1;
+constexpr size_t kMaxBytes = 10;
+
+class KeyMaster4AttestationFuzzer {
+ public:
+ void process(const uint8_t* data, size_t size);
+
+ private:
+ ErrorCode generateKey(const AuthorizationSet& keyDesc, hidl_vec<uint8_t>* keyBlob,
+ KeyCharacteristics* keyCharacteristics);
+ ErrorCode attestKey(hidl_vec<uint8_t>& keyBlob, const AuthorizationSet& attestParams,
+ hidl_vec<hidl_vec<uint8_t>>* certificateChain);
+ X509_Ptr parseCertificateBlob(const hidl_vec<uint8_t>& blob);
+ ASN1_OCTET_STRING* getAttestationRecord(const X509* certificate);
+ bool verifyAttestationRecord(const hidl_vec<uint8_t>& attestationCert);
+ void invokeAttestationRecord();
+
+ sp<IKeymasterDevice> mKeymaster = nullptr;
+ std::unique_ptr<FuzzedDataProvider> mFdp = nullptr;
+};
+
+ErrorCode KeyMaster4AttestationFuzzer::generateKey(const AuthorizationSet& key_desc,
+ hidl_vec<uint8_t>* keyBlob,
+ KeyCharacteristics* keyCharacteristics) {
+ ErrorCode error;
+ mKeymaster->generateKey(key_desc.hidl_data(),
+ [&](ErrorCode hidlError, const hidl_vec<uint8_t>& hidlKeyBlob,
+ const KeyCharacteristics& hidlKeyCharacteristics) {
+ error = hidlError;
+ *keyBlob = hidlKeyBlob;
+ *keyCharacteristics = hidlKeyCharacteristics;
+ });
+ return error;
+}
+
+ErrorCode KeyMaster4AttestationFuzzer::attestKey(hidl_vec<uint8_t>& keyBlob,
+ const AuthorizationSet& attestParams,
+ hidl_vec<hidl_vec<uint8_t>>* certificateChain) {
+ ErrorCode error;
+ auto rc = mKeymaster->attestKey(
+ keyBlob, attestParams.hidl_data(),
+ [&](ErrorCode hidlError, const hidl_vec<hidl_vec<uint8_t>>& hidlCertificateChain) {
+ error = hidlError;
+ *certificateChain = hidlCertificateChain;
+ });
+
+ if (!rc.isOk()) {
+ return ErrorCode::UNKNOWN_ERROR;
+ }
+ return error;
+}
+
+X509_Ptr KeyMaster4AttestationFuzzer::parseCertificateBlob(const hidl_vec<uint8_t>& blob) {
+ const uint8_t* p = blob.data();
+ return X509_Ptr(d2i_X509(nullptr, &p, blob.size()));
+}
+
+/**
+ * @brief getAttestationRecord() accepts a 'certificate' pointer and the return value points to the
+ * data owned by 'certificate'. Hence, 'certificate' should not be freed and the return value cannot
+ * outlive 'certificate'
+ */
+ASN1_OCTET_STRING* KeyMaster4AttestationFuzzer::getAttestationRecord(const X509* certificate) {
+ ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
+ if (!oid.get()) {
+ return nullptr;
+ }
+
+ int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
+ if (location == -1) {
+ return nullptr;
+ }
+
+ X509_EXTENSION* attestRecordExt = X509_get_ext(certificate, location);
+ if (!attestRecordExt) {
+ return nullptr;
+ }
+
+ ASN1_OCTET_STRING* attestRecord = X509_EXTENSION_get_data(attestRecordExt);
+ return attestRecord;
+}
+
+bool KeyMaster4AttestationFuzzer::verifyAttestationRecord(
+ const hidl_vec<uint8_t>& attestationCert) {
+ X509_Ptr cert(parseCertificateBlob(attestationCert));
+ if (!cert.get()) {
+ return false;
+ }
+
+ ASN1_OCTET_STRING* attestRecord = getAttestationRecord(cert.get());
+ if (!attestRecord) {
+ return false;
+ }
+
+ AuthorizationSet attestationSwEnforced;
+ AuthorizationSet attestationHwEnforced;
+ uint32_t attestationVersion;
+ uint32_t keymasterVersion;
+ SecurityLevel securityLevel;
+ SecurityLevel keymasterSecurityLevel;
+ hidl_vec<uint8_t> attestationChallenge;
+ hidl_vec<uint8_t> attestationUniqueId;
+
+ auto error = parse_attestation_record(
+ attestRecord->data, attestRecord->length, &attestationVersion, &securityLevel,
+ &keymasterVersion, &keymasterSecurityLevel, &attestationChallenge,
+ &attestationSwEnforced, &attestationHwEnforced, &attestationUniqueId);
+ if (error != ErrorCode::OK) {
+ return false;
+ }
+
+ hidl_vec<uint8_t> verifiedBootKey;
+ keymaster_verified_boot_t verifiedBootState;
+ bool device_locked;
+ hidl_vec<uint8_t> verifiedBootHash;
+
+ parse_root_of_trust(attestRecord->data, attestRecord->length, &verifiedBootKey,
+ &verifiedBootState, &device_locked, &verifiedBootHash);
+ return true;
+}
+
+void KeyMaster4AttestationFuzzer::invokeAttestationRecord() {
+ mKeymaster = IKeymasterDevice::getService();
+ if (!mKeymaster) {
+ return;
+ }
+
+ hidl_vec<uint8_t> keyBlob;
+ KeyCharacteristics keyCharacteristics;
+ generateKey(createAuthorizationSet(mFdp), &keyBlob, &keyCharacteristics);
+
+ hidl_vec<hidl_vec<uint8_t>> certificateChain;
+
+ std::vector<uint8_t> challenge, attestationId;
+ challenge =
+ mFdp->ConsumeBytes<uint8_t>(mFdp->ConsumeIntegralInRange<size_t>(kMinBytes, kMaxBytes));
+ attestationId =
+ mFdp->ConsumeBytes<uint8_t>(mFdp->ConsumeIntegralInRange<size_t>(kMinBytes, kMaxBytes));
+ attestKey(keyBlob,
+ AuthorizationSetBuilder()
+ .Authorization(TAG_ATTESTATION_CHALLENGE, challenge)
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, attestationId),
+ &certificateChain);
+
+ if (certificateChain.size() > 0) {
+ verifyAttestationRecord(certificateChain[mFdp->ConsumeIntegralInRange<size_t>(
+ 0, certificateChain.size() - 1)]);
+ }
+}
+
+void KeyMaster4AttestationFuzzer::process(const uint8_t* data, size_t size) {
+ mFdp = std::make_unique<FuzzedDataProvider>(data, size);
+ invokeAttestationRecord();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ KeyMaster4AttestationFuzzer km4AttestationFuzzer;
+ km4AttestationFuzzer.process(data, size);
+ return 0;
+}
+
+} // namespace android::hardware::keymaster::V4_0::fuzzer
diff --git a/keymaster/4.0/support/fuzzer/keymaster4_authSet_fuzzer.cpp b/keymaster/4.0/support/fuzzer/keymaster4_authSet_fuzzer.cpp
new file mode 100644
index 0000000..63e0499
--- /dev/null
+++ b/keymaster/4.0/support/fuzzer/keymaster4_authSet_fuzzer.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2021 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 <fstream>
+#include "keymaster4_common.h"
+
+namespace android::hardware::keymaster::V4_0::fuzzer {
+
+constexpr size_t kMaxVectorSize = 100;
+constexpr size_t kMaxKeyParameter = 10;
+
+constexpr Tag kTagArray[] = {Tag::INVALID,
+ Tag::PURPOSE,
+ Tag::ALGORITHM,
+ Tag::KEY_SIZE,
+ Tag::BLOCK_MODE,
+ Tag::DIGEST,
+ Tag::PADDING,
+ Tag::CALLER_NONCE,
+ Tag::MIN_MAC_LENGTH,
+ Tag::EC_CURVE,
+ Tag::RSA_PUBLIC_EXPONENT,
+ Tag::INCLUDE_UNIQUE_ID,
+ Tag::BLOB_USAGE_REQUIREMENTS,
+ Tag::BOOTLOADER_ONLY,
+ Tag::ROLLBACK_RESISTANCE,
+ Tag::HARDWARE_TYPE,
+ Tag::ACTIVE_DATETIME,
+ Tag::ORIGINATION_EXPIRE_DATETIME,
+ Tag::USAGE_EXPIRE_DATETIME,
+ Tag::MIN_SECONDS_BETWEEN_OPS,
+ Tag::MAX_USES_PER_BOOT,
+ Tag::USER_ID,
+ Tag::USER_SECURE_ID,
+ Tag::NO_AUTH_REQUIRED,
+ Tag::USER_AUTH_TYPE,
+ Tag::AUTH_TIMEOUT,
+ Tag::ALLOW_WHILE_ON_BODY,
+ Tag::TRUSTED_USER_PRESENCE_REQUIRED,
+ Tag::TRUSTED_CONFIRMATION_REQUIRED,
+ Tag::UNLOCKED_DEVICE_REQUIRED,
+ Tag::APPLICATION_ID,
+ Tag::APPLICATION_DATA,
+ Tag::CREATION_DATETIME,
+ Tag::ORIGIN,
+ Tag::ROOT_OF_TRUST,
+ Tag::OS_VERSION,
+ Tag::OS_PATCHLEVEL,
+ Tag::UNIQUE_ID,
+ Tag::ATTESTATION_CHALLENGE,
+ Tag::ATTESTATION_APPLICATION_ID,
+ Tag::ATTESTATION_ID_BRAND,
+ Tag::ATTESTATION_ID_DEVICE,
+ Tag::ATTESTATION_ID_PRODUCT,
+ Tag::ATTESTATION_ID_SERIAL,
+ Tag::ATTESTATION_ID_IMEI,
+ Tag::ATTESTATION_ID_MEID,
+ Tag::ATTESTATION_ID_MANUFACTURER,
+ Tag::ATTESTATION_ID_MODEL,
+ Tag::VENDOR_PATCHLEVEL,
+ Tag::BOOT_PATCHLEVEL,
+ Tag::ASSOCIATED_DATA,
+ Tag::NONCE,
+ Tag::MAC_LENGTH,
+ Tag::RESET_SINCE_ID_ROTATION,
+ Tag::CONFIRMATION_TOKEN};
+
+class KeyMaster4AuthSetFuzzer {
+ public:
+ void process(const uint8_t* data, size_t size);
+
+ private:
+ void invokeAuthSetAPIs();
+ std::unique_ptr<FuzzedDataProvider> mFdp = nullptr;
+};
+
+/**
+ * @brief invokeAuthSetAPIs() function aims at calling functions of authorization_set.cpp
+ * and authorization_set.h in order to get a good coverage for libkeymaster4support.
+ */
+void KeyMaster4AuthSetFuzzer::invokeAuthSetAPIs() {
+ AuthorizationSet authSet = createAuthorizationSet(mFdp);
+ while (mFdp->remaining_bytes() > 0) {
+ uint32_t action = mFdp->ConsumeIntegralInRange<uint32_t>(0, 15);
+ switch (action) {
+ case 0: {
+ authSet.Sort();
+ } break;
+ case 1: {
+ authSet.Deduplicate();
+ } break;
+ case 2: {
+ authSet.Union(createAuthorizationSet(mFdp));
+ } break;
+ case 3: {
+ authSet.Subtract(createAuthorizationSet(mFdp));
+ } break;
+ case 4: {
+ std::filebuf fbOut;
+ fbOut.open("/dev/zero", std::ios::out);
+ std::ostream out(&fbOut);
+ authSet.Serialize(&out);
+ } break;
+ case 5: {
+ std::filebuf fbIn;
+ fbIn.open("/dev/zero", std::ios::in);
+ std::istream in(&fbIn);
+ authSet.Deserialize(&in);
+ } break;
+ case 6: { // invoke push_back()
+ AuthorizationSetBuilder builder = AuthorizationSetBuilder();
+ for (const KeyParameter& tag : authSet) {
+ builder.push_back(tag);
+ }
+ AuthorizationSet params = createAuthorizationSet(mFdp);
+ authSet.push_back(params);
+ } break;
+ case 7: { // invoke copy constructor
+ auto params = AuthorizationSetBuilder().Authorizations(authSet);
+ authSet = params;
+ } break;
+ case 8: { // invoke move constructor
+ auto params = AuthorizationSetBuilder().Authorizations(authSet);
+ authSet = std::move(params);
+ } break;
+ case 9: { // invoke Constructor from hidl_vec<KeyParameter>
+ hidl_vec<KeyParameter> keyParam;
+ size_t numKeyParam = mFdp->ConsumeIntegralInRange<size_t>(1, kMaxKeyParameter);
+ keyParam.resize(numKeyParam);
+ for (size_t i = 0; i < numKeyParam - 1; ++i) {
+ keyParam[i].tag = mFdp->PickValueInArray(kTagArray);
+ std::vector<uint8_t> dataVector = mFdp->ConsumeBytes<uint8_t>(
+ mFdp->ConsumeIntegralInRange<size_t>(0, kMaxVectorSize));
+ keyParam[i].blob = dataVector;
+ }
+ if (mFdp->ConsumeBool()) {
+ AuthorizationSet auths(keyParam);
+ auths.push_back(AuthorizationSet(keyParam));
+ } else { // invoke operator=
+ AuthorizationSet auths = keyParam;
+ }
+ } break;
+ case 10: { // invoke 'Contains()'
+ Tag tag;
+ if (authSet.size() > 0) {
+ tag = authSet[mFdp->ConsumeIntegralInRange<size_t>(0, authSet.size() - 1)].tag;
+ }
+ authSet.Contains(mFdp->ConsumeBool() ? tag : mFdp->PickValueInArray(kTagArray));
+ } break;
+ case 11: { // invoke 'GetTagCount()'
+ Tag tag;
+ if (authSet.size() > 0) {
+ tag = authSet[mFdp->ConsumeIntegralInRange<size_t>(0, authSet.size() - 1)].tag;
+ }
+ authSet.GetTagCount(mFdp->ConsumeBool() ? tag : mFdp->PickValueInArray(kTagArray));
+ } break;
+ case 12: { // invoke 'empty()'
+ authSet.empty();
+ } break;
+ case 13: { // invoke 'data()'
+ authSet.data();
+ } break;
+ case 14: { // invoke 'hidl_data()'
+ authSet.hidl_data();
+ } break;
+ case 15: { // invoke 'erase()'
+ if (authSet.size() > 0) {
+ authSet.erase(mFdp->ConsumeIntegralInRange<size_t>(0, authSet.size() - 1));
+ }
+ } break;
+ default:
+ break;
+ };
+ }
+ authSet.Clear();
+}
+
+void KeyMaster4AuthSetFuzzer::process(const uint8_t* data, size_t size) {
+ mFdp = std::make_unique<FuzzedDataProvider>(data, size);
+ invokeAuthSetAPIs();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ KeyMaster4AuthSetFuzzer km4AuthSetFuzzer;
+ km4AuthSetFuzzer.process(data, size);
+ return 0;
+}
+
+} // namespace android::hardware::keymaster::V4_0::fuzzer
diff --git a/keymaster/4.0/support/fuzzer/keymaster4_common.h b/keymaster/4.0/support/fuzzer/keymaster4_common.h
new file mode 100644
index 0000000..f6e53ee
--- /dev/null
+++ b/keymaster/4.0/support/fuzzer/keymaster4_common.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2021 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.
+ *
+ */
+#ifndef __KEYMASTER4_COMMON_H__
+#define __KEYMASTER4_COMMON_H__
+
+#include <fuzzer/FuzzedDataProvider.h>
+#include <keymasterV4_0/authorization_set.h>
+
+namespace android::hardware::keymaster::V4_0::fuzzer {
+
+using ::android::hardware::hidl_vec;
+
+constexpr uint32_t kKeySize = 2048;
+constexpr uint32_t kPublicExponent = 65537;
+
+constexpr EcCurve kCurve[] = {EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521};
+
+constexpr PaddingMode kPaddingMode[] = {
+ PaddingMode::NONE,
+ PaddingMode::RSA_OAEP,
+ PaddingMode::RSA_PSS,
+ PaddingMode::RSA_PKCS1_1_5_ENCRYPT,
+ PaddingMode::RSA_PKCS1_1_5_SIGN,
+ PaddingMode::PKCS7,
+};
+
+constexpr Digest kDigest[] = {
+ Digest::NONE, Digest::MD5, Digest::SHA1, Digest::SHA_2_224,
+ Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512,
+};
+
+enum AuthSet : uint32_t {
+ RSA_SIGNING_KEY = 0u,
+ RSA_ENCRYPRION_KEY,
+ ECDSA_SIGNING_CURVE,
+ ECDSA_SIGNING_KEY,
+ AES_ENCRYPTION_KEY,
+ TRIPLE_DES,
+ HMAC,
+ NO_DIGEST,
+ ECB_MODE,
+ GSM_MODE_MIN_MAC,
+ GSM_MODE_MAC,
+ BLOCK_MODE,
+ kMaxValue = BLOCK_MODE
+};
+
+AuthorizationSet createAuthorizationSet(std::unique_ptr<FuzzedDataProvider>& dataProvider) {
+ uint32_t authSet = dataProvider->ConsumeEnum<AuthSet>();
+ switch (authSet) {
+ case RSA_SIGNING_KEY: {
+ Digest digest = dataProvider->PickValueInArray(kDigest);
+ PaddingMode padding = dataProvider->PickValueInArray(kPaddingMode);
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(kKeySize, kPublicExponent)
+ .Digest(digest)
+ .Padding(padding)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID);
+ } break;
+ case RSA_ENCRYPRION_KEY: {
+ Digest digest = dataProvider->PickValueInArray(kDigest);
+ PaddingMode padding = dataProvider->PickValueInArray(kPaddingMode);
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(kKeySize, kPublicExponent)
+ .Digest(digest)
+ .Padding(padding)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID);
+ } break;
+ case ECDSA_SIGNING_CURVE: {
+ EcCurve ecCurve = dataProvider->PickValueInArray(kCurve);
+ Digest digest = dataProvider->PickValueInArray(kDigest);
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(ecCurve)
+ .Digest(digest)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID);
+ } break;
+ case ECDSA_SIGNING_KEY: {
+ Digest digest = dataProvider->PickValueInArray(kDigest);
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(kKeySize)
+ .Digest(digest)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID);
+ } break;
+ case AES_ENCRYPTION_KEY: {
+ Digest digest = dataProvider->PickValueInArray(kDigest);
+ PaddingMode padding = dataProvider->PickValueInArray(kPaddingMode);
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(kKeySize)
+ .Digest(digest)
+ .Padding(padding)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID);
+ } break;
+ case TRIPLE_DES: {
+ Digest digest = dataProvider->PickValueInArray(kDigest);
+ PaddingMode padding = dataProvider->PickValueInArray(kPaddingMode);
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .TripleDesEncryptionKey(kKeySize)
+ .Digest(digest)
+ .Padding(padding)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID);
+ } break;
+ case HMAC: {
+ Digest digest = dataProvider->PickValueInArray(kDigest);
+ PaddingMode padding = dataProvider->PickValueInArray(kPaddingMode);
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .HmacKey(kKeySize)
+ .Digest(digest)
+ .Padding(padding)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID);
+ } break;
+ case NO_DIGEST: {
+ Digest digest = dataProvider->PickValueInArray(kDigest);
+ PaddingMode padding = dataProvider->PickValueInArray(kPaddingMode);
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .NoDigestOrPadding()
+ .Digest(digest)
+ .Padding(padding)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID);
+ } break;
+ case ECB_MODE: {
+ Digest digest = dataProvider->PickValueInArray(kDigest);
+ PaddingMode padding = dataProvider->PickValueInArray(kPaddingMode);
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcbMode()
+ .Digest(digest)
+ .Padding(padding)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID);
+ } break;
+ case GSM_MODE_MIN_MAC: {
+ uint32_t minMacLength = dataProvider->ConsumeIntegral<uint32_t>();
+ Digest digest = dataProvider->PickValueInArray(kDigest);
+ PaddingMode padding = dataProvider->PickValueInArray(kPaddingMode);
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .GcmModeMinMacLen(minMacLength)
+ .Digest(digest)
+ .Padding(padding)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID);
+ } break;
+ case GSM_MODE_MAC: {
+ uint32_t macLength = dataProvider->ConsumeIntegral<uint32_t>();
+ Digest digest = dataProvider->PickValueInArray(kDigest);
+ PaddingMode padding = dataProvider->PickValueInArray(kPaddingMode);
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .GcmModeMacLen(macLength)
+ .Digest(digest)
+ .Padding(padding)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID);
+ } break;
+ case BLOCK_MODE: {
+ Digest digest = dataProvider->PickValueInArray(kDigest);
+ PaddingMode padding = dataProvider->PickValueInArray(kPaddingMode);
+ auto blockModes = {
+ BlockMode::ECB,
+ BlockMode::CBC,
+ BlockMode::CTR,
+ BlockMode::GCM,
+ };
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .BlockMode(blockModes)
+ .Digest(digest)
+ .Padding(padding)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID);
+ } break;
+ default:
+ break;
+ };
+ return AuthorizationSetBuilder();
+}
+
+} // namespace android::hardware::keymaster::V4_0::fuzzer
+
+#endif // __KEYMASTER4_COMMON_H__
diff --git a/keymaster/4.0/support/fuzzer/keymaster4_utils_fuzzer.cpp b/keymaster/4.0/support/fuzzer/keymaster4_utils_fuzzer.cpp
new file mode 100644
index 0000000..bf074e8
--- /dev/null
+++ b/keymaster/4.0/support/fuzzer/keymaster4_utils_fuzzer.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2021 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 <hardware/hw_auth_token.h>
+#include <keymasterV4_0/keymaster_utils.h>
+#include "keymaster4_common.h"
+
+namespace android::hardware::keymaster::V4_0::fuzzer {
+
+using android::hardware::keymaster::V4_0::SecurityLevel;
+using android::hardware::keymaster::V4_0::VerificationToken;
+using android::hardware::keymaster::V4_0::support::deserializeVerificationToken;
+using android::hardware::keymaster::V4_0::support::serializeVerificationToken;
+
+constexpr SecurityLevel kSecurityLevel[]{
+ SecurityLevel::SOFTWARE,
+ SecurityLevel::TRUSTED_ENVIRONMENT,
+ SecurityLevel::STRONGBOX,
+};
+constexpr size_t kMaxVectorSize = 100;
+constexpr size_t kMaxCharacters = 100;
+
+class KeyMaster4UtilsFuzzer {
+ public:
+ void process(const uint8_t* data, size_t size);
+
+ private:
+ void invokeKeyMasterUtils();
+ std::unique_ptr<FuzzedDataProvider> mFdp = nullptr;
+};
+
+void KeyMaster4UtilsFuzzer::invokeKeyMasterUtils() {
+ support::getOsVersion();
+ support::getOsPatchlevel();
+
+ VerificationToken token;
+ token.challenge = mFdp->ConsumeIntegral<uint64_t>();
+ token.timestamp = mFdp->ConsumeIntegral<uint64_t>();
+ token.securityLevel = mFdp->PickValueInArray(kSecurityLevel);
+ size_t vectorSize = mFdp->ConsumeIntegralInRange<size_t>(0, kMaxVectorSize);
+ token.mac.resize(vectorSize);
+ for (size_t n = 0; n < vectorSize; ++n) {
+ token.mac[n] = n;
+ }
+ std::optional<std::vector<uint8_t>> serialized = serializeVerificationToken(token);
+ if (serialized.has_value()) {
+ std::optional<VerificationToken> deserialized =
+ deserializeVerificationToken(serialized.value());
+ }
+
+ std::vector<uint8_t> dataVector;
+ size_t size = mFdp->ConsumeIntegralInRange<size_t>(0, sizeof(hw_auth_token_t));
+ dataVector = mFdp->ConsumeBytes<uint8_t>(size);
+ support::blob2hidlVec(dataVector.data(), dataVector.size());
+
+ support::blob2hidlVec(dataVector);
+
+ std::string str = mFdp->ConsumeRandomLengthString(kMaxCharacters);
+ support::blob2hidlVec(str);
+
+ HardwareAuthToken authToken = support::hidlVec2AuthToken(dataVector);
+ hidl_vec<uint8_t> volatile hidlVector = support::authToken2HidlVec(authToken);
+}
+
+void KeyMaster4UtilsFuzzer::process(const uint8_t* data, size_t size) {
+ mFdp = std::make_unique<FuzzedDataProvider>(data, size);
+ invokeKeyMasterUtils();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ KeyMaster4UtilsFuzzer kmUtilsFuzzer;
+ kmUtilsFuzzer.process(data, size);
+ return 0;
+}
+
+} // namespace android::hardware::keymaster::V4_0::fuzzer