From 20bf5e70bc2976177138c480f70880ef2bf6c4a0 Mon Sep 17 00:00:00 2001 From: Ayushi Khopkar Date: Wed, 9 Jun 2021 09:18:45 +0530 Subject: [PATCH] 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 --- keymaster/4.0/support/fuzzer/Android.bp | 67 ++++++ keymaster/4.0/support/fuzzer/README.md | 58 +++++ .../fuzzer/keymaster4_attestation_fuzzer.cpp | 185 ++++++++++++++++ .../fuzzer/keymaster4_authSet_fuzzer.cpp | 202 ++++++++++++++++++ .../4.0/support/fuzzer/keymaster4_common.h | 198 +++++++++++++++++ .../fuzzer/keymaster4_utils_fuzzer.cpp | 89 ++++++++ 6 files changed, 799 insertions(+) create mode 100644 keymaster/4.0/support/fuzzer/Android.bp create mode 100644 keymaster/4.0/support/fuzzer/README.md create mode 100644 keymaster/4.0/support/fuzzer/keymaster4_attestation_fuzzer.cpp create mode 100644 keymaster/4.0/support/fuzzer/keymaster4_authSet_fuzzer.cpp create mode 100644 keymaster/4.0/support/fuzzer/keymaster4_common.h create mode 100644 keymaster/4.0/support/fuzzer/keymaster4_utils_fuzzer.cpp diff --git a/keymaster/4.0/support/fuzzer/Android.bp b/keymaster/4.0/support/fuzzer/Android.bp new file mode 100644 index 0000000000..57a2d26802 --- /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 0000000000..bf4af25c87 --- /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 0000000000..b8b858d30e --- /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 +#include +#include +#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* keyBlob, + KeyCharacteristics* keyCharacteristics); + ErrorCode attestKey(hidl_vec& keyBlob, const AuthorizationSet& attestParams, + hidl_vec>* certificateChain); + X509_Ptr parseCertificateBlob(const hidl_vec& blob); + ASN1_OCTET_STRING* getAttestationRecord(const X509* certificate); + bool verifyAttestationRecord(const hidl_vec& attestationCert); + void invokeAttestationRecord(); + + sp mKeymaster = nullptr; + std::unique_ptr mFdp = nullptr; +}; + +ErrorCode KeyMaster4AttestationFuzzer::generateKey(const AuthorizationSet& key_desc, + hidl_vec* keyBlob, + KeyCharacteristics* keyCharacteristics) { + ErrorCode error; + mKeymaster->generateKey(key_desc.hidl_data(), + [&](ErrorCode hidlError, const hidl_vec& hidlKeyBlob, + const KeyCharacteristics& hidlKeyCharacteristics) { + error = hidlError; + *keyBlob = hidlKeyBlob; + *keyCharacteristics = hidlKeyCharacteristics; + }); + return error; +} + +ErrorCode KeyMaster4AttestationFuzzer::attestKey(hidl_vec& keyBlob, + const AuthorizationSet& attestParams, + hidl_vec>* certificateChain) { + ErrorCode error; + auto rc = mKeymaster->attestKey( + keyBlob, attestParams.hidl_data(), + [&](ErrorCode hidlError, const hidl_vec>& hidlCertificateChain) { + error = hidlError; + *certificateChain = hidlCertificateChain; + }); + + if (!rc.isOk()) { + return ErrorCode::UNKNOWN_ERROR; + } + return error; +} + +X509_Ptr KeyMaster4AttestationFuzzer::parseCertificateBlob(const hidl_vec& 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& 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 attestationChallenge; + hidl_vec 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 verifiedBootKey; + keymaster_verified_boot_t verifiedBootState; + bool device_locked; + hidl_vec 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 keyBlob; + KeyCharacteristics keyCharacteristics; + generateKey(createAuthorizationSet(mFdp), &keyBlob, &keyCharacteristics); + + hidl_vec> certificateChain; + + std::vector challenge, attestationId; + challenge = + mFdp->ConsumeBytes(mFdp->ConsumeIntegralInRange(kMinBytes, kMaxBytes)); + attestationId = + mFdp->ConsumeBytes(mFdp->ConsumeIntegralInRange(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( + 0, certificateChain.size() - 1)]); + } +} + +void KeyMaster4AttestationFuzzer::process(const uint8_t* data, size_t size) { + mFdp = std::make_unique(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 0000000000..63e0499336 --- /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 +#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 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(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 + hidl_vec keyParam; + size_t numKeyParam = mFdp->ConsumeIntegralInRange(1, kMaxKeyParameter); + keyParam.resize(numKeyParam); + for (size_t i = 0; i < numKeyParam - 1; ++i) { + keyParam[i].tag = mFdp->PickValueInArray(kTagArray); + std::vector dataVector = mFdp->ConsumeBytes( + mFdp->ConsumeIntegralInRange(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(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(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(0, authSet.size() - 1)); + } + } break; + default: + break; + }; + } + authSet.Clear(); +} + +void KeyMaster4AuthSetFuzzer::process(const uint8_t* data, size_t size) { + mFdp = std::make_unique(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 0000000000..f6e53eec59 --- /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 +#include + +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& dataProvider) { + uint32_t authSet = dataProvider->ConsumeEnum(); + 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(); + 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(); + 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 0000000000..bf074e824c --- /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 +#include +#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 mFdp = nullptr; +}; + +void KeyMaster4UtilsFuzzer::invokeKeyMasterUtils() { + support::getOsVersion(); + support::getOsPatchlevel(); + + VerificationToken token; + token.challenge = mFdp->ConsumeIntegral(); + token.timestamp = mFdp->ConsumeIntegral(); + token.securityLevel = mFdp->PickValueInArray(kSecurityLevel); + size_t vectorSize = mFdp->ConsumeIntegralInRange(0, kMaxVectorSize); + token.mac.resize(vectorSize); + for (size_t n = 0; n < vectorSize; ++n) { + token.mac[n] = n; + } + std::optional> serialized = serializeVerificationToken(token); + if (serialized.has_value()) { + std::optional deserialized = + deserializeVerificationToken(serialized.value()); + } + + std::vector dataVector; + size_t size = mFdp->ConsumeIntegralInRange(0, sizeof(hw_auth_token_t)); + dataVector = mFdp->ConsumeBytes(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 volatile hidlVector = support::authToken2HidlVec(authToken); +} + +void KeyMaster4UtilsFuzzer::process(const uint8_t* data, size_t size) { + mFdp = std::make_unique(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