diff --git a/security/keymint/support/fuzzer/Android.bp b/security/keymint/support/fuzzer/Android.bp index 1b1a580955..5b1bdb2d38 100644 --- a/security/keymint/support/fuzzer/Android.bp +++ b/security/keymint/support/fuzzer/Android.bp @@ -48,6 +48,20 @@ cc_defaults { ], } +cc_defaults { + name: "keymint_remote_fuzzer_defaults", + static_libs: [ + "libkeymint_remote_prov_support", + "android.hardware.security.rkp-V3-ndk", + ], + shared_libs: [ + "libcppbor", + "libcppcose_rkp", + "libjsoncpp", + "libkeymaster_portable", + ], +} + cc_fuzz { name: "keymint_attestation_fuzzer", srcs: [ @@ -67,3 +81,14 @@ cc_fuzz { "keymint_fuzzer_defaults", ], } + +cc_fuzz { + name: "keymint_remote_prov_fuzzer", + srcs: [ + "keymint_remote_prov_fuzzer.cpp", + ], + defaults: [ + "keymint_fuzzer_defaults", + "keymint_remote_fuzzer_defaults", + ], +} diff --git a/security/keymint/support/fuzzer/README.md b/security/keymint/support/fuzzer/README.md index d41af0862b..13d3f340ed 100644 --- a/security/keymint/support/fuzzer/README.md +++ b/security/keymint/support/fuzzer/README.md @@ -12,6 +12,7 @@ The plugins feed the entire input data to the module. This ensures that the plug ## Table of contents + [keymint_attestation_fuzzer](#KeyMintAttestation) + [keymint_authSet_fuzzer](#KeyMintAuthSet) ++ [keymint_remote_prov_fuzzer](#KeyMintRemoteProv) # Fuzzer for KeyMintAttestation KeyMintAttestation supports the following parameters: @@ -77,3 +78,26 @@ $ mm -j$(nproc) keymint_authSet_fuzzer $ adb sync data $ adb shell /data/fuzz/arm64/keymint_authSet_fuzzer/keymint_authSet_fuzzer ``` + +# Fuzzer for KeyMintRemoteProv +KeyMintRemoteProv supports the following parameters: +1. ChallengeSize(parameter name: "challengeSize") +2. Challenge(parameter name: "challenge") +3. NumKeys(parameter name: "numKeys") + +| Parameter| Valid Values| Configured Value| +|------------- |--------------| -------------------- | +|`challengeSize`| `uint8_t` |Value obtained from FuzzedDataProvider| +|`challenge`| `std::vector` |Value obtained from FuzzedDataProvider| +|`numKeys`| `uint8_t` |Value obtained from FuzzedDataProvider| + +#### Steps to run +1. Build the fuzzer +``` +$ mm -j$(nproc) keymint_remote_prov_fuzzer +``` +2. Run on device +``` +$ adb sync data +$ adb shell /data/fuzz/arm64/keymint_remote_prov_fuzzer/keymint_remote_prov_fuzzer +``` diff --git a/security/keymint/support/fuzzer/keymint_remote_prov_fuzzer.cpp b/security/keymint/support/fuzzer/keymint_remote_prov_fuzzer.cpp new file mode 100644 index 0000000000..6bd986c28d --- /dev/null +++ b/security/keymint/support/fuzzer/keymint_remote_prov_fuzzer.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2024 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 + +namespace android::hardware::security::keymint_support::fuzzer { + +using namespace cppcose; +using namespace aidl::android::hardware::security::keymint; +using namespace aidl::android::hardware::security::keymint::remote_prov; + +constexpr size_t kMinSize = 0; +constexpr size_t kSupportedNumKeys = 4; +constexpr size_t kChallengeSize = 64; +constexpr size_t kMaxBytes = 128; +const std::string kServiceName = + "android.hardware.security.keymint.IRemotelyProvisionedComponent/default"; + +std::shared_ptr gRPC = nullptr; + +class KeyMintRemoteProv { + public: + KeyMintRemoteProv(const uint8_t* data, size_t size) : mFdp(data, size){}; + void process(); + + private: + std::vector ExtractPayloadValue(const MacedPublicKey& macedPubKey); + FuzzedDataProvider mFdp; +}; + +std::vector KeyMintRemoteProv::ExtractPayloadValue(const MacedPublicKey& macedPubKey) { + std::vector payloadValue; + + auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey); + if (coseMac0) { + // The payload is a bstr holding an encoded COSE_Key + auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr(); + if (payload != nullptr) { + payloadValue = payload->value(); + } + } + return payloadValue; +} + +void KeyMintRemoteProv::process() { + std::vector keysToSign = std::vector( + mFdp.ConsumeIntegralInRange(kMinSize, kSupportedNumKeys)); + cppbor::Array cborKeysToSign; + for (auto& key : keysToSign) { + // TODO: b/350649166 - Randomize keysToSign + std::vector privateKeyBlob; + gRPC->generateEcdsaP256KeyPair(false /* testMode */, &key, &privateKeyBlob); + + std::vector payloadValue = ExtractPayloadValue(key); + cborKeysToSign.add(cppbor::EncodedItem(payloadValue)); + } + + uint8_t challengeSize = mFdp.ConsumeIntegralInRange(kMinSize, kChallengeSize); + std::vector challenge = mFdp.ConsumeBytes(challengeSize); + + std::vector csr; + gRPC->generateCertificateRequestV2(keysToSign, challenge, &csr); + + while (mFdp.remaining_bytes()) { + auto invokeProvAPI = mFdp.PickValueInArray>({ + [&]() { verifyFactoryCsr(cborKeysToSign, csr, gRPC.get(), challenge); }, + [&]() { verifyProductionCsr(cborKeysToSign, csr, gRPC.get(), challenge); }, + [&]() { isCsrWithProperDiceChain(csr); }, + }); + invokeProvAPI(); + } +} + +extern "C" int LLVMFuzzerInitialize(int /* *argc */, char /* ***argv */) { + ::ndk::SpAIBinder binder(AServiceManager_waitForService(kServiceName.c_str())); + gRPC = IRemotelyProvisionedComponent::fromBinder(binder); + LOG_ALWAYS_FATAL_IF(!gRPC, "Failed to get IRemotelyProvisionedComponent instance."); + return 0; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + KeyMintRemoteProv kmRemoteProv(data, size); + kmRemoteProv.process(); + return 0; +} + +} // namespace android::hardware::security::keymint_support::fuzzer