Merge "Added fuzzers for libkeymaster4support" am: 03c30ca9a8
Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/1729193 Change-Id: Iecd2b69c3cbf5a21cadbd9768b27f5df24786d48
This commit is contained in:
commit
52607dea82
6 changed files with 799 additions and 0 deletions
67
keymaster/4.0/support/fuzzer/Android.bp
Normal file
67
keymaster/4.0/support/fuzzer/Android.bp
Normal file
|
@ -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",
|
||||
],
|
||||
}
|
58
keymaster/4.0/support/fuzzer/README.md
Normal file
58
keymaster/4.0/support/fuzzer/README.md
Normal file
|
@ -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
|
185
keymaster/4.0/support/fuzzer/keymaster4_attestation_fuzzer.cpp
Normal file
185
keymaster/4.0/support/fuzzer/keymaster4_attestation_fuzzer.cpp
Normal file
|
@ -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
|
202
keymaster/4.0/support/fuzzer/keymaster4_authSet_fuzzer.cpp
Normal file
202
keymaster/4.0/support/fuzzer/keymaster4_authSet_fuzzer.cpp
Normal file
|
@ -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
|
198
keymaster/4.0/support/fuzzer/keymaster4_common.h
Normal file
198
keymaster/4.0/support/fuzzer/keymaster4_common.h
Normal file
|
@ -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__
|
89
keymaster/4.0/support/fuzzer/keymaster4_utils_fuzzer.cpp
Normal file
89
keymaster/4.0/support/fuzzer/keymaster4_utils_fuzzer.cpp
Normal file
|
@ -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
|
Loading…
Reference in a new issue