/* * 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 #include #include #include namespace android::hardware::security::keymint_support::fuzzer { using namespace android; using AStatus = ::ndk::ScopedAStatus; std::shared_ptr gKeyMint = nullptr; constexpr size_t kMaxBytes = 256; const std::string kServiceName = "android.hardware.security.keymint.IKeyMintDevice/default"; class KeyMintAttestationFuzzer { public: KeyMintAttestationFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){}; void process(); private: KeyCreationResult generateKey(const AuthorizationSet& keyDesc, const std::optional& attestKey, vector* keyBlob, vector* keyCharacteristics, vector* certChain); X509_Ptr parseCertificateBlob(const vector& blob); ASN1_OCTET_STRING* getAttestationRecord(const X509* certificate); bool verifyAttestationRecord(const vector& attestationCert); FuzzedDataProvider mFdp; }; KeyCreationResult KeyMintAttestationFuzzer::generateKey( const AuthorizationSet& keyDesc, const std::optional& attestKey, vector* keyBlob, vector* keyCharacteristics, vector* certChain) { KeyCreationResult creationResult; AStatus result = gKeyMint->generateKey(keyDesc.vector_data(), attestKey, &creationResult); if (result.isOk() && creationResult.keyBlob.size() > 0) { *keyBlob = std::move(creationResult.keyBlob); *keyCharacteristics = std::move(creationResult.keyCharacteristics); *certChain = std::move(creationResult.certificateChain); } return creationResult; } X509_Ptr KeyMintAttestationFuzzer::parseCertificateBlob(const vector& blob) { const uint8_t* data = blob.data(); return X509_Ptr(d2i_X509(nullptr, &data, blob.size())); } ASN1_OCTET_STRING* KeyMintAttestationFuzzer::getAttestationRecord(const X509* certificate) { ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */)); if (!oid.get()) { return nullptr; } int32_t 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 KeyMintAttestationFuzzer::verifyAttestationRecord(const vector& 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; SecurityLevel attestationSecurityLevel; SecurityLevel keymintSecurityLevel; vector attestationChallenge; vector attestationUniqueId; uint32_t attestationVersion; uint32_t keymintVersion; auto error = parse_attestation_record(attestRecord->data, attestRecord->length, &attestationVersion, &attestationSecurityLevel, &keymintVersion, &keymintSecurityLevel, &attestationChallenge, &attestationSwEnforced, &attestationHwEnforced, &attestationUniqueId); if (error != ErrorCode::OK) { return false; } VerifiedBoot verifiedBootState; vector verifiedBootKey; vector verifiedBootHash; bool device_locked; error = parse_root_of_trust(attestRecord->data, attestRecord->length, &verifiedBootKey, &verifiedBootState, &device_locked, &verifiedBootHash); if (error != ErrorCode::OK) { return false; } return true; } void KeyMintAttestationFuzzer::process() { AttestationKey attestKey; vector attestKeyCertChain; vector attestKeyCharacteristics; generateKey(createAuthSetForAttestKey(&mFdp), {}, &attestKey.keyBlob, &attestKeyCharacteristics, &attestKeyCertChain); vector attestedKeyCertChain; vector attestedKeyCharacteristics; vector attestedKeyBlob; attestKey.issuerSubjectName = mFdp.ConsumeBytes(kMaxBytes); generateKey(createAuthorizationSet(&mFdp), attestKey, &attestedKeyBlob, &attestedKeyCharacteristics, &attestedKeyCertChain); if (attestedKeyCertChain.size() > 0) { size_t leafCert = attestedKeyCertChain.size() - 1; verifyAttestationRecord(attestedKeyCertChain[leafCert].encodedCertificate); } } extern "C" int LLVMFuzzerInitialize(int /* *argc */, char /* ***argv */) { ::ndk::SpAIBinder binder(AServiceManager_waitForService(kServiceName.c_str())); gKeyMint = std::move(IKeyMintDevice::fromBinder(binder)); LOG_ALWAYS_FATAL_IF(!gKeyMint, "Failed to get IKeyMintDevice instance."); return 0; } extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { KeyMintAttestationFuzzer kmAttestationFuzzer(data, size); kmAttestationFuzzer.process(); return 0; } } // namespace android::hardware::security::keymint_support::fuzzer