Merge "Added TD-SCDMA bands for network scanning"
diff --git a/current.txt b/current.txt
index f7c9b45..09759b9 100644
--- a/current.txt
+++ b/current.txt
@@ -651,10 +651,10 @@
df9c79c4fdde2821550c6d5c3d07f5ec0adfb1b702561ce543c906ddef698703 android.hardware.media.c2@1.1::IComponent
a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardware.media.c2@1.1::IComponentStore
4b5c8546533db9412fec6d32c0ef42b22e5e68dbf390c775ec3c22bb2d501102 android.hardware.neuralnetworks@1.3::IBuffer
-234cc547d63d2f24a447aee0a9a76cab68b31c080adadc5a960598b827a69fa2 android.hardware.neuralnetworks@1.3::IDevice
+5a6b75f13f0e010a4268defa4f627b862ab2899fb04f9d985194a25bd8f9fe0d android.hardware.neuralnetworks@1.3::IDevice
058b48f0e2e725bb2b3fa2b7917b0f0a696383d03a4c57afe26f0eadb6a7af28 android.hardware.neuralnetworks@1.3::IPreparedModel
94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback
-2576ba54711218ce0d7f207baa533fca9af3c630756938ede6e73fe197b7ea38 android.hardware.neuralnetworks@1.3::types
+12c51f9d04a52324510419aeee3e37bb3607e6900556cdde79774d80ed989855 android.hardware.neuralnetworks@1.3::types
3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi
c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd
11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types
diff --git a/keymaster/4.0/support/Android.bp b/keymaster/4.0/support/Android.bp
index 2f40282..9c5fbab 100644
--- a/keymaster/4.0/support/Android.bp
+++ b/keymaster/4.0/support/Android.bp
@@ -27,11 +27,10 @@
"authorization_set.cpp",
"key_param_output.cpp",
"keymaster_utils.cpp",
- "Keymaster.cpp",
- "Keymaster3.cpp",
- "Keymaster4.cpp",
],
- export_include_dirs: ["include"],
+ export_include_dirs: [
+ "include",
+ ],
shared_libs: [
"android.hardware.keymaster@3.0",
"android.hardware.keymaster@4.0",
@@ -39,6 +38,5 @@
"libcrypto",
"libhardware",
"libhidlbase",
- "libutils",
- ]
+ ],
}
diff --git a/keymaster/4.0/support/Keymaster4.cpp b/keymaster/4.0/support/Keymaster4.cpp
deleted file mode 100644
index cc3d656..0000000
--- a/keymaster/4.0/support/Keymaster4.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
-**
-** Copyright 2017, 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 <keymasterV4_0/Keymaster4.h>
-
-#include <android-base/logging.h>
-
-namespace android {
-namespace hardware {
-namespace keymaster {
-namespace V4_0 {
-namespace support {
-
-void Keymaster4::getVersionIfNeeded() {
- if (haveVersion_) return;
-
- auto rc =
- dev_->getHardwareInfo([&](SecurityLevel securityLevel, const hidl_string& keymasterName,
- const hidl_string& authorName) {
- version_ = {keymasterName, authorName, 4 /* major version */, securityLevel,
- true /* supportsEc */};
- haveVersion_ = true;
- });
-
- CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware info";
-}
-
-} // namespace support
-} // namespace V4_0
-} // namespace keymaster
-} // namespace hardware
-} // namespace android
diff --git a/keymaster/4.0/support/OWNERS b/keymaster/4.0/support/OWNERS
index 335660d..a9efe66 100644
--- a/keymaster/4.0/support/OWNERS
+++ b/keymaster/4.0/support/OWNERS
@@ -1,2 +1,3 @@
jdanis@google.com
swillden@google.com
+jbires@google.com
diff --git a/keymaster/4.0/support/attestation_record.cpp b/keymaster/4.0/support/attestation_record.cpp
index 000d46e..27e00c1 100644
--- a/keymaster/4.0/support/attestation_record.cpp
+++ b/keymaster/4.0/support/attestation_record.cpp
@@ -321,19 +321,20 @@
LOG(ERROR) << AT << "Failed record parsing";
return ErrorCode::UNKNOWN_ERROR;
}
- if (!record->tee_enforced) {
- LOG(ERROR) << AT << "Failed hardware characteristic parsing";
+
+ KM_ROOT_OF_TRUST* root_of_trust = nullptr;
+ if (record->tee_enforced && record->tee_enforced->root_of_trust) {
+ root_of_trust = record->tee_enforced->root_of_trust;
+ } else if (record->software_enforced && record->software_enforced->root_of_trust) {
+ root_of_trust = record->software_enforced->root_of_trust;
+ } else {
+ LOG(ERROR) << AT << " Failed root of trust parsing";
return ErrorCode::INVALID_ARGUMENT;
}
- if (!record->tee_enforced->root_of_trust) {
- LOG(ERROR) << AT << "Failed root of trust parsing";
+ if (!root_of_trust->verified_boot_key) {
+ LOG(ERROR) << AT << " Failed verified boot key parsing";
return ErrorCode::INVALID_ARGUMENT;
}
- if (!record->tee_enforced->root_of_trust->verified_boot_key) {
- LOG(ERROR) << AT << "Failed verified boot key parsing";
- return ErrorCode::INVALID_ARGUMENT;
- }
- KM_ROOT_OF_TRUST* root_of_trust = record->tee_enforced->root_of_trust;
auto& vb_key = root_of_trust->verified_boot_key;
verified_boot_key->resize(vb_key->length);
@@ -342,19 +343,19 @@
*verified_boot_state = static_cast<keymaster_verified_boot_t>(
ASN1_ENUMERATED_get(root_of_trust->verified_boot_state));
if (!verified_boot_state) {
- LOG(ERROR) << AT << "Failed verified boot state parsing";
+ LOG(ERROR) << AT << " Failed verified boot state parsing";
return ErrorCode::INVALID_ARGUMENT;
}
*device_locked = root_of_trust->device_locked;
if (!device_locked) {
- LOG(ERROR) << AT << "Failed device locked parsing";
+ LOG(ERROR) << AT << " Failed device locked parsing";
return ErrorCode::INVALID_ARGUMENT;
}
auto& vb_hash = root_of_trust->verified_boot_hash;
if (!vb_hash) {
- LOG(ERROR) << AT << "Failed verified boot hash parsing";
+ LOG(ERROR) << AT << " Failed verified boot hash parsing";
return ErrorCode::INVALID_ARGUMENT;
}
verified_boot_hash->resize(vb_hash->length);
diff --git a/keymaster/4.0/support/authorization_set.cpp b/keymaster/4.0/support/authorization_set.cpp
index d6b50f5..a024ff9 100644
--- a/keymaster/4.0/support/authorization_set.cpp
+++ b/keymaster/4.0/support/authorization_set.cpp
@@ -25,7 +25,7 @@
namespace keymaster {
namespace V4_0 {
-inline bool keyParamLess(const KeyParameter& a, const KeyParameter& b) {
+bool keyParamLess(const KeyParameter& a, const KeyParameter& b) {
if (a.tag != b.tag) return a.tag < b.tag;
int retval;
switch (typeFromTag(a.tag)) {
@@ -58,7 +58,7 @@
return false;
}
-inline bool keyParamEqual(const KeyParameter& a, const KeyParameter& b) {
+bool keyParamEqual(const KeyParameter& a, const KeyParameter& b) {
if (a.tag != b.tag) return false;
switch (typeFromTag(a.tag)) {
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h
deleted file mode 100644
index dfd03ef..0000000
--- a/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- **
- ** Copyright 2017, 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 HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_4_H_
-#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_4_H_
-
-#include "Keymaster.h"
-
-namespace android {
-namespace hardware {
-namespace keymaster {
-namespace V4_0 {
-namespace support {
-
-using android::sp;
-using IKeymaster4Device = ::android::hardware::keymaster::V4_0::IKeymasterDevice;
-
-class Keymaster4 : public Keymaster {
- public:
- using WrappedIKeymasterDevice = IKeymaster4Device;
- Keymaster4(sp<IKeymasterDevice> km4_dev, const hidl_string& instanceName)
- : Keymaster(IKeymaster4Device::descriptor, instanceName),
- haveVersion_(false),
- dev_(km4_dev) {}
-
- const VersionResult& halVersion() const override {
- const_cast<Keymaster4*>(this)->getVersionIfNeeded();
- return version_;
- }
-
- Return<void> getHardwareInfo(getHardwareInfo_cb _hidl_cb) override {
- return dev_->getHardwareInfo(_hidl_cb);
- }
-
- Return<void> getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) override {
- return dev_->getHmacSharingParameters(_hidl_cb);
- }
-
- Return<void> computeSharedHmac(const hidl_vec<HmacSharingParameters>& params,
- computeSharedHmac_cb _hidl_cb) override {
- return dev_->computeSharedHmac(params, _hidl_cb);
- }
-
- Return<void> verifyAuthorization(uint64_t operationHandle, const hidl_vec<KeyParameter>& params,
- const HardwareAuthToken& authToken,
- verifyAuthorization_cb _hidl_cb) override {
- return dev_->verifyAuthorization(operationHandle, params, authToken, _hidl_cb);
- }
-
- Return<ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override {
- return dev_->addRngEntropy(data);
- }
-
- Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
- generateKey_cb _hidl_cb) override {
- return dev_->generateKey(keyParams, _hidl_cb);
- }
-
- Return<void> getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
- const hidl_vec<uint8_t>& clientId,
- const hidl_vec<uint8_t>& appData,
- getKeyCharacteristics_cb _hidl_cb) override {
- return dev_->getKeyCharacteristics(keyBlob, clientId, appData, _hidl_cb);
- }
-
- Return<void> importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
- const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) override {
- return dev_->importKey(params, keyFormat, keyData, _hidl_cb);
- }
-
- Return<void> importWrappedKey(const hidl_vec<uint8_t>& wrappedKeyData,
- const hidl_vec<uint8_t>& wrappingKeyBlob,
- const hidl_vec<uint8_t>& maskingKey,
- const hidl_vec<KeyParameter>& unwrappingParams,
- uint64_t passwordSid, uint64_t biometricSid,
- importWrappedKey_cb _hidl_cb) {
- return dev_->importWrappedKey(wrappedKeyData, wrappingKeyBlob, maskingKey, unwrappingParams,
- passwordSid, biometricSid, _hidl_cb);
- }
-
- Return<void> exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
- const hidl_vec<uint8_t>& clientId, const hidl_vec<uint8_t>& appData,
- exportKey_cb _hidl_cb) override {
- return dev_->exportKey(exportFormat, keyBlob, clientId, appData, _hidl_cb);
- }
-
- Return<void> attestKey(const hidl_vec<uint8_t>& keyToAttest,
- const hidl_vec<KeyParameter>& attestParams,
- attestKey_cb _hidl_cb) override {
- return dev_->attestKey(keyToAttest, attestParams, _hidl_cb);
- }
-
- Return<void> upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
- const hidl_vec<KeyParameter>& upgradeParams,
- upgradeKey_cb _hidl_cb) override {
- return dev_->upgradeKey(keyBlobToUpgrade, upgradeParams, _hidl_cb);
- }
-
- Return<ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override {
- return dev_->deleteKey(keyBlob);
- }
-
- Return<ErrorCode> deleteAllKeys() override { return dev_->deleteAllKeys(); }
-
- Return<ErrorCode> destroyAttestationIds() override { return dev_->destroyAttestationIds(); }
-
- Return<void> begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
- const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
- begin_cb _hidl_cb) override {
- return dev_->begin(purpose, key, inParams, authToken, _hidl_cb);
- }
-
- Return<void> update(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
- const hidl_vec<uint8_t>& input, const HardwareAuthToken& authToken,
- const VerificationToken& verificationToken, update_cb _hidl_cb) override {
- return dev_->update(operationHandle, inParams, input, authToken, verificationToken,
- _hidl_cb);
- }
-
- Return<void> finish(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
- const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
- const HardwareAuthToken& authToken,
- const VerificationToken& verificationToken, finish_cb _hidl_cb) override {
- return dev_->finish(operationHandle, inParams, input, signature, authToken,
- verificationToken, _hidl_cb);
- }
-
- Return<ErrorCode> abort(uint64_t operationHandle) override {
- return dev_->abort(operationHandle);
- }
-
- private:
- void getVersionIfNeeded();
-
- bool haveVersion_;
- VersionResult version_;
- sp<IKeymaster4Device> dev_;
-};
-
-} // namespace support
-} // namespace V4_0
-} // namespace keymaster
-} // namespace hardware
-} // namespace android
-
-#endif // HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_4_H_
diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
index cb29c64..bc7f311 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
@@ -355,95 +355,61 @@
return accessTagValue(ttag, param);
}
+inline bool operator<(const KeyParameter& a, const KeyParameter& b) {
+ if (a.tag != b.tag) return a.tag < b.tag;
+ int retval;
+ switch (typeFromTag(a.tag)) {
+ case TagType::INVALID:
+ case TagType::BOOL:
+ return false;
+ case TagType::ENUM:
+ case TagType::ENUM_REP:
+ case TagType::UINT:
+ case TagType::UINT_REP:
+ return a.f.integer < b.f.integer;
+ case TagType::ULONG:
+ case TagType::ULONG_REP:
+ return a.f.longInteger < b.f.longInteger;
+ case TagType::DATE:
+ return a.f.dateTime < b.f.dateTime;
+ case TagType::BIGNUM:
+ case TagType::BYTES:
+ // Handle the empty cases.
+ if (a.blob.size() == 0) return b.blob.size() != 0;
+ if (b.blob.size() == 0) return false;
+
+ retval = memcmp(&a.blob[0], &b.blob[0], std::min(a.blob.size(), b.blob.size()));
+ // if one is the prefix of the other the longer wins
+ if (retval == 0) return a.blob.size() < b.blob.size();
+ // Otherwise a is less if a is less.
+ else
+ return retval < 0;
+ }
+ return false;
+}
+
inline bool operator==(const KeyParameter& a, const KeyParameter& b) {
- if (a.tag != b.tag) {
- return false;
- }
+ if (a.tag != b.tag) return false;
- switch (a.tag) {
- /* Boolean tags */
- case Tag::INVALID:
- case Tag::CALLER_NONCE:
- case Tag::INCLUDE_UNIQUE_ID:
- case Tag::BOOTLOADER_ONLY:
- case Tag::NO_AUTH_REQUIRED:
- case Tag::ALLOW_WHILE_ON_BODY:
- case Tag::UNLOCKED_DEVICE_REQUIRED:
- case Tag::ROLLBACK_RESISTANCE:
- case Tag::RESET_SINCE_ID_ROTATION:
- case Tag::TRUSTED_CONFIRMATION_REQUIRED:
- case Tag::TRUSTED_USER_PRESENCE_REQUIRED:
+ switch (typeFromTag(a.tag)) {
+ case TagType::INVALID:
+ case TagType::BOOL:
return true;
-
- /* Integer tags */
- case Tag::KEY_SIZE:
- case Tag::MIN_MAC_LENGTH:
- case Tag::MIN_SECONDS_BETWEEN_OPS:
- case Tag::MAX_USES_PER_BOOT:
- case Tag::OS_VERSION:
- case Tag::OS_PATCHLEVEL:
- case Tag::MAC_LENGTH:
- case Tag::USER_ID:
- case Tag::AUTH_TIMEOUT:
- case Tag::VENDOR_PATCHLEVEL:
- case Tag::BOOT_PATCHLEVEL:
+ case TagType::ENUM:
+ case TagType::ENUM_REP:
+ case TagType::UINT:
+ case TagType::UINT_REP:
return a.f.integer == b.f.integer;
-
- /* Long integer tags */
- case Tag::RSA_PUBLIC_EXPONENT:
- case Tag::USER_SECURE_ID:
+ case TagType::ULONG:
+ case TagType::ULONG_REP:
return a.f.longInteger == b.f.longInteger;
-
- /* Date-time tags */
- case Tag::ACTIVE_DATETIME:
- case Tag::ORIGINATION_EXPIRE_DATETIME:
- case Tag::USAGE_EXPIRE_DATETIME:
- case Tag::CREATION_DATETIME:
+ case TagType::DATE:
return a.f.dateTime == b.f.dateTime;
-
- /* Bytes tags */
- case Tag::APPLICATION_ID:
- case Tag::APPLICATION_DATA:
- case Tag::ROOT_OF_TRUST:
- case Tag::UNIQUE_ID:
- case Tag::ATTESTATION_CHALLENGE:
- case Tag::ATTESTATION_APPLICATION_ID:
- case Tag::ATTESTATION_ID_BRAND:
- case Tag::ATTESTATION_ID_DEVICE:
- case Tag::ATTESTATION_ID_PRODUCT:
- case Tag::ATTESTATION_ID_SERIAL:
- case Tag::ATTESTATION_ID_IMEI:
- case Tag::ATTESTATION_ID_MEID:
- case Tag::ATTESTATION_ID_MANUFACTURER:
- case Tag::ATTESTATION_ID_MODEL:
- case Tag::ASSOCIATED_DATA:
- case Tag::CONFIRMATION_TOKEN:
- case Tag::NONCE:
- return a.blob == b.blob;
-
- /* Enum tags */
- case Tag::PURPOSE:
- return a.f.purpose == b.f.purpose;
- case Tag::ALGORITHM:
- return a.f.algorithm == b.f.algorithm;
- case Tag::BLOCK_MODE:
- return a.f.blockMode == b.f.blockMode;
- case Tag::DIGEST:
- return a.f.digest == b.f.digest;
- case Tag::PADDING:
- return a.f.paddingMode == b.f.paddingMode;
- case Tag::EC_CURVE:
- return a.f.ecCurve == b.f.ecCurve;
- case Tag::BLOB_USAGE_REQUIREMENTS:
- return a.f.keyBlobUsageRequirements == b.f.keyBlobUsageRequirements;
- case Tag::USER_AUTH_TYPE:
- return a.f.integer == b.f.integer;
- case Tag::ORIGIN:
- return a.f.origin == b.f.origin;
- case Tag::HARDWARE_TYPE:
- return a.f.hardwareType == b.f.hardwareType;
+ case TagType::BIGNUM:
+ case TagType::BYTES:
+ if (a.blob.size() != b.blob.size()) return false;
+ return a.blob.size() == 0 || memcmp(&a.blob[0], &b.blob[0], a.blob.size()) == 0;
}
-
return false;
}
diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
index 5e5ae8d..61645f8 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
@@ -52,6 +52,9 @@
HardwareAuthToken hidlVec2AuthToken(const hidl_vec<uint8_t>& buffer);
hidl_vec<uint8_t> authToken2HidlVec(const HardwareAuthToken& token);
+uint32_t getOsVersion();
+uint32_t getOsPatchlevel();
+
} // namespace support
} // namespace V4_0
} // namespace keymaster
diff --git a/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h b/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h
index cc71dd1..b3869f4 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h
@@ -18,6 +18,8 @@
#define HARDWARE_INTERFACES_KEYMASTER_4_0_SUPPORT_OPENSSL_UTILS_H_
#include <android/hardware/keymaster/4.0/types.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
template <typename T, void (*F)(T*)>
struct UniquePtrDeleter {
diff --git a/keymaster/4.0/support/keymaster_utils.cpp b/keymaster/4.0/support/keymaster_utils.cpp
index e35fdd3..850a776 100644
--- a/keymaster/4.0/support/keymaster_utils.cpp
+++ b/keymaster/4.0/support/keymaster_utils.cpp
@@ -14,11 +14,13 @@
* limitations under the License.
*/
+#include <regex.h>
+
+#include <android-base/properties.h>
#include <hardware/hw_auth_token.h>
#include <keymasterV4_0/keymaster_utils.h>
-namespace android {
-namespace hardware {
+namespace android::hardware {
inline static bool operator<(const hidl_vec<uint8_t>& a, const hidl_vec<uint8_t>& b) {
auto result = memcmp(a.data(), b.data(), std::min(a.size(), b.size()));
@@ -32,8 +34,7 @@
return memcmp(a.data(), b.data(), SIZE) == -1;
}
-namespace keymaster {
-namespace V4_0 {
+namespace keymaster::V4_0 {
bool operator<(const HmacSharingParameters& a, const HmacSharingParameters& b) {
return std::tie(a.seed, a.nonce) < std::tie(b.seed, b.nonce);
@@ -58,9 +59,9 @@
hidl_vec<uint8_t> authToken2HidlVec(const HardwareAuthToken& token) {
static_assert(1 /* version size */ + sizeof(token.challenge) + sizeof(token.userId) +
- sizeof(token.authenticatorId) + sizeof(token.authenticatorType) +
- sizeof(token.timestamp) + kHmacSize ==
- sizeof(hw_auth_token_t),
+ sizeof(token.authenticatorId) + sizeof(token.authenticatorType) +
+ sizeof(token.timestamp) + kHmacSize ==
+ sizeof(hw_auth_token_t),
"HardwareAuthToken content size does not match hw_auth_token_t size");
hidl_vec<uint8_t> result;
@@ -86,9 +87,9 @@
HardwareAuthToken hidlVec2AuthToken(const hidl_vec<uint8_t>& buffer) {
HardwareAuthToken token;
static_assert(1 /* version size */ + sizeof(token.challenge) + sizeof(token.userId) +
- sizeof(token.authenticatorId) + sizeof(token.authenticatorType) +
- sizeof(token.timestamp) + kHmacSize ==
- sizeof(hw_auth_token_t),
+ sizeof(token.authenticatorId) + sizeof(token.authenticatorType) +
+ sizeof(token.timestamp) + kHmacSize ==
+ sizeof(hw_auth_token_t),
"HardwareAuthToken content size does not match hw_auth_token_t size");
if (buffer.size() != sizeof(hw_auth_token_t)) return {};
@@ -100,7 +101,7 @@
pos = copy_bytes_from_iterator(&token.authenticatorId, pos);
pos = copy_bytes_from_iterator(&token.authenticatorType, pos);
token.authenticatorType = static_cast<HardwareAuthenticatorType>(
- ntohl(static_cast<uint32_t>(token.authenticatorType)));
+ ntohl(static_cast<uint32_t>(token.authenticatorType)));
pos = copy_bytes_from_iterator(&token.timestamp, pos);
token.timestamp = ntohq(token.timestamp);
token.mac.resize(kHmacSize);
@@ -109,8 +110,93 @@
return token;
}
+namespace {
+
+constexpr char kPlatformVersionProp[] = "ro.build.version.release";
+constexpr char kPlatformVersionRegex[] = "^([0-9]{1,2})(\\.([0-9]{1,2}))?(\\.([0-9]{1,2}))?";
+constexpr size_t kMajorVersionMatch = 1;
+constexpr size_t kMinorVersionMatch = 3;
+constexpr size_t kSubminorVersionMatch = 5;
+constexpr size_t kPlatformVersionMatchCount = kSubminorVersionMatch + 1;
+
+constexpr char kPlatformPatchlevelProp[] = "ro.build.version.security_patch";
+constexpr char kPlatformPatchlevelRegex[] = "^([0-9]{4})-([0-9]{2})-[0-9]{2}$";
+constexpr size_t kYearMatch = 1;
+constexpr size_t kMonthMatch = 2;
+constexpr size_t kPlatformPatchlevelMatchCount = kMonthMatch + 1;
+
+uint32_t match_to_uint32(const char* expression, const regmatch_t& match) {
+ if (match.rm_so == -1) return 0;
+
+ size_t len = match.rm_eo - match.rm_so;
+ std::string s(expression + match.rm_so, len);
+ return std::stoul(s);
+}
+
+std::string wait_and_get_property(const char* prop) {
+ std::string prop_value;
+ while (!android::base::WaitForPropertyCreation(prop))
+ ;
+ prop_value = android::base::GetProperty(prop, "" /* default */);
+ return prop_value;
+}
+
+} // anonymous namespace
+
+uint32_t getOsVersion(const char* version_str) {
+ regex_t regex;
+ if (regcomp(®ex, kPlatformVersionRegex, REG_EXTENDED)) {
+ return 0;
+ }
+
+ regmatch_t matches[kPlatformVersionMatchCount];
+ int not_match =
+ regexec(®ex, version_str, kPlatformVersionMatchCount, matches, 0 /* flags */);
+ regfree(®ex);
+ if (not_match) {
+ return 0;
+ }
+
+ uint32_t major = match_to_uint32(version_str, matches[kMajorVersionMatch]);
+ uint32_t minor = match_to_uint32(version_str, matches[kMinorVersionMatch]);
+ uint32_t subminor = match_to_uint32(version_str, matches[kSubminorVersionMatch]);
+
+ return (major * 100 + minor) * 100 + subminor;
+}
+
+uint32_t getOsVersion() {
+ std::string version = wait_and_get_property(kPlatformVersionProp);
+ return getOsVersion(version.c_str());
+}
+
+uint32_t getOsPatchlevel(const char* patchlevel_str) {
+ regex_t regex;
+ if (regcomp(®ex, kPlatformPatchlevelRegex, REG_EXTENDED) != 0) {
+ return 0;
+ }
+
+ regmatch_t matches[kPlatformPatchlevelMatchCount];
+ int not_match =
+ regexec(®ex, patchlevel_str, kPlatformPatchlevelMatchCount, matches, 0 /* flags */);
+ regfree(®ex);
+ if (not_match) {
+ return 0;
+ }
+
+ uint32_t year = match_to_uint32(patchlevel_str, matches[kYearMatch]);
+ uint32_t month = match_to_uint32(patchlevel_str, matches[kMonthMatch]);
+
+ if (month < 1 || month > 12) {
+ return 0;
+ }
+ return year * 100 + month;
+}
+
+uint32_t getOsPatchlevel() {
+ std::string patchlevel = wait_and_get_property(kPlatformPatchlevelProp);
+ return getOsPatchlevel(patchlevel.c_str());
+}
+
} // namespace support
-} // namespace V4_0
-} // namespace keymaster
-} // namespace hardware
-} // namespace android
+} // namespace keymaster::V4_0
+} // namespace android::hardware
diff --git a/keymaster/4.0/vts/functional/Android.bp b/keymaster/4.0/vts/functional/Android.bp
index 5649f20..db50080 100644
--- a/keymaster/4.0/vts/functional/Android.bp
+++ b/keymaster/4.0/vts/functional/Android.bp
@@ -19,7 +19,6 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: [
"HmacKeySharingTest.cpp",
- "KeymasterHidlTest.cpp",
"VerificationTokenTest.cpp",
"keymaster_hidl_hal_test.cpp",
],
@@ -27,7 +26,25 @@
"android.hardware.keymaster@4.0",
"libcrypto_static",
"libkeymaster4support",
- "libsoftkeymasterdevice",
+ "libkeymaster4vtstest",
],
- test_suites: ["general-tests", "vts-core"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
+}
+
+cc_test_library {
+ name: "libkeymaster4vtstest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "KeymasterHidlTest.cpp",
+ ],
+ export_include_dirs: [
+ ".",
+ ],
+ static_libs: [
+ "android.hardware.keymaster@4.0",
+ "libkeymaster4support",
+ ],
}
diff --git a/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp b/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
index c228ef7..f57a668 100644
--- a/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
+++ b/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
@@ -28,6 +28,16 @@
*/
class HmacKeySharingTest : public KeymasterHidlTest {
protected:
+ const std::vector<sp<IKeymasterDevice>>& allKeymasters() {
+ if (all_keymasters_.empty()) {
+ auto names = android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor);
+ for (const auto& name : names) {
+ all_keymasters_.push_back(IKeymasterDevice::getService(name));
+ }
+ }
+ return all_keymasters_;
+ }
+
struct GetParamsResult {
ErrorCode error;
HmacSharingParameters params;
@@ -99,8 +109,13 @@
EXPECT_EQ(expected, response.sharing_check) << "Sharing check values should match.";
}
}
+
+ private:
+ static std::vector<sp<IKeymasterDevice>> all_keymasters_;
};
+std::vector<sp<IKeymasterDevice>> HmacKeySharingTest::all_keymasters_;
+
TEST_P(HmacKeySharingTest, GetParameters) {
auto result1 = getHmacSharingParameters(keymaster());
EXPECT_EQ(ErrorCode::OK, result1.error);
@@ -115,26 +130,26 @@
}
TEST_P(HmacKeySharingTest, ComputeSharedHmac) {
- auto params = getHmacSharingParameters(all_keymasters());
- ASSERT_EQ(all_keymasters().size(), params.size())
- << "One or more keymasters failed to provide parameters.";
+ auto params = getHmacSharingParameters(allKeymasters());
+ ASSERT_EQ(allKeymasters().size(), params.size())
+ << "One or more keymasters failed to provide parameters.";
auto nonces = copyNonces(params);
- EXPECT_EQ(all_keymasters().size(), nonces.size());
+ EXPECT_EQ(allKeymasters().size(), nonces.size());
std::sort(nonces.begin(), nonces.end());
std::unique(nonces.begin(), nonces.end());
- EXPECT_EQ(all_keymasters().size(), nonces.size());
+ EXPECT_EQ(allKeymasters().size(), nonces.size());
- auto responses = computeSharedHmac(all_keymasters(), params);
+ auto responses = computeSharedHmac(allKeymasters(), params);
ASSERT_GT(responses.size(), 0U);
verifyResponses(responses[0].sharing_check, responses);
// Do it a second time. Should get the same answers.
- params = getHmacSharingParameters(all_keymasters());
- ASSERT_EQ(all_keymasters().size(), params.size())
- << "One or more keymasters failed to provide parameters.";
+ params = getHmacSharingParameters(allKeymasters());
+ ASSERT_EQ(allKeymasters().size(), params.size())
+ << "One or more keymasters failed to provide parameters.";
- responses = computeSharedHmac(all_keymasters(), params);
+ responses = computeSharedHmac(allKeymasters(), params);
ASSERT_GT(responses.size(), 0U);
ASSERT_EQ(32U, responses[0].sharing_check.size());
verifyResponses(responses[0].sharing_check, responses);
@@ -160,15 +175,16 @@
// sync with respect to the HMAC key. Granted that VTS tests aren't run on in-use production
// devices, this still has the potential to cause confusion. To mitigate that, we always
// (barring crashes :-/) re-run the unmodified agreement process on our way out.
- auto fixup_hmac = finally(
- [&]() { computeSharedHmac(all_keymasters(), getHmacSharingParameters(all_keymasters())); });
+ auto fixup_hmac = finally([&]() {
+ computeSharedHmac(allKeymasters(), getHmacSharingParameters(allKeymasters()));
+ });
- auto params = getHmacSharingParameters(all_keymasters());
- ASSERT_EQ(all_keymasters().size(), params.size())
- << "One or more keymasters failed to provide parameters.";
+ auto params = getHmacSharingParameters(allKeymasters());
+ ASSERT_EQ(allKeymasters().size(), params.size())
+ << "One or more keymasters failed to provide parameters.";
// All should be well in the normal case
- auto responses = computeSharedHmac(all_keymasters(), params);
+ auto responses = computeSharedHmac(allKeymasters(), params);
ASSERT_GT(responses.size(), 0U);
HidlBuf correct_response = responses[0].sharing_check;
@@ -181,7 +197,7 @@
uint8_t bit_to_tweak = rand() % 8;
params[param_to_tweak].nonce[byte_to_tweak] ^= (1 << bit_to_tweak);
- responses = computeSharedHmac(all_keymasters(), params);
+ responses = computeSharedHmac(allKeymasters(), params);
for (size_t i = 0; i < responses.size(); ++i) {
if (i == param_to_tweak) {
EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error)
@@ -199,15 +215,16 @@
// sync with respect to the HMAC key. Granted that VTS tests aren't run on in-use production
// devices, this still has the potential to cause confusion. To mitigate that, we always
// (barring crashes :-/) re-run the unmodified agreement process on our way out.
- auto fixup_hmac = finally(
- [&]() { computeSharedHmac(all_keymasters(), getHmacSharingParameters(all_keymasters())); });
+ auto fixup_hmac = finally([&]() {
+ computeSharedHmac(allKeymasters(), getHmacSharingParameters(allKeymasters()));
+ });
- auto params = getHmacSharingParameters(all_keymasters());
- ASSERT_EQ(all_keymasters().size(), params.size())
- << "One or more keymasters failed to provide parameters.";
+ auto params = getHmacSharingParameters(allKeymasters());
+ ASSERT_EQ(allKeymasters().size(), params.size())
+ << "One or more keymasters failed to provide parameters.";
// All should be well in the normal case
- auto responses = computeSharedHmac(all_keymasters(), params);
+ auto responses = computeSharedHmac(allKeymasters(), params);
ASSERT_GT(responses.size(), 0U);
HidlBuf correct_response = responses[0].sharing_check;
@@ -223,7 +240,7 @@
}
to_tweak[0]++;
- responses = computeSharedHmac(all_keymasters(), params);
+ responses = computeSharedHmac(allKeymasters(), params);
for (size_t i = 0; i < responses.size(); ++i) {
if (i == param_to_tweak) {
EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error)
@@ -236,10 +253,7 @@
}
}
-INSTANTIATE_TEST_SUITE_P(
- PerInstance, HmacKeySharingTest,
- testing::ValuesIn(android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor)),
- android::hardware::PrintInstanceNameToString);
+INSTANTIATE_KEYMASTER_HIDL_TEST(HmacKeySharingTest);
} // namespace test
} // namespace V4_0
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
index 7241984..d0ad433 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
@@ -23,6 +23,7 @@
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <keymasterV4_0/key_param_output.h>
+#include <keymasterV4_0/keymaster_utils.h>
namespace android {
namespace hardware {
@@ -41,39 +42,26 @@
namespace test {
-void KeymasterHidlTest::InitializeKeymaster() {
- service_name_ = GetParam();
- keymaster_ = IKeymasterDevice::getService(service_name_);
- ASSERT_NE(keymaster_, nullptr);
+using namespace std::literals::chrono_literals;
+void KeymasterHidlTest::InitializeKeymaster(sp<IKeymasterDevice> keymaster) {
+ ASSERT_NE(keymaster, nullptr);
+ keymaster_ = keymaster;
ASSERT_TRUE(keymaster_
- ->getHardwareInfo([&](SecurityLevel securityLevel, const hidl_string& name,
- const hidl_string& author) {
- securityLevel_ = securityLevel;
- name_ = name;
- author_ = author;
- })
- .isOk());
+ ->getHardwareInfo([&](SecurityLevel securityLevel, const hidl_string& name,
+ const hidl_string& author) {
+ securityLevel_ = securityLevel;
+ name_ = name;
+ author_ = author;
+ })
+ .isOk());
+
+ os_version_ = support::getOsVersion();
+ os_patch_level_ = support::getOsPatchlevel();
}
void KeymasterHidlTest::SetUp() {
- InitializeKeymaster();
-
- os_version_ = ::keymaster::GetOsVersion();
- os_patch_level_ = ::keymaster::GetOsPatchlevel();
-
- auto service_manager = android::hidl::manager::V1_0::IServiceManager::getService();
- ASSERT_NE(nullptr, service_manager.get());
- all_keymasters_.push_back(keymaster_);
- service_manager->listByInterface(
- IKeymasterDevice::descriptor, [&](const hidl_vec<hidl_string>& names) {
- for (auto& name : names) {
- if (name == service_name_) continue;
- auto keymaster = IKeymasterDevice::getService(name);
- ASSERT_NE(keymaster, nullptr);
- all_keymasters_.push_back(keymaster);
- }
- });
+ InitializeKeymaster(IKeymasterDevice::getService(GetParam()));
}
ErrorCode KeymasterHidlTest::GenerateKey(const AuthorizationSet& key_desc, HidlBuf* key_blob,
@@ -138,7 +126,7 @@
string masking_key,
const AuthorizationSet& unwrapping_params) {
ErrorCode error;
- ImportKey(wrapping_key_desc, KeyFormat::PKCS8, wrapping_key);
+ EXPECT_EQ(ErrorCode::OK, ImportKey(wrapping_key_desc, KeyFormat::PKCS8, wrapping_key));
EXPECT_TRUE(keymaster_
->importWrappedKey(HidlBuf(wrapped_key), key_blob_, HidlBuf(masking_key),
unwrapping_params.hidl_data(), 0 /* passwordSid */,
@@ -207,7 +195,9 @@
HidlBuf empty_buf = {};
EXPECT_EQ(ErrorCode::OK,
GetCharacteristics(key_blob, client_id, app_data, key_characteristics));
- EXPECT_GT(key_characteristics->hardwareEnforced.size(), 0);
+ if (SecLevel() != SecurityLevel::SOFTWARE) {
+ EXPECT_GT(key_characteristics->hardwareEnforced.size(), 0);
+ }
EXPECT_GT(key_characteristics->softwareEnforced.size(), 0);
EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
@@ -647,23 +637,25 @@
switch (algorithm) {
case Algorithm::RSA:
switch (SecLevel()) {
+ case SecurityLevel::SOFTWARE:
case SecurityLevel::TRUSTED_ENVIRONMENT:
return {2048, 3072, 4096};
case SecurityLevel::STRONGBOX:
return {2048};
default:
- CHECK(false) << "Invalid security level " << uint32_t(SecLevel());
+ ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel());
break;
}
break;
case Algorithm::EC:
switch (SecLevel()) {
+ case SecurityLevel::SOFTWARE:
case SecurityLevel::TRUSTED_ENVIRONMENT:
return {224, 256, 384, 521};
case SecurityLevel::STRONGBOX:
return {256};
default:
- CHECK(false) << "Invalid security level " << uint32_t(SecLevel());
+ ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel());
break;
}
break;
@@ -678,25 +670,27 @@
return retval;
}
default:
- CHECK(false) << "Invalid Algorithm: " << algorithm;
+ ADD_FAILURE() << "Invalid Algorithm: " << algorithm;
return {};
}
- CHECK(false) << "Should be impossible to get here";
+ ADD_FAILURE() << "Should be impossible to get here";
return {};
}
+
std::vector<uint32_t> KeymasterHidlTest::InvalidKeySizes(Algorithm algorithm) {
- if (SecLevel() == SecurityLevel::TRUSTED_ENVIRONMENT) return {};
- CHECK(SecLevel() == SecurityLevel::STRONGBOX);
- switch (algorithm) {
- case Algorithm::RSA:
- return {3072, 4096};
- case Algorithm::EC:
- return {224, 384, 521};
- case Algorithm::AES:
- return {192};
- default:
- return {};
+ if (SecLevel() == SecurityLevel::STRONGBOX) {
+ switch (algorithm) {
+ case Algorithm::RSA:
+ return {3072, 4096};
+ case Algorithm::EC:
+ return {224, 384, 521};
+ case Algorithm::AES:
+ return {192};
+ default:
+ return {};
+ }
}
+ return {};
}
std::vector<EcCurve> KeymasterHidlTest::ValidCurves() {
@@ -715,6 +709,7 @@
std::vector<Digest> KeymasterHidlTest::ValidDigests(bool withNone, bool withMD5) {
switch (SecLevel()) {
+ case SecurityLevel::SOFTWARE:
case SecurityLevel::TRUSTED_ENVIRONMENT:
if (withNone) {
if (withMD5)
@@ -740,10 +735,10 @@
return {Digest::SHA_2_256};
break;
default:
- CHECK(false) << "Invalid security level " << uint32_t(SecLevel());
+ ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel());
break;
}
- CHECK(false) << "Should be impossible to get here";
+ ADD_FAILURE() << "Should be impossible to get here";
return {};
}
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.h b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
index 4bd8b26..f495516 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.h
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
@@ -21,7 +21,6 @@
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
-#include <keymaster/keymaster_configuration.h>
#include <keymasterV4_0/authorization_set.h>
@@ -35,16 +34,18 @@
namespace test {
using ::android::sp;
-using ::std::string;
using hidl::base::V1_0::DebugInfo;
+using ::std::string;
class HidlBuf : public hidl_vec<uint8_t> {
- typedef hidl_vec<uint8_t> super;
+ using super = hidl_vec<uint8_t>;
- public:
+ public:
HidlBuf() {}
HidlBuf(const super& other) : super(other) {}
- HidlBuf(super&& other) : super(std::move(other)) {}
+ HidlBuf(super&& other) : super(std::move(other)) { other = {}; }
+ HidlBuf(const HidlBuf& other) : super(other) {}
+ HidlBuf(HidlBuf&& other) : super(std::move(other)) { other = HidlBuf(); }
explicit HidlBuf(const std::string& other) : HidlBuf() { *this = other; }
HidlBuf& operator=(const super& other) {
@@ -54,6 +55,18 @@
HidlBuf& operator=(super&& other) {
super::operator=(std::move(other));
+ other = {};
+ return *this;
+ }
+
+ HidlBuf& operator=(const HidlBuf& other) {
+ super::operator=(other);
+ return *this;
+ }
+
+ HidlBuf& operator=(HidlBuf&& other) {
+ super::operator=(std::move(other));
+ other.super::operator=({});
return *this;
}
@@ -70,20 +83,16 @@
class KeymasterHidlTest : public ::testing::TestWithParam<std::string> {
public:
- void SetUp();
+ void SetUp() override;
void TearDown() override {
if (key_blob_.size()) {
CheckedDeleteKey();
}
AbortIfNeeded();
- keymaster_.clear();
- all_keymasters_.clear();
}
- void InitializeKeymaster();
-
+ void InitializeKeymaster(sp<IKeymasterDevice> keymaster);
IKeymasterDevice& keymaster() { return *keymaster_; }
- const std::vector<sp<IKeymasterDevice>>& all_keymasters() { return all_keymasters_; }
uint32_t os_version() { return os_version_; }
uint32_t os_patch_level() { return os_patch_level_; }
@@ -209,18 +218,26 @@
KeyCharacteristics key_characteristics_;
OperationHandle op_handle_ = kOpHandleSentinel;
- private:
- sp<IKeymasterDevice> keymaster_;
- std::vector<sp<IKeymasterDevice>> all_keymasters_;
- uint32_t os_version_;
- uint32_t os_patch_level_;
+ static std::vector<std::string> build_params() {
+ auto params = android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor);
+ return params;
+ }
- SecurityLevel securityLevel_;
- hidl_string name_;
- hidl_string author_;
- string service_name_;
+ private:
+ sp<IKeymasterDevice> keymaster_;
+ uint32_t os_version_;
+ uint32_t os_patch_level_;
+
+ SecurityLevel securityLevel_;
+ hidl_string name_;
+ hidl_string author_;
};
+#define INSTANTIATE_KEYMASTER_HIDL_TEST(name) \
+ INSTANTIATE_TEST_SUITE_P(PerInstance, name, \
+ testing::ValuesIn(KeymasterHidlTest::build_params()), \
+ android::hardware::PrintInstanceNameToString)
+
} // namespace test
} // namespace V4_0
} // namespace keymaster
diff --git a/keymaster/4.0/vts/functional/VerificationTokenTest.cpp b/keymaster/4.0/vts/functional/VerificationTokenTest.cpp
index 693f4ae..bab1439 100644
--- a/keymaster/4.0/vts/functional/VerificationTokenTest.cpp
+++ b/keymaster/4.0/vts/functional/VerificationTokenTest.cpp
@@ -185,10 +185,7 @@
memcmp(result1.token.mac.data(), result2.token.mac.data(), result1.token.mac.size()));
}
-INSTANTIATE_TEST_SUITE_P(
- PerInstance, VerificationTokenTest,
- testing::ValuesIn(android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor)),
- android::hardware::PrintInstanceNameToString);
+INSTANTIATE_KEYMASTER_HIDL_TEST(VerificationTokenTest);
} // namespace test
} // namespace V4_0
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index 66132ad..6cbe4da 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -352,11 +352,11 @@
EXPECT_EQ(ErrorCode::OK, error);
if (error != ErrorCode::OK) return false;
- EXPECT_TRUE(att_attestation_version == 3);
+ EXPECT_GE(att_attestation_version, 3U);
expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID, HidlBuf(app_id));
- EXPECT_EQ(att_keymaster_version, 4U);
+ EXPECT_GE(att_keymaster_version, 4U);
EXPECT_EQ(security_level, att_keymaster_security_level);
EXPECT_EQ(security_level, att_attestation_security_level);
@@ -397,10 +397,16 @@
// true. A provided boolean tag that can be pulled back out of the certificate indicates correct
// encoding. No need to check if it's in both lists, since the AuthorizationSet compare below
// will handle mismatches of tags.
- EXPECT_TRUE(expected_hw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
+ if (security_level == SecurityLevel::SOFTWARE) {
+ EXPECT_TRUE(expected_sw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
+ } else {
+ EXPECT_TRUE(expected_hw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
+ }
// Alternatively this checks the opposite - a false boolean tag (one that isn't provided in
// the authorization list during key generation) isn't being attested to in the certificate.
+ EXPECT_FALSE(expected_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
+ EXPECT_FALSE(att_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
EXPECT_FALSE(expected_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
EXPECT_FALSE(att_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
@@ -461,10 +467,10 @@
verified_boot_key.size()));
} else if (!strcmp(property_value, "red")) {
EXPECT_EQ(verified_boot_state, KM_VERIFIED_BOOT_FAILED);
- EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
- verified_boot_key.size()));
} else {
- EXPECT_TRUE(false);
+ EXPECT_EQ(verified_boot_state, KM_VERIFIED_BOOT_UNVERIFIED);
+ EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+ verified_boot_key.size()));
}
att_sw_enforced.Sort();
@@ -840,6 +846,8 @@
.Authorization(TAG_MIN_MAC_LENGTH, 128)));
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(NewKeyGenerationTest);
+
typedef KeymasterHidlTest SigningOperationsTest;
/*
@@ -1509,6 +1517,8 @@
}
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(SigningOperationsTest);
+
typedef KeymasterHidlTest VerificationOperationsTest;
/*
@@ -1749,6 +1759,8 @@
CheckedDeleteKey(&verification_key);
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(VerificationOperationsTest);
+
typedef KeymasterHidlTest ExportKeyTest;
/*
@@ -1828,6 +1840,8 @@
EXPECT_EQ(ErrorCode::UNSUPPORTED_KEY_FORMAT, ExportKey(KeyFormat::RAW, &export_data));
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(ExportKeyTest);
+
class ImportKeyTest : public KeymasterHidlTest {
public:
template <TagType tag_type, Tag tag, typename ValueT>
@@ -2093,6 +2107,8 @@
VerifyMessage(message, signature, AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(ImportKeyTest);
+
auto wrapped_key = hex2str(
"3082017902010004820100934bf94e2aa28a3f83c9f79297250262fbe3276b5a1c91159bbfa3ef8957aac84b59b30b"
"455a79c2973480823d8b3863c3deef4a8e243590268d80e18751a0e130f67ce6a1ace9f79b95e097474febc981195b"
@@ -2214,6 +2230,8 @@
.Padding(PaddingMode::RSA_OAEP)));
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(ImportWrappedKeyTest);
+
typedef KeymasterHidlTest EncryptionOperationsTest;
/*
@@ -4111,6 +4129,8 @@
EXPECT_EQ(message, plaintext);
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(EncryptionOperationsTest);
+
typedef KeymasterHidlTest MaxOperationsTest;
/*
@@ -4166,6 +4186,8 @@
EXPECT_EQ(ErrorCode::KEY_MAX_OPS_EXCEEDED, Begin(KeyPurpose::SIGN, params));
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(MaxOperationsTest);
+
typedef KeymasterHidlTest AddEntropyTest;
/*
@@ -4196,6 +4218,8 @@
EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf(string(2 * 1024, 'a'))));
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(AddEntropyTest);
+
typedef KeymasterHidlTest AttestationTest;
/*
@@ -4373,6 +4397,8 @@
&cert_chain));
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(AttestationTest);
+
typedef KeymasterHidlTest KeyDeletionTest;
/**
@@ -4478,6 +4504,8 @@
}
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(KeyDeletionTest);
+
using UpgradeKeyTest = KeymasterHidlTest;
/*
@@ -4497,6 +4525,8 @@
EXPECT_EQ(result, std::make_pair(ErrorCode::OK, HidlBuf()));
}
+INSTANTIATE_KEYMASTER_HIDL_TEST(UpgradeKeyTest);
+
using ClearOperationsTest = KeymasterHidlTest;
/*
@@ -4533,51 +4563,14 @@
AbortIfNeeded();
}
-/*
- * ClearSlotsTest.ServiceDeath
- *
- * Verifies that the service is restarted after death and the ongoing
- * operations are cleared.
- */
-TEST_P(ClearOperationsTest, ServiceDeath) {
- ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
- .Authorization(TAG_NO_AUTH_REQUIRED)
- .RsaEncryptionKey(2048, 65537)
- .Padding(PaddingMode::NONE)));
-
- auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
- int max_operations = SecLevel() == SecurityLevel::STRONGBOX ? 4 : 16;
- OperationHandle op_handles[max_operations];
- AuthorizationSet out_params;
- for(int i=0; i<max_operations; i++) {
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &(op_handles[i])));
- }
- EXPECT_EQ(ErrorCode::TOO_MANY_OPERATIONS,
- Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &op_handle_));
-
- DebugInfo debug_info;
- GetDebugInfo(&debug_info);
- kill(debug_info.pid, SIGKILL);
- // wait 1 second for keymaster to restart
- sleep(1);
- InitializeKeymaster();
-
- for(int i=0; i<max_operations; i++) {
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &(op_handles[i])));
- }
- EXPECT_EQ(ErrorCode::TOO_MANY_OPERATIONS,
- Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &op_handle_));
- for(int i=0; i<max_operations; i++) {
- EXPECT_EQ(ErrorCode::OK, Abort(op_handles[i]));
- }
-}
+INSTANTIATE_KEYMASTER_HIDL_TEST(ClearOperationsTest);
typedef KeymasterHidlTest TransportLimitTest;
/*
- * TransportLimitTest.LargeFinishInput
+ * TransportLimitTest.FinishInput
*
- * Verifies that passing large input data to finish either succeeds or fails as expected.
+ * Verifies that passing input data to finish succeeds as expected.
*/
TEST_P(TransportLimitTest, LargeFinishInput) {
ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
@@ -4586,7 +4579,7 @@
.BlockMode(BlockMode::ECB)
.Padding(PaddingMode::NONE)));
- for (int msg_size = 10 /*1KB*/; msg_size <= 17 /*128KB*/; msg_size++) {
+ for (int msg_size = 8 /* 256 bytes */; msg_size <= 11 /* 2 KiB */; msg_size++) {
auto cipher_params =
AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
@@ -4597,71 +4590,22 @@
string encrypted_message;
auto rc = Finish(plain_message, &encrypted_message);
- if (rc == ErrorCode::OK) {
- EXPECT_EQ(plain_message.size(), encrypted_message.size())
- << "Encrypt finish returned OK, but did not consume all of the given input";
- } else {
- EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, rc)
- << "Encrypt finish failed in an unexpected way when given a large input";
- continue;
- }
+ EXPECT_EQ(ErrorCode::OK, rc);
+ EXPECT_EQ(plain_message.size(), encrypted_message.size())
+ << "Encrypt finish returned OK, but did not consume all of the given input";
cipher_params.push_back(out_params);
EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, cipher_params));
string decrypted_message;
rc = Finish(encrypted_message, &decrypted_message);
-
- if (rc == ErrorCode::OK) {
- EXPECT_EQ(plain_message.size(), decrypted_message.size())
- << "Decrypt finish returned OK, did not consume all of the given input";
- } else {
- EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, rc)
- << "Encrypt finish failed in an unexpected way when given a large input";
- }
+ EXPECT_EQ(ErrorCode::OK, rc);
+ EXPECT_EQ(plain_message.size(), decrypted_message.size())
+ << "Decrypt finish returned OK, did not consume all of the given input";
}
-
- CheckedDeleteKey();
}
-static const auto kKeymasterDeviceChoices =
- testing::ValuesIn(android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor));
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, NewKeyGenerationTest, kKeymasterDeviceChoices,
- android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, ImportKeyTest, kKeymasterDeviceChoices,
- android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, ImportWrappedKeyTest, kKeymasterDeviceChoices,
- android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, SigningOperationsTest, kKeymasterDeviceChoices,
- android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, VerificationOperationsTest, kKeymasterDeviceChoices,
- android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, ExportKeyTest, kKeymasterDeviceChoices,
- android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, EncryptionOperationsTest, kKeymasterDeviceChoices,
- android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, MaxOperationsTest, kKeymasterDeviceChoices,
- android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, AddEntropyTest, kKeymasterDeviceChoices,
- android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, AttestationTest, kKeymasterDeviceChoices,
- android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, KeyDeletionTest, kKeymasterDeviceChoices,
- android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, TransportLimitTest, kKeymasterDeviceChoices,
- android::hardware::PrintInstanceNameToString);
+INSTANTIATE_KEYMASTER_HIDL_TEST(TransportLimitTest);
} // namespace test
} // namespace V4_0
diff --git a/keymaster/4.1/default/Android.bp b/keymaster/4.1/default/Android.bp
index b06878b..27297b9 100644
--- a/keymaster/4.1/default/Android.bp
+++ b/keymaster/4.1/default/Android.bp
@@ -31,6 +31,7 @@
"libhidlbase",
"libkeymaster4",
"libkeymaster41",
+ "libkeymaster4_1support",
"liblog",
"libutils",
],
diff --git a/keymaster/4.1/support/Android.bp b/keymaster/4.1/support/Android.bp
index 34b6108..bdd0ca8 100644
--- a/keymaster/4.1/support/Android.bp
+++ b/keymaster/4.1/support/Android.bp
@@ -22,11 +22,25 @@
"-Wextra",
"-Werror",
],
+ srcs: [
+ "attestation_record.cpp",
+ "Keymaster.cpp",
+ "Keymaster3.cpp",
+ "Keymaster4.cpp",
+ ],
export_include_dirs: ["include"],
shared_libs: [
"android.hardware.keymaster@3.0",
"android.hardware.keymaster@4.0",
"android.hardware.keymaster@4.1",
+ "libbase",
+ "libcrypto",
+ "libhidlbase",
"libkeymaster4support",
- ]
+ "libutils",
+ ],
+ export_shared_lib_headers: [
+ "android.hardware.keymaster@4.1",
+ "libkeymaster4support",
+ ],
}
diff --git a/keymaster/4.0/support/Keymaster.cpp b/keymaster/4.1/support/Keymaster.cpp
similarity index 85%
rename from keymaster/4.0/support/Keymaster.cpp
rename to keymaster/4.1/support/Keymaster.cpp
index f20f951..ea6604e 100644
--- a/keymaster/4.0/support/Keymaster.cpp
+++ b/keymaster/4.1/support/Keymaster.cpp
@@ -14,19 +14,18 @@
** limitations under the License.
*/
-#include <keymasterV4_0/Keymaster.h>
+#include <keymasterV4_1/Keymaster.h>
#include <iomanip>
#include <android-base/logging.h>
#include <android/hidl/manager/1.2/IServiceManager.h>
-#include <keymasterV4_0/Keymaster3.h>
-#include <keymasterV4_0/Keymaster4.h>
#include <keymasterV4_0/key_param_output.h>
#include <keymasterV4_0/keymaster_utils.h>
+#include <keymasterV4_1/Keymaster3.h>
+#include <keymasterV4_1/Keymaster4.h>
-namespace android {
-namespace hardware {
+namespace android::hardware {
template <class T>
std::ostream& operator<<(std::ostream& os, const hidl_vec<T>& vec) {
@@ -57,6 +56,7 @@
}
namespace keymaster {
+
namespace V4_0 {
std::ostream& operator<<(std::ostream& os, const HmacSharingParameters& params) {
@@ -66,7 +66,9 @@
return os;
}
-namespace support {
+} // namespace V4_0
+
+namespace V4_1::support {
using ::android::sp;
using ::android::hidl::manager::V1_2::IServiceManager;
@@ -140,14 +142,14 @@
}
static hidl_vec<HmacSharingParameters> getHmacParameters(
- const Keymaster::KeymasterSet& keymasters) {
+ const Keymaster::KeymasterSet& keymasters) {
std::vector<HmacSharingParameters> params_vec;
params_vec.reserve(keymasters.size());
for (auto& keymaster : keymasters) {
if (keymaster->halVersion().majorVersion < 4) continue;
auto rc = keymaster->getHmacSharingParameters([&](auto error, auto& params) {
- CHECK(error == ErrorCode::OK)
- << "Failed to get HMAC parameters from " << *keymaster << " error " << error;
+ CHECK(error == V4_0::ErrorCode::OK)
+ << "Failed to get HMAC parameters from " << *keymaster << " error " << error;
params_vec.push_back(params);
});
CHECK(rc.isOk()) << "Failed to communicate with " << *keymaster
@@ -169,18 +171,18 @@
if (keymaster->halVersion().majorVersion < 4) continue;
LOG(DEBUG) << "Computing HMAC for " << *keymaster;
auto rc = keymaster->computeSharedHmac(
- params, [&](ErrorCode error, const hidl_vec<uint8_t>& curSharingCheck) {
- CHECK(error == ErrorCode::OK)
- << "Failed to get HMAC parameters from " << *keymaster << " error " << error;
- if (firstKeymaster) {
- sharingCheck = curSharingCheck;
- firstKeymaster = false;
- }
- if (curSharingCheck != sharingCheck)
- LOG(WARNING) << "HMAC computation failed for " << *keymaster //
- << " Expected: " << sharingCheck //
- << " got: " << curSharingCheck;
- });
+ params, [&](V4_0::ErrorCode error, const hidl_vec<uint8_t>& curSharingCheck) {
+ CHECK(error == V4_0::ErrorCode::OK) << "Failed to get HMAC parameters from "
+ << *keymaster << " error " << error;
+ if (firstKeymaster) {
+ sharingCheck = curSharingCheck;
+ firstKeymaster = false;
+ }
+ if (curSharingCheck != sharingCheck)
+ LOG(WARNING) << "HMAC computation failed for " << *keymaster //
+ << " Expected: " << sharingCheck //
+ << " got: " << curSharingCheck;
+ });
CHECK(rc.isOk()) << "Failed to communicate with " << *keymaster
<< " error: " << rc.description();
}
@@ -190,8 +192,6 @@
computeHmac(keymasters, getHmacParameters(keymasters));
}
-} // namespace support
-} // namespace V4_0
+} // namespace V4_1::support
} // namespace keymaster
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware
diff --git a/keymaster/4.0/support/Keymaster3.cpp b/keymaster/4.1/support/Keymaster3.cpp
similarity index 81%
rename from keymaster/4.0/support/Keymaster3.cpp
rename to keymaster/4.1/support/Keymaster3.cpp
index b2cdbd9..b665689 100644
--- a/keymaster/4.0/support/Keymaster3.cpp
+++ b/keymaster/4.1/support/Keymaster3.cpp
@@ -15,23 +15,19 @@
** limitations under the License.
*/
-#include <keymasterV4_0/Keymaster3.h>
+#include <keymasterV4_1/Keymaster3.h>
#include <android-base/logging.h>
#include <keymasterV4_0/keymaster_utils.h>
-namespace android {
-namespace hardware {
-namespace keymaster {
-namespace V4_0 {
-namespace support {
+namespace android::hardware::keymaster::V4_1::support {
using android::hardware::details::StatusOf;
namespace {
-ErrorCode convert(V3_0::ErrorCode error) {
- return static_cast<ErrorCode>(error);
+V4_0::ErrorCode convert(V3_0::ErrorCode error) {
+ return static_cast<V4_0::ErrorCode>(error);
}
V3_0::KeyPurpose convert(KeyPurpose purpose) {
@@ -53,7 +49,7 @@
KeyParameter convert(const V3_0::KeyParameter& param) {
KeyParameter converted;
- converted.tag = static_cast<Tag>(param.tag);
+ converted.tag = static_cast<V4_0::Tag>(param.tag);
static_assert(sizeof(converted.f) == sizeof(param.f), "This function assumes sizes match");
memcpy(&converted.f, ¶m.f, sizeof(param.f));
converted.blob = param.blob;
@@ -89,7 +85,7 @@
converted[i] = convert(params[i]);
}
converted[params.size()].tag = V3_0::Tag::AUTH_TOKEN;
- converted[params.size()].blob = authToken2HidlVec(authToken);
+ converted[params.size()].blob = V4_0::support::authToken2HidlVec(authToken);
return converted;
}
@@ -107,16 +103,19 @@
if (haveVersion_) return;
auto rc = km3_dev_->getHardwareFeatures(
- [&](bool isSecure, bool supportsEllipticCurve, bool supportsSymmetricCryptography,
- bool supportsAttestation, bool supportsAllDigests, const hidl_string& keymasterName,
- const hidl_string& keymasterAuthorName) {
- version_ = {keymasterName, keymasterAuthorName, 0 /* major version, filled below */,
- isSecure ? SecurityLevel::TRUSTED_ENVIRONMENT : SecurityLevel::SOFTWARE,
- supportsEllipticCurve};
- supportsSymmetricCryptography_ = supportsSymmetricCryptography;
- supportsAttestation_ = supportsAttestation;
- supportsAllDigests_ = supportsAllDigests;
- });
+ [&](bool isSecure, bool supportsEllipticCurve, bool supportsSymmetricCryptography,
+ bool supportsAttestation, bool supportsAllDigests, const hidl_string& keymasterName,
+ const hidl_string& keymasterAuthorName) {
+ version_ = {keymasterName,
+ keymasterAuthorName,
+ 0 /* major version, filled below */,
+ 0 /* minor version */,
+ isSecure ? SecurityLevel::TRUSTED_ENVIRONMENT : SecurityLevel::SOFTWARE,
+ supportsEllipticCurve};
+ supportsSymmetricCryptography_ = supportsSymmetricCryptography;
+ supportsAttestation_ = supportsAttestation;
+ supportsAllDigests_ = supportsAllDigests;
+ });
CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware features";
@@ -139,10 +138,10 @@
return Void();
}
-Return<ErrorCode> Keymaster3::addRngEntropy(const hidl_vec<uint8_t>& data) {
+Return<V4_0::ErrorCode> Keymaster3::addRngEntropy(const hidl_vec<uint8_t>& data) {
auto rc = km3_dev_->addRngEntropy(data);
if (!rc.isOk()) {
- return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+ return StatusOf<V3_0::ErrorCode, V4_0::ErrorCode>(rc);
}
return convert(rc);
}
@@ -215,21 +214,21 @@
return rc;
}
-Return<ErrorCode> Keymaster3::deleteKey(const hidl_vec<uint8_t>& keyBlob) {
+Return<V4_0::ErrorCode> Keymaster3::deleteKey(const hidl_vec<uint8_t>& keyBlob) {
auto rc = km3_dev_->deleteKey(keyBlob);
- if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+ if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, V4_0::ErrorCode>(rc);
return convert(rc);
}
-Return<ErrorCode> Keymaster3::deleteAllKeys() {
+Return<V4_0::ErrorCode> Keymaster3::deleteAllKeys() {
auto rc = km3_dev_->deleteAllKeys();
- if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+ if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, V4_0::ErrorCode>(rc);
return convert(rc);
}
-Return<ErrorCode> Keymaster3::destroyAttestationIds() {
+Return<V4_0::ErrorCode> Keymaster3::destroyAttestationIds() {
auto rc = km3_dev_->destroyAttestationIds();
- if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+ if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, V4_0::ErrorCode>(rc);
return convert(rc);
}
@@ -242,7 +241,7 @@
};
auto rc =
- km3_dev_->begin(convert(purpose), key, convertAndAddAuthToken(inParams, authToken), cb);
+ km3_dev_->begin(convert(purpose), key, convertAndAddAuthToken(inParams, authToken), cb);
rc.isOk(); // move ctor prereq
return rc;
}
@@ -256,8 +255,8 @@
_hidl_cb(convert(error), inputConsumed, convert(outParams), output);
};
- auto rc =
- km3_dev_->update(operationHandle, convertAndAddAuthToken(inParams, authToken), input, cb);
+ auto rc = km3_dev_->update(operationHandle, convertAndAddAuthToken(inParams, authToken), input,
+ cb);
rc.isOk(); // move ctor prereq
return rc;
}
@@ -278,14 +277,10 @@
return rc;
}
-Return<ErrorCode> Keymaster3::abort(uint64_t operationHandle) {
+Return<V4_0::ErrorCode> Keymaster3::abort(uint64_t operationHandle) {
auto rc = km3_dev_->abort(operationHandle);
- if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+ if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, V4_0::ErrorCode>(rc);
return convert(rc);
}
-} // namespace support
-} // namespace V4_0
-} // namespace keymaster
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.1/support/Keymaster4.cpp b/keymaster/4.1/support/Keymaster4.cpp
new file mode 100644
index 0000000..33f4bb1
--- /dev/null
+++ b/keymaster/4.1/support/Keymaster4.cpp
@@ -0,0 +1,41 @@
+/*
+** Copyright 2017, 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 <keymasterV4_1/Keymaster4.h>
+
+#include <android-base/logging.h>
+
+namespace android::hardware::keymaster::V4_1::support {
+
+void Keymaster4::getVersionIfNeeded() {
+ if (haveVersion_) return;
+
+ auto rc = km4_0_dev_->getHardwareInfo([&](SecurityLevel securityLevel,
+ const hidl_string& keymasterName,
+ const hidl_string& authorName) {
+ version_ = {keymasterName,
+ authorName,
+ 4 /* major version */,
+ static_cast<uint8_t>((km4_1_dev_) ? 1 : 0) /* minor version */,
+ securityLevel,
+ true /* supportsEc */};
+ haveVersion_ = true;
+ });
+
+ CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware info";
+}
+
+} // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.1/support/OWNERS b/keymaster/4.1/support/OWNERS
new file mode 100644
index 0000000..a9efe66
--- /dev/null
+++ b/keymaster/4.1/support/OWNERS
@@ -0,0 +1,3 @@
+jdanis@google.com
+swillden@google.com
+jbires@google.com
diff --git a/keymaster/4.1/support/attestation_record.cpp b/keymaster/4.1/support/attestation_record.cpp
new file mode 100644
index 0000000..9eab1db
--- /dev/null
+++ b/keymaster/4.1/support/attestation_record.cpp
@@ -0,0 +1,387 @@
+/*
+ * Copyright 2020 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 <keymasterV4_1/attestation_record.h>
+
+#include <android-base/logging.h>
+#include <assert.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#include <keymasterV4_0/authorization_set.h>
+#include <keymasterV4_0/openssl_utils.h>
+
+#define AT __FILE__ ":" << __LINE__
+
+/*
+ * NOTE: The contents of this file are *extremely* similar to the contents of the V4_0 copy of the
+ * same support file. Unfortunately, small changes in the scheme mean that the schema types have to
+ * be distinct, which drives almost everything else to be different as well. In the next version we
+ * plan to abandon not just this openssl mechanism for parsing ASN.1, but ASN.1 entirely, so
+ * eventually all of this duplication can be removed.
+ */
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_1 {
+
+struct stack_st_ASN1_TYPE_Delete {
+ void operator()(stack_st_ASN1_TYPE* p) { sk_ASN1_TYPE_free(p); }
+};
+
+struct ASN1_STRING_Delete {
+ void operator()(ASN1_STRING* p) { ASN1_STRING_free(p); }
+};
+
+struct ASN1_TYPE_Delete {
+ void operator()(ASN1_TYPE* p) { ASN1_TYPE_free(p); }
+};
+
+#define ASN1_INTEGER_SET STACK_OF(ASN1_INTEGER)
+
+typedef struct km_root_of_trust {
+ ASN1_OCTET_STRING* verified_boot_key;
+ ASN1_BOOLEAN* device_locked;
+ ASN1_ENUMERATED* verified_boot_state;
+ ASN1_OCTET_STRING* verified_boot_hash;
+} KM_ROOT_OF_TRUST;
+
+ASN1_SEQUENCE(KM_ROOT_OF_TRUST) = {
+ ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_key, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(KM_ROOT_OF_TRUST, device_locked, ASN1_BOOLEAN),
+ ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_state, ASN1_ENUMERATED),
+ ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_hash, ASN1_OCTET_STRING),
+} ASN1_SEQUENCE_END(KM_ROOT_OF_TRUST);
+IMPLEMENT_ASN1_FUNCTIONS(KM_ROOT_OF_TRUST);
+
+typedef struct km_auth_list {
+ ASN1_INTEGER_SET* purpose;
+ ASN1_INTEGER* algorithm;
+ ASN1_INTEGER* key_size;
+ ASN1_INTEGER_SET* digest;
+ ASN1_INTEGER_SET* padding;
+ ASN1_INTEGER* ec_curve;
+ ASN1_INTEGER* rsa_public_exponent;
+ ASN1_INTEGER* active_date_time;
+ ASN1_INTEGER* origination_expire_date_time;
+ ASN1_INTEGER* usage_expire_date_time;
+ ASN1_NULL* no_auth_required;
+ ASN1_INTEGER* user_auth_type;
+ ASN1_INTEGER* auth_timeout;
+ ASN1_NULL* allow_while_on_body;
+ ASN1_NULL* all_applications;
+ ASN1_OCTET_STRING* application_id;
+ ASN1_INTEGER* creation_date_time;
+ ASN1_INTEGER* origin;
+ ASN1_NULL* rollback_resistance;
+ KM_ROOT_OF_TRUST* root_of_trust;
+ ASN1_INTEGER* os_version;
+ ASN1_INTEGER* os_patchlevel;
+ ASN1_OCTET_STRING* attestation_application_id;
+ ASN1_NULL* trusted_user_presence_required;
+ ASN1_NULL* trusted_confirmation_required;
+ ASN1_NULL* unlocked_device_required;
+ ASN1_INTEGER* vendor_patchlevel;
+ ASN1_INTEGER* boot_patchlevel;
+ ASN1_NULL* early_boot_only;
+ ASN1_NULL* device_unique_attestation;
+} KM_AUTH_LIST;
+
+ASN1_SEQUENCE(KM_AUTH_LIST) = {
+ ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.maskedTag()),
+ ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.maskedTag()),
+ ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER,
+ TAG_RSA_PUBLIC_EXPONENT.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistance, ASN1_NULL,
+ TAG_ROLLBACK_RESISTANCE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER,
+ TAG_ORIGINATION_EXPIRE_DATETIME.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER,
+ TAG_USAGE_EXPIRE_DATETIME.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, allow_while_on_body, ASN1_NULL,
+ TAG_ALLOW_WHILE_ON_BODY.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, trusted_user_presence_required, ASN1_NULL,
+ TAG_TRUSTED_USER_PRESENCE_REQUIRED.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, trusted_confirmation_required, ASN1_NULL,
+ TAG_TRUSTED_CONFIRMATION_REQUIRED.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, unlocked_device_required, ASN1_NULL,
+ TAG_UNLOCKED_DEVICE_REQUIRED.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER,
+ TAG_CREATION_DATETIME.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, vendor_patchlevel, ASN1_INTEGER,
+ TAG_VENDOR_PATCHLEVEL.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, boot_patchlevel, ASN1_INTEGER, TAG_BOOT_PATCHLEVEL.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_application_id, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_APPLICATION_ID.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, early_boot_only, ASN1_NULL, TAG_EARLY_BOOT_ONLY.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, device_unique_attestation, ASN1_NULL,
+ TAG_DEVICE_UNIQUE_ATTESTATION.maskedTag()),
+} ASN1_SEQUENCE_END(KM_AUTH_LIST);
+IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST);
+
+typedef struct km_key_description {
+ ASN1_INTEGER* attestation_version;
+ ASN1_ENUMERATED* attestation_security_level;
+ ASN1_INTEGER* keymaster_version;
+ ASN1_ENUMERATED* keymaster_security_level;
+ ASN1_OCTET_STRING* attestation_challenge;
+ KM_AUTH_LIST* software_enforced;
+ KM_AUTH_LIST* tee_enforced;
+ ASN1_INTEGER* unique_id;
+} KM_KEY_DESCRIPTION;
+
+ASN1_SEQUENCE(KM_KEY_DESCRIPTION) = {
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_version, ASN1_INTEGER),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_security_level, ASN1_ENUMERATED),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_version, ASN1_INTEGER),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_security_level, ASN1_ENUMERATED),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_challenge, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, unique_id, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, software_enforced, KM_AUTH_LIST),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, tee_enforced, KM_AUTH_LIST),
+} ASN1_SEQUENCE_END(KM_KEY_DESCRIPTION);
+IMPLEMENT_ASN1_FUNCTIONS(KM_KEY_DESCRIPTION);
+
+template <V4_0::Tag tag>
+void copyAuthTag(const stack_st_ASN1_INTEGER* stack, TypedTag<TagType::ENUM_REP, tag> ttag,
+ AuthorizationSet* auth_list) {
+ typedef typename V4_0::TypedTag2ValueType<decltype(ttag)>::type ValueT;
+ for (size_t i = 0; i < sk_ASN1_INTEGER_num(stack); ++i) {
+ auth_list->push_back(
+ ttag, static_cast<ValueT>(ASN1_INTEGER_get(sk_ASN1_INTEGER_value(stack, i))));
+ }
+}
+
+template <V4_0::Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::ENUM, tag> ttag,
+ AuthorizationSet* auth_list) {
+ typedef typename V4_0::TypedTag2ValueType<decltype(ttag)>::type ValueT;
+ if (!asn1_int) return;
+ auth_list->push_back(ttag, static_cast<ValueT>(ASN1_INTEGER_get(asn1_int)));
+}
+
+template <V4_0::Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::UINT, tag> ttag,
+ AuthorizationSet* auth_list) {
+ if (!asn1_int) return;
+ auth_list->push_back(ttag, ASN1_INTEGER_get(asn1_int));
+}
+
+BIGNUM* construct_uint_max() {
+ BIGNUM* value = BN_new();
+ BIGNUM_Ptr one(BN_new());
+ BN_one(one.get());
+ BN_lshift(value, one.get(), 32);
+ return value;
+}
+
+uint64_t BignumToUint64(BIGNUM* num) {
+ static_assert((sizeof(BN_ULONG) == sizeof(uint32_t)) || (sizeof(BN_ULONG) == sizeof(uint64_t)),
+ "This implementation only supports 32 and 64-bit BN_ULONG");
+ if (sizeof(BN_ULONG) == sizeof(uint32_t)) {
+ BIGNUM_Ptr uint_max(construct_uint_max());
+ BIGNUM_Ptr hi(BN_new()), lo(BN_new());
+ BN_CTX_Ptr ctx(BN_CTX_new());
+ BN_div(hi.get(), lo.get(), num, uint_max.get(), ctx.get());
+ return static_cast<uint64_t>(BN_get_word(hi.get())) << 32 | BN_get_word(lo.get());
+ } else if (sizeof(BN_ULONG) == sizeof(uint64_t)) {
+ return BN_get_word(num);
+ } else {
+ return 0;
+ }
+}
+
+template <V4_0::Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::ULONG, tag> ttag,
+ AuthorizationSet* auth_list) {
+ if (!asn1_int) return;
+ BIGNUM_Ptr num(ASN1_INTEGER_to_BN(asn1_int, nullptr));
+ auth_list->push_back(ttag, BignumToUint64(num.get()));
+}
+
+template <V4_0::Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::DATE, tag> ttag,
+ AuthorizationSet* auth_list) {
+ if (!asn1_int) return;
+ BIGNUM_Ptr num(ASN1_INTEGER_to_BN(asn1_int, nullptr));
+ auth_list->push_back(ttag, BignumToUint64(num.get()));
+}
+
+template <V4_0::Tag tag>
+void copyAuthTag(const ASN1_NULL* asn1_null, TypedTag<TagType::BOOL, tag> ttag,
+ AuthorizationSet* auth_list) {
+ if (!asn1_null) return;
+ auth_list->push_back(ttag);
+}
+
+template <V4_0::Tag tag>
+void copyAuthTag(const ASN1_OCTET_STRING* asn1_string, TypedTag<TagType::BYTES, tag> ttag,
+ AuthorizationSet* auth_list) {
+ if (!asn1_string) return;
+ hidl_vec<uint8_t> buf;
+ buf.setToExternal(asn1_string->data, asn1_string->length);
+ auth_list->push_back(ttag, buf);
+}
+
+// Extract the values from the specified ASN.1 record and place them in auth_list.
+static ErrorCode extract_auth_list(const KM_AUTH_LIST* record, AuthorizationSet* auth_list) {
+ if (!record) return ErrorCode::OK;
+
+ copyAuthTag(record->active_date_time, TAG_ACTIVE_DATETIME, auth_list);
+ copyAuthTag(record->algorithm, TAG_ALGORITHM, auth_list);
+ copyAuthTag(record->application_id, TAG_APPLICATION_ID, auth_list);
+ copyAuthTag(record->auth_timeout, TAG_AUTH_TIMEOUT, auth_list);
+ copyAuthTag(record->creation_date_time, TAG_CREATION_DATETIME, auth_list);
+ copyAuthTag(record->digest, TAG_DIGEST, auth_list);
+ copyAuthTag(record->ec_curve, TAG_EC_CURVE, auth_list);
+ copyAuthTag(record->key_size, TAG_KEY_SIZE, auth_list);
+ copyAuthTag(record->no_auth_required, TAG_NO_AUTH_REQUIRED, auth_list);
+ copyAuthTag(record->origin, TAG_ORIGIN, auth_list);
+ copyAuthTag(record->origination_expire_date_time, TAG_ORIGINATION_EXPIRE_DATETIME, auth_list);
+ copyAuthTag(record->os_patchlevel, TAG_OS_PATCHLEVEL, auth_list);
+ copyAuthTag(record->os_version, TAG_OS_VERSION, auth_list);
+ copyAuthTag(record->padding, TAG_PADDING, auth_list);
+ copyAuthTag(record->purpose, TAG_PURPOSE, auth_list);
+ copyAuthTag(record->rollback_resistance, TAG_ROLLBACK_RESISTANCE, auth_list);
+ copyAuthTag(record->rsa_public_exponent, TAG_RSA_PUBLIC_EXPONENT, auth_list);
+ copyAuthTag(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list);
+ copyAuthTag(record->user_auth_type, TAG_USER_AUTH_TYPE, auth_list);
+ copyAuthTag(record->attestation_application_id, TAG_ATTESTATION_APPLICATION_ID, auth_list);
+ copyAuthTag(record->vendor_patchlevel, TAG_VENDOR_PATCHLEVEL, auth_list);
+ copyAuthTag(record->boot_patchlevel, TAG_BOOT_PATCHLEVEL, auth_list);
+ copyAuthTag(record->trusted_user_presence_required, TAG_TRUSTED_USER_PRESENCE_REQUIRED,
+ auth_list);
+ copyAuthTag(record->trusted_confirmation_required, TAG_TRUSTED_CONFIRMATION_REQUIRED,
+ auth_list);
+ copyAuthTag(record->unlocked_device_required, TAG_UNLOCKED_DEVICE_REQUIRED, auth_list);
+ copyAuthTag(record->early_boot_only, TAG_EARLY_BOOT_ONLY, auth_list);
+ copyAuthTag(record->device_unique_attestation, TAG_DEVICE_UNIQUE_ATTESTATION, auth_list);
+
+ return ErrorCode::OK;
+}
+
+MAKE_OPENSSL_PTR_TYPE(KM_KEY_DESCRIPTION)
+
+// Parse the DER-encoded attestation record, placing the results in keymaster_version,
+// attestation_challenge, software_enforced, tee_enforced and unique_id.
+std::tuple<ErrorCode, AttestationRecord> parse_attestation_record(const hidl_vec<uint8_t>& cert) {
+ const uint8_t* p = cert.data();
+ X509_Ptr x509(d2i_X509(nullptr, &p, cert.size()));
+
+ ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
+ if (!oid.get()) {
+ LOG(ERROR) << "Error parsing OID";
+ return {ErrorCode::UNKNOWN_ERROR, {}};
+ }
+
+ int location = X509_get_ext_by_OBJ(x509.get(), oid.get(), -1 /* search from beginning */);
+ if (location == -1) {
+ LOG(ERROR) << "Attestation extension not found in certificate";
+ return {ErrorCode::UNKNOWN_ERROR, {}};
+ }
+
+ X509_EXTENSION* attest_rec_ext = X509_get_ext(x509.get(), location);
+ if (!attest_rec_ext) {
+ LOG(ERROR) << "Found extension but couldn't retrieve it. Probably BoringSSL bug.";
+ return {ErrorCode::UNKNOWN_ERROR, {}};
+ }
+
+ ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
+ if (!attest_rec_ext) {
+ LOG(ERROR) << "Attestation extension contained no data";
+ return {ErrorCode::UNKNOWN_ERROR, {}};
+ }
+
+ p = attest_rec->data;
+ KM_KEY_DESCRIPTION_Ptr record(d2i_KM_KEY_DESCRIPTION(nullptr, &p, attest_rec->length));
+ if (!record.get()) return {ErrorCode::UNKNOWN_ERROR, {}};
+
+ AttestationRecord result;
+
+ result.attestation_version = ASN1_INTEGER_get(record->attestation_version);
+ result.attestation_security_level =
+ static_cast<SecurityLevel>(ASN1_ENUMERATED_get(record->attestation_security_level));
+ result.keymaster_version = ASN1_INTEGER_get(record->keymaster_version);
+ result.keymaster_security_level =
+ static_cast<SecurityLevel>(ASN1_ENUMERATED_get(record->keymaster_security_level));
+
+ auto& chall = record->attestation_challenge;
+ result.attestation_challenge.resize(chall->length);
+ memcpy(result.attestation_challenge.data(), chall->data, chall->length);
+ auto& uid = record->unique_id;
+ result.unique_id.resize(uid->length);
+ memcpy(result.unique_id.data(), uid->data, uid->length);
+
+ ErrorCode error = extract_auth_list(record->software_enforced, &result.software_enforced);
+ if (error != ErrorCode::OK) return {error, {}};
+
+ error = extract_auth_list(record->tee_enforced, &result.hardware_enforced);
+ if (error != ErrorCode::OK) return {error, {}};
+
+ KM_ROOT_OF_TRUST* root_of_trust = nullptr;
+ if (record->tee_enforced && record->tee_enforced->root_of_trust) {
+ root_of_trust = record->tee_enforced->root_of_trust;
+ } else if (record->software_enforced && record->software_enforced->root_of_trust) {
+ root_of_trust = record->software_enforced->root_of_trust;
+ } else {
+ LOG(ERROR) << AT << " Failed root of trust parsing";
+ return {ErrorCode::INVALID_ARGUMENT, {}};
+ }
+ if (!root_of_trust->verified_boot_key) {
+ LOG(ERROR) << AT << " Failed verified boot key parsing";
+ return {ErrorCode::INVALID_ARGUMENT, {}};
+ }
+
+ RootOfTrust& rot = result.root_of_trust;
+ auto& vb_key = root_of_trust->verified_boot_key;
+ rot.verified_boot_key.resize(vb_key->length);
+ memcpy(rot.verified_boot_key.data(), vb_key->data, vb_key->length);
+
+ rot.verified_boot_state = static_cast<keymaster_verified_boot_t>(
+ ASN1_ENUMERATED_get(root_of_trust->verified_boot_state));
+ rot.device_locked = root_of_trust->device_locked;
+
+ auto& vb_hash = root_of_trust->verified_boot_hash;
+ if (!vb_hash) {
+ LOG(ERROR) << AT << " Failed verified boot hash parsing";
+ return {ErrorCode::INVALID_ARGUMENT, {}};
+ }
+ rot.verified_boot_hash.resize(vb_hash->length);
+ memcpy(rot.verified_boot_hash.data(), vb_hash->data, vb_hash->length);
+
+ return {ErrorCode::OK, result};
+}
+
+} // namespace V4_1
+} // namespace keymaster
+} // namespace hardware
+} // namespace android
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h b/keymaster/4.1/support/include/keymasterV4_1/Keymaster.h
similarity index 73%
rename from keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
rename to keymaster/4.1/support/include/keymasterV4_1/Keymaster.h
index ad83f17..1f49e18 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
+++ b/keymaster/4.1/support/include/keymasterV4_1/Keymaster.h
@@ -15,28 +15,28 @@
** limitations under the License.
*/
-#ifndef HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_H_
-#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_H_
-
-#include <android/hardware/keymaster/4.0/IKeymasterDevice.h>
+#pragma once
#include <memory>
#include <vector>
-namespace android {
-namespace hardware {
-namespace keymaster {
-namespace V4_0 {
-namespace support {
+#include <android/hardware/keymaster/4.1/IKeymasterDevice.h>
+#include <keymasterV4_1/keymaster_tags.h>
+
+namespace android::hardware::keymaster::V4_1::support {
/**
- * Keymaster abstracts the underlying V4_0::IKeymasterDevice. There is one implementation
- * (Keymaster4) which is a trivial passthrough and one that wraps a V3_0::IKeymasterDevice.
+ * Keymaster abstracts the underlying V4_1::IKeymasterDevice. There are two implementations,
+ * Keymaster3 which wraps a V3_0::IKeymasterDevice and Keymaster4, which wraps either a
+ * V4_0::IKeymasterDevice or a V4_1::IKeymasterDevice. There is a V3_0::IKeymasterDevice
+ * implementation that is used to wrap pre-HIDL keymaster implementations, and Keymaster3 will wrap
+ * that.
*
* The reason for adding this additional layer, rather than simply using the latest HAL directly and
* subclassing it to wrap any older HAL, is because this provides a place to put additional methods
* which clients can use when they need to distinguish between different underlying HAL versions,
- * while still having to use only the latest interface.
+ * while still having to use only the latest interface. Plus it's a handy place to keep some
+ * convenience methods.
*/
class Keymaster : public IKeymasterDevice {
public:
@@ -50,12 +50,14 @@
hidl_string keymasterName;
hidl_string authorName;
uint8_t majorVersion;
+ uint8_t minorVersion;
SecurityLevel securityLevel;
bool supportsEc;
bool operator>(const VersionResult& other) const {
- auto lhs = std::tie(securityLevel, majorVersion, supportsEc);
- auto rhs = std::tie(other.securityLevel, other.majorVersion, other.supportsEc);
+ auto lhs = std::tie(securityLevel, majorVersion, minorVersion, supportsEc);
+ auto rhs = std::tie(other.securityLevel, other.majorVersion, other.minorVersion,
+ other.supportsEc);
return lhs > rhs;
}
};
@@ -69,6 +71,9 @@
* There are no side effects otherwise.
*/
void logIfKeymasterVendorError(ErrorCode ec) const;
+ void logIfKeymasterVendorError(V4_0::ErrorCode ec) const {
+ logIfKeymasterVendorError(static_cast<ErrorCode>(ec));
+ }
/**
* Returns all available Keymaster3 and Keymaster4 instances, in order of most secure to least
@@ -93,10 +98,4 @@
std::ostream& operator<<(std::ostream& os, const Keymaster& keymaster);
-} // namespace support
-} // namespace V4_0
-} // namespace keymaster
-} // namespace hardware
-} // namespace android
-
-#endif // HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_H_
+} // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h b/keymaster/4.1/support/include/keymasterV4_1/Keymaster3.h
similarity index 72%
rename from keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h
rename to keymaster/4.1/support/include/keymasterV4_1/Keymaster3.h
index c40be7c..c201e8c 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h
+++ b/keymaster/4.1/support/include/keymasterV4_1/Keymaster3.h
@@ -1,5 +1,4 @@
/*
- **
** Copyright 2017, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,18 +14,14 @@
** limitations under the License.
*/
-#ifndef HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_3_H_
-#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_3_H_
+#pragma once
#include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
#include "Keymaster.h"
+#include "Operation.h"
-namespace android {
-namespace hardware {
-namespace keymaster {
-namespace V4_0 {
-namespace support {
+namespace android::hardware::keymaster::V4_1::support {
using IKeymaster3Device = ::android::hardware::keymaster::V3_0::IKeymasterDevice;
@@ -38,8 +33,10 @@
using ::android::hardware::details::return_status;
class Keymaster3 : public Keymaster {
- public:
+ public:
+ // This definition is used for device enumeration.
using WrappedIKeymasterDevice = IKeymaster3Device;
+
Keymaster3(sp<IKeymaster3Device> km3_dev, const hidl_string& instanceName)
: Keymaster(IKeymaster3Device::descriptor, instanceName),
km3_dev_(km3_dev),
@@ -53,24 +50,24 @@
Return<void> getHardwareInfo(getHardwareInfo_cb _hidl_cb);
Return<void> getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) override {
- _hidl_cb(ErrorCode::UNIMPLEMENTED, {});
+ _hidl_cb(V4_0::ErrorCode::UNIMPLEMENTED, {});
return Void();
}
Return<void> computeSharedHmac(const hidl_vec<HmacSharingParameters>&,
computeSharedHmac_cb _hidl_cb) override {
- _hidl_cb(ErrorCode::UNIMPLEMENTED, {});
+ _hidl_cb(V4_0::ErrorCode::UNIMPLEMENTED, {});
return Void();
}
Return<void> verifyAuthorization(uint64_t, const hidl_vec<KeyParameter>&,
const HardwareAuthToken&,
verifyAuthorization_cb _hidl_cb) override {
- _hidl_cb(ErrorCode::UNIMPLEMENTED, {});
+ _hidl_cb(V4_0::ErrorCode::UNIMPLEMENTED, {});
return Void();
}
- Return<ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override;
+ Return<V4_0::ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override;
Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
generateKey_cb _hidl_cb) override;
Return<void> getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
@@ -86,7 +83,7 @@
const hidl_vec<KeyParameter>& /* unwrappingParams */,
uint64_t /* passwordSid */, uint64_t /* biometricSid */,
importWrappedKey_cb _hidl_cb) {
- _hidl_cb(ErrorCode::UNIMPLEMENTED, {}, {});
+ _hidl_cb(V4_0::ErrorCode::UNIMPLEMENTED, {}, {});
return Void();
}
@@ -99,9 +96,9 @@
Return<void> upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
const hidl_vec<KeyParameter>& upgradeParams,
upgradeKey_cb _hidl_cb) override;
- Return<ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override;
- Return<ErrorCode> deleteAllKeys() override;
- Return<ErrorCode> destroyAttestationIds() override;
+ Return<V4_0::ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override;
+ Return<V4_0::ErrorCode> deleteAllKeys() override;
+ Return<V4_0::ErrorCode> destroyAttestationIds() override;
Return<void> begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
begin_cb _hidl_cb) override;
@@ -112,9 +109,31 @@
const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
const HardwareAuthToken& authToken,
const VerificationToken& verificationToken, finish_cb _hidl_cb) override;
- Return<ErrorCode> abort(uint64_t operationHandle) override;
+ Return<V4_0::ErrorCode> abort(uint64_t operationHandle) override;
- private:
+ /**********************************
+ * V4_1::IKeymasterDevice methods *
+ *********************************/
+
+ Return<ErrorCode> deviceLocked(bool /* passwordOnly */,
+ const VerificationToken& /* verificationToken */) override {
+ return ErrorCode::UNIMPLEMENTED;
+ }
+
+ Return<ErrorCode> earlyBootEnded() override { return ErrorCode::UNIMPLEMENTED; }
+
+ Return<void> beginOp(KeyPurpose purpose, const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
+ beginOp_cb _hidl_cb) override {
+ return begin(purpose, keyBlob, inParams, authToken,
+ [&_hidl_cb](V4_0::ErrorCode errorCode, const hidl_vec<KeyParameter>& outParams,
+ OperationHandle operationHandle) {
+ _hidl_cb(static_cast<ErrorCode>(errorCode), outParams,
+ new Operation(operationHandle));
+ });
+ }
+
+ private:
void getVersionIfNeeded();
sp<IKeymaster3Device> km3_dev_;
@@ -126,10 +145,4 @@
bool supportsAllDigests_;
};
-} // namespace support
-} // namespace V4_0
-} // namespace keymaster
-} // namespace hardware
-} // namespace android
-
-#endif // HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_3_H_
+} // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.1/support/include/keymasterV4_1/Keymaster4.h b/keymaster/4.1/support/include/keymasterV4_1/Keymaster4.h
new file mode 100644
index 0000000..6d74d98
--- /dev/null
+++ b/keymaster/4.1/support/include/keymasterV4_1/Keymaster4.h
@@ -0,0 +1,197 @@
+/*
+ ** Copyright 2020, 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.
+ */
+
+#pragma once
+
+#include "Keymaster.h"
+#include "Operation.h"
+
+namespace android::hardware::keymaster::V4_1::support {
+
+using android::sp;
+
+/**
+ * This class can wrap either a V4_0 or V4_1 IKeymasterDevice.
+ */
+class Keymaster4 : public Keymaster {
+ public:
+ // This definition is used for device enumeration; enumerating 4.0 devices will also
+ // enumerate 4.1. devices.
+ using WrappedIKeymasterDevice = V4_0::IKeymasterDevice;
+
+ Keymaster4(sp<V4_1::IKeymasterDevice> km4_1_dev, const hidl_string& instanceName)
+ : Keymaster(V4_1::IKeymasterDevice::descriptor, instanceName),
+ haveVersion_(false),
+ km4_0_dev_(km4_1_dev),
+ km4_1_dev_(km4_1_dev) {}
+
+ Keymaster4(sp<V4_0::IKeymasterDevice> km4_0_dev, const hidl_string& instanceName)
+ : Keymaster(V4_1::IKeymasterDevice::descriptor, instanceName),
+ haveVersion_(false),
+ km4_0_dev_(km4_0_dev),
+ km4_1_dev_() {}
+
+ const VersionResult& halVersion() const override {
+ const_cast<Keymaster4*>(this)->getVersionIfNeeded();
+ return version_;
+ }
+
+ /**********************************
+ * V4_0::IKeymasterDevice methods *
+ *********************************/
+
+ Return<void> getHardwareInfo(getHardwareInfo_cb _hidl_cb) override {
+ return km4_0_dev_->getHardwareInfo(_hidl_cb);
+ }
+
+ Return<void> getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) override {
+ return km4_0_dev_->getHmacSharingParameters(_hidl_cb);
+ }
+
+ Return<void> computeSharedHmac(const hidl_vec<HmacSharingParameters>& params,
+ computeSharedHmac_cb _hidl_cb) override {
+ return km4_0_dev_->computeSharedHmac(params, _hidl_cb);
+ }
+
+ Return<void> verifyAuthorization(uint64_t operationHandle, const hidl_vec<KeyParameter>& params,
+ const HardwareAuthToken& authToken,
+ verifyAuthorization_cb _hidl_cb) override {
+ return km4_0_dev_->verifyAuthorization(operationHandle, params, authToken, _hidl_cb);
+ }
+
+ Return<V4_0::ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override {
+ return km4_0_dev_->addRngEntropy(data);
+ }
+
+ Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
+ generateKey_cb _hidl_cb) override {
+ return km4_0_dev_->generateKey(keyParams, _hidl_cb);
+ }
+
+ Return<void> getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<uint8_t>& clientId,
+ const hidl_vec<uint8_t>& appData,
+ getKeyCharacteristics_cb _hidl_cb) override {
+ return km4_0_dev_->getKeyCharacteristics(keyBlob, clientId, appData, _hidl_cb);
+ }
+
+ Return<void> importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
+ const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) override {
+ return km4_0_dev_->importKey(params, keyFormat, keyData, _hidl_cb);
+ }
+
+ Return<void> importWrappedKey(const hidl_vec<uint8_t>& wrappedKeyData,
+ const hidl_vec<uint8_t>& wrappingKeyBlob,
+ const hidl_vec<uint8_t>& maskingKey,
+ const hidl_vec<KeyParameter>& unwrappingParams,
+ uint64_t passwordSid, uint64_t biometricSid,
+ importWrappedKey_cb _hidl_cb) {
+ return km4_0_dev_->importWrappedKey(wrappedKeyData, wrappingKeyBlob, maskingKey,
+ unwrappingParams, passwordSid, biometricSid, _hidl_cb);
+ }
+
+ Return<void> exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<uint8_t>& clientId, const hidl_vec<uint8_t>& appData,
+ exportKey_cb _hidl_cb) override {
+ return km4_0_dev_->exportKey(exportFormat, keyBlob, clientId, appData, _hidl_cb);
+ }
+
+ Return<void> attestKey(const hidl_vec<uint8_t>& keyToAttest,
+ const hidl_vec<KeyParameter>& attestParams,
+ attestKey_cb _hidl_cb) override {
+ return km4_0_dev_->attestKey(keyToAttest, attestParams, _hidl_cb);
+ }
+
+ Return<void> upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
+ const hidl_vec<KeyParameter>& upgradeParams,
+ upgradeKey_cb _hidl_cb) override {
+ return km4_0_dev_->upgradeKey(keyBlobToUpgrade, upgradeParams, _hidl_cb);
+ }
+
+ Return<V4_0::ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override {
+ return km4_0_dev_->deleteKey(keyBlob);
+ }
+
+ Return<V4_0::ErrorCode> deleteAllKeys() override { return km4_0_dev_->deleteAllKeys(); }
+
+ Return<V4_0::ErrorCode> destroyAttestationIds() override {
+ return km4_0_dev_->destroyAttestationIds();
+ }
+
+ Return<void> begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
+ const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
+ begin_cb _hidl_cb) override {
+ return km4_0_dev_->begin(purpose, key, inParams, authToken, _hidl_cb);
+ }
+
+ Return<void> update(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+ const hidl_vec<uint8_t>& input, const HardwareAuthToken& authToken,
+ const VerificationToken& verificationToken, update_cb _hidl_cb) override {
+ return km4_0_dev_->update(operationHandle, inParams, input, authToken, verificationToken,
+ _hidl_cb);
+ }
+
+ Return<void> finish(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+ const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
+ const HardwareAuthToken& authToken,
+ const VerificationToken& verificationToken, finish_cb _hidl_cb) override {
+ return km4_0_dev_->finish(operationHandle, inParams, input, signature, authToken,
+ verificationToken, _hidl_cb);
+ }
+
+ Return<V4_0::ErrorCode> abort(uint64_t operationHandle) override {
+ return km4_0_dev_->abort(operationHandle);
+ }
+
+ /**********************************
+ * V4_1::IKeymasterDevice methods *
+ *********************************/
+
+ Return<ErrorCode> deviceLocked(bool passwordOnly,
+ const VerificationToken& verificationToken) override {
+ if (km4_1_dev_) return km4_1_dev_->deviceLocked(passwordOnly, verificationToken);
+ return ErrorCode::UNIMPLEMENTED;
+ }
+
+ Return<ErrorCode> earlyBootEnded() override {
+ if (km4_1_dev_) return km4_1_dev_->earlyBootEnded();
+ return ErrorCode::UNIMPLEMENTED;
+ }
+
+ Return<void> beginOp(KeyPurpose purpose, const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
+ beginOp_cb _hidl_cb) override {
+ if (km4_1_dev_) return km4_1_dev_->beginOp(purpose, keyBlob, inParams, authToken, _hidl_cb);
+
+ return km4_0_dev_->begin(
+ purpose, keyBlob, inParams, authToken,
+ [&_hidl_cb](V4_0::ErrorCode errorCode, const hidl_vec<KeyParameter>& outParams,
+ OperationHandle operationHandle) {
+ _hidl_cb(static_cast<ErrorCode>(errorCode), outParams,
+ new Operation(operationHandle));
+ });
+ }
+
+ private:
+ void getVersionIfNeeded();
+
+ bool haveVersion_;
+ VersionResult version_;
+ sp<V4_0::IKeymasterDevice> km4_0_dev_;
+ sp<V4_1::IKeymasterDevice> km4_1_dev_;
+}; // namespace android::hardware::keymaster::V4_1::support
+
+} // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.1/support/include/keymasterV4_1/Operation.h b/keymaster/4.1/support/include/keymasterV4_1/Operation.h
new file mode 100644
index 0000000..902d49a
--- /dev/null
+++ b/keymaster/4.1/support/include/keymasterV4_1/Operation.h
@@ -0,0 +1,38 @@
+/*
+ ** Copyright 2020, 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.
+ */
+
+#pragma once
+
+#include <android/hardware/keymaster/4.1/IOperation.h>
+
+#include <keymasterV4_1/keymaster_tags.h>
+
+namespace android::hardware::keymaster::V4_1::support {
+
+class Operation : public IOperation {
+ public:
+ Operation(OperationHandle handle) : handle_(handle) {}
+
+ Return<void> getOperationChallenge(getOperationChallenge_cb _hidl_cb) override {
+ _hidl_cb(V4_1::ErrorCode::OK, handle_);
+ return Void();
+ }
+
+ private:
+ OperationHandle handle_;
+};
+
+} // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.1/support/include/keymasterV4_1/attestation_record.h b/keymaster/4.1/support/include/keymasterV4_1/attestation_record.h
new file mode 100644
index 0000000..b543bdd
--- /dev/null
+++ b/keymaster/4.1/support/include/keymasterV4_1/attestation_record.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2020 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.
+ */
+
+#pragma once
+
+#include <android/hardware/keymaster/4.1/IKeymasterDevice.h>
+#include <keymasterV4_0/attestation_record.h>
+#include <keymasterV4_0/openssl_utils.h>
+#include <keymasterV4_1/authorization_set.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_1 {
+
+using V4_0::kAttestionRecordOid;
+using V4_0::keymaster_verified_boot_t;
+
+struct RootOfTrust {
+ SecurityLevel security_level;
+ hidl_vec<uint8_t> verified_boot_key;
+ hidl_vec<uint8_t> verified_boot_hash;
+ keymaster_verified_boot_t verified_boot_state;
+ bool device_locked;
+};
+
+struct AttestationRecord {
+ RootOfTrust root_of_trust;
+ uint32_t attestation_version;
+ SecurityLevel attestation_security_level;
+ uint32_t keymaster_version;
+ SecurityLevel keymaster_security_level;
+ hidl_vec<uint8_t> attestation_challenge;
+ AuthorizationSet software_enforced;
+ AuthorizationSet hardware_enforced;
+ hidl_vec<uint8_t> unique_id;
+};
+
+std::tuple<ErrorCode, AttestationRecord> parse_attestation_record(const hidl_vec<uint8_t>& cert);
+
+} // namespace V4_1
+} // namespace keymaster
+} // namespace hardware
+} // namespace android
diff --git a/keymaster/4.1/support/include/keymasterV4_1/authorization_set.h b/keymaster/4.1/support/include/keymasterV4_1/authorization_set.h
index afc0eaf..01605b7 100644
--- a/keymaster/4.1/support/include/keymasterV4_1/authorization_set.h
+++ b/keymaster/4.1/support/include/keymasterV4_1/authorization_set.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_AUTHORIZATION_SET_H_
-#define HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_AUTHORIZATION_SET_H_
+#pragma once
#include <keymasterV4_0/authorization_set.h>
@@ -28,5 +27,3 @@
using V4_0::KeyParameter;
} // namespace android::hardware::keymaster::V4_1
-
-#endif // HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_AUTHORIZATION_SET_H_
diff --git a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
index 6ffe8e1..c5ce950 100644
--- a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
+++ b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
@@ -23,16 +23,26 @@
namespace android::hardware::keymaster::V4_1 {
+using V4_0::Algorithm;
using V4_0::BlockMode;
using V4_0::Digest;
using V4_0::EcCurve;
-using V4_0::ErrorCode;
+using V4_0::HardwareAuthenticatorType;
using V4_0::HardwareAuthToken;
+using V4_0::HmacSharingParameters;
+using V4_0::KeyBlobUsageRequirements;
+using V4_0::KeyCharacteristics;
+using V4_0::KeyFormat;
+using V4_0::KeyOrigin;
using V4_0::KeyParameter;
+using V4_0::KeyPurpose;
+using V4_0::OperationHandle;
using V4_0::PaddingMode;
+using V4_0::SecurityLevel;
using V4_0::TagType;
using V4_0::VerificationToken;
+using V4_0::NullOr;
using V4_0::TypedTag;
using V4_0::TAG_ACTIVE_DATETIME;
diff --git a/keymaster/4.1/support/include/keymasterV4_1/keymaster_utils.h b/keymaster/4.1/support/include/keymasterV4_1/keymaster_utils.h
new file mode 100644
index 0000000..2e28002
--- /dev/null
+++ b/keymaster/4.1/support/include/keymasterV4_1/keymaster_utils.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <keymasterV4_0/keymaster_utils.h>
+
+namespace android::hardware::keymaster::V4_1::support {
+
+using V4_0::support::blob2hidlVec;
+using V4_0::support::hidlVec2AuthToken;
+
+} // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.1/vts/functional/Android.bp b/keymaster/4.1/vts/functional/Android.bp
index f5a0c9c..c2d7fa3 100644
--- a/keymaster/4.1/vts/functional/Android.bp
+++ b/keymaster/4.1/vts/functional/Android.bp
@@ -19,12 +19,24 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: [
"EarlyBootKeyTest.cpp",
+ "DeviceUniqueAttestationTest.cpp",
+ "Keymaster4_1HidlTest.cpp",
+ "UnlockedDeviceRequiredTest.cpp",
],
static_libs: [
"android.hardware.keymaster@4.0",
"android.hardware.keymaster@4.1",
- "libkeymaster4support",
+ "libcrypto_static",
"libkeymaster4_1support",
+ "libkeymaster4support",
+ "libkeymaster4vtstest",
],
- test_suites: ["vts-core"],
+ cflags: [
+ "-Wall",
+ "-O0",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
}
diff --git a/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp b/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp
new file mode 100644
index 0000000..7ea3275
--- /dev/null
+++ b/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2020 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 "Keymaster4_1HidlTest.h"
+
+#include <cutils/properties.h>
+
+#include <openssl/x509.h>
+
+#include <keymasterV4_1/attestation_record.h>
+#include <keymasterV4_1/authorization_set.h>
+
+namespace android::hardware::keymaster::V4_0 {
+
+bool operator==(const AuthorizationSet& a, const AuthorizationSet& b) {
+ return std::equal(a.begin(), a.end(), b.begin(), b.end());
+}
+
+} // namespace android::hardware::keymaster::V4_0
+
+namespace android::hardware::keymaster::V4_1 {
+
+inline ::std::ostream& operator<<(::std::ostream& os, Tag tag) {
+ return os << toString(tag);
+}
+
+namespace test {
+
+using std::string;
+using std::tuple;
+
+namespace {
+
+char nibble2hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+string bin2hex(const hidl_vec<uint8_t>& data) {
+ string retval;
+ retval.reserve(data.size() * 2 + 1);
+ for (uint8_t byte : data) {
+ retval.push_back(nibble2hex[0x0F & (byte >> 4)]);
+ retval.push_back(nibble2hex[0x0F & byte]);
+ }
+ return retval;
+}
+
+struct AuthorizationSetDifferences {
+ string aName;
+ string bName;
+ AuthorizationSet aWhackB;
+ AuthorizationSet bWhackA;
+};
+
+std::ostream& operator<<(std::ostream& o, const AuthorizationSetDifferences& diffs) {
+ if (!diffs.aWhackB.empty()) {
+ o << "Set " << diffs.aName << " contains the following that " << diffs.bName << " does not"
+ << diffs.aWhackB;
+ if (!diffs.bWhackA.empty()) o << std::endl;
+ }
+
+ if (!diffs.bWhackA.empty()) {
+ o << "Set " << diffs.bName << " contains the following that " << diffs.aName << " does not"
+ << diffs.bWhackA;
+ }
+ return o;
+}
+
+// Computes and returns a \ b and b \ a ('\' is the set-difference operator, a \ b means all the
+// elements that are in a but not b, i.e. take a and whack all the elements in b) to the provided
+// stream. The sets must be sorted.
+//
+// This provides a simple and clear view of how the two sets differ, generally much
+// easier than scrutinizing printouts of the two sets.
+AuthorizationSetDifferences difference(string aName, const AuthorizationSet& a, string bName,
+ const AuthorizationSet& b) {
+ AuthorizationSetDifferences diffs = {std::move(aName), std::move(bName), {}, {}};
+ std::set_difference(a.begin(), a.end(), b.begin(), b.end(), std::back_inserter(diffs.aWhackB));
+ std::set_difference(b.begin(), b.end(), a.begin(), a.end(), std::back_inserter(diffs.bWhackA));
+ return diffs;
+}
+
+#define DIFFERENCE(a, b) difference(#a, a, #b, b)
+
+void check_root_of_trust(const RootOfTrust& root_of_trust) {
+ char vb_meta_device_state[PROPERTY_VALUE_MAX];
+ if (property_get("ro.boot.vbmeta.device_state", vb_meta_device_state, "") == 0) return;
+
+ char vb_meta_digest[PROPERTY_VALUE_MAX];
+ EXPECT_GT(property_get("ro.boot.vbmeta.digest", vb_meta_digest, ""), 0);
+ EXPECT_EQ(vb_meta_digest, bin2hex(root_of_trust.verified_boot_hash));
+
+ // Verified boot key should be all 0's if the boot state is not verified or self signed
+ HidlBuf empty_boot_key(string(32, '\0'));
+
+ char vb_meta_bootstate[PROPERTY_VALUE_MAX];
+ auto& verified_boot_key = root_of_trust.verified_boot_key;
+ auto& verified_boot_state = root_of_trust.verified_boot_state;
+ EXPECT_GT(property_get("ro.boot.verifiedbootstate", vb_meta_bootstate, ""), 0);
+ if (!strcmp(vb_meta_bootstate, "green")) {
+ EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_VERIFIED);
+ EXPECT_NE(verified_boot_key, empty_boot_key);
+ } else if (!strcmp(vb_meta_bootstate, "yellow")) {
+ EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_SELF_SIGNED);
+ EXPECT_NE(verified_boot_key, empty_boot_key);
+ } else if (!strcmp(vb_meta_bootstate, "orange")) {
+ EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_UNVERIFIED);
+ EXPECT_EQ(verified_boot_key, empty_boot_key);
+ } else if (!strcmp(vb_meta_bootstate, "red")) {
+ EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_FAILED);
+ } else {
+ EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_UNVERIFIED);
+ EXPECT_EQ(verified_boot_key, empty_boot_key);
+ }
+}
+
+void check_attestation_record(AttestationRecord attestation, const HidlBuf& challenge,
+ AuthorizationSet expected_sw_enforced,
+ AuthorizationSet expected_hw_enforced,
+ SecurityLevel expected_security_level) {
+ EXPECT_EQ(41U, attestation.keymaster_version);
+ EXPECT_EQ(4U, attestation.attestation_version);
+ EXPECT_EQ(expected_security_level, attestation.attestation_security_level);
+ EXPECT_EQ(expected_security_level, attestation.keymaster_security_level);
+ EXPECT_EQ(challenge, attestation.attestation_challenge);
+
+ check_root_of_trust(attestation.root_of_trust);
+
+ // Sort all of the authorization lists, so that equality matching works.
+ expected_sw_enforced.Sort();
+ expected_hw_enforced.Sort();
+ attestation.software_enforced.Sort();
+ attestation.hardware_enforced.Sort();
+
+ EXPECT_EQ(expected_sw_enforced, attestation.software_enforced)
+ << DIFFERENCE(expected_sw_enforced, attestation.software_enforced);
+ EXPECT_EQ(expected_hw_enforced, attestation.hardware_enforced)
+ << DIFFERENCE(expected_hw_enforced, attestation.hardware_enforced);
+}
+
+} // namespace
+
+using std::string;
+using DeviceUniqueAttestationTest = Keymaster4_1HidlTest;
+
+TEST_P(DeviceUniqueAttestationTest, StrongBoxOnly) {
+ if (SecLevel() != SecurityLevel::STRONGBOX) return;
+
+ ASSERT_EQ(ErrorCode::OK, convert(GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID))));
+
+ hidl_vec<hidl_vec<uint8_t>> cert_chain;
+ EXPECT_EQ(ErrorCode::UNIMPLEMENTED,
+ convert(AttestKey(
+ AuthorizationSetBuilder()
+ .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+ .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")),
+ &cert_chain)));
+ CheckedDeleteKey();
+
+ ASSERT_EQ(ErrorCode::OK, convert(GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID))));
+
+ EXPECT_EQ(ErrorCode::UNIMPLEMENTED,
+ convert(AttestKey(
+ AuthorizationSetBuilder()
+ .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")),
+ &cert_chain)));
+}
+
+TEST_P(DeviceUniqueAttestationTest, Rsa) {
+ if (SecLevel() != SecurityLevel::STRONGBOX) return;
+ ASSERT_EQ(ErrorCode::OK,
+ convert(GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
+ .Authorization(TAG_CREATION_DATETIME, 1))));
+
+ hidl_vec<hidl_vec<uint8_t>> cert_chain;
+ HidlBuf challenge("challenge");
+ HidlBuf app_id("foo");
+ EXPECT_EQ(ErrorCode::OK,
+ convert(AttestKey(AuthorizationSetBuilder()
+ .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+ .Authorization(TAG_ATTESTATION_CHALLENGE, challenge)
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
+ &cert_chain)));
+
+ EXPECT_EQ(1U, cert_chain.size());
+ auto [err, attestation] = parse_attestation_record(cert_chain[0]);
+ EXPECT_EQ(ErrorCode::OK, err);
+
+ check_attestation_record(attestation, challenge,
+ /* sw_enforced */
+ AuthorizationSetBuilder()
+ .Authorization(TAG_CREATION_DATETIME, 1)
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
+ /* hw_enforced */
+ AuthorizationSetBuilder()
+ .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
+ .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED)
+ .Authorization(TAG_OS_VERSION, os_version())
+ .Authorization(TAG_OS_PATCHLEVEL, os_patch_level()),
+ SecLevel());
+}
+
+TEST_P(DeviceUniqueAttestationTest, Ecdsa) {
+ if (SecLevel() != SecurityLevel::STRONGBOX) return;
+ ASSERT_EQ(ErrorCode::OK,
+ convert(GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(256)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_CREATION_DATETIME, 1))));
+
+ hidl_vec<hidl_vec<uint8_t>> cert_chain;
+ HidlBuf challenge("challenge");
+ HidlBuf app_id("foo");
+ EXPECT_EQ(ErrorCode::OK,
+ convert(AttestKey(AuthorizationSetBuilder()
+ .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+ .Authorization(TAG_ATTESTATION_CHALLENGE, challenge)
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
+ &cert_chain)));
+
+ EXPECT_EQ(1U, cert_chain.size());
+ auto [err, attestation] = parse_attestation_record(cert_chain[0]);
+ EXPECT_EQ(ErrorCode::OK, err);
+
+ check_attestation_record(attestation, challenge,
+ /* sw_enforced */
+ AuthorizationSetBuilder()
+ .Authorization(TAG_CREATION_DATETIME, 1)
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
+ /* hw_enforced */
+ AuthorizationSetBuilder()
+ .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(256)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_EC_CURVE, EcCurve::P_256)
+ .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED)
+ .Authorization(TAG_OS_VERSION, os_version())
+ .Authorization(TAG_OS_PATCHLEVEL, os_patch_level()),
+ SecLevel());
+}
+
+INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(DeviceUniqueAttestationTest);
+
+} // namespace test
+} // namespace android::hardware::keymaster::V4_1
diff --git a/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp b/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp
index 4a19010..a26c688 100644
--- a/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp
+++ b/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp
@@ -14,8 +14,78 @@
* limitations under the License.
*/
+#include "Keymaster4_1HidlTest.h"
+
+#include <keymasterV4_1/authorization_set.h>
+
namespace android::hardware::keymaster::V4_1::test {
-// TODO(swillden): Put tests here.
+using std::string;
+
+using EarlyBootKeyTest = Keymaster4_1HidlTest;
+
+// Because VTS tests are run on fully-booted machines, we can only run negative tests for early boot
+// keys, which cannot be created or used after /data is mounted. This is the only test we can run
+// in the normal case. The positive test will have to be done by the Android system, when it
+// creates/uses early boot keys during boot. It should fail to boot if the early boot key usage
+// fails.
+TEST_P(EarlyBootKeyTest, CannotCreateEarlyBootKeys) {
+ auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] =
+ CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::EARLY_BOOT_ENDED);
+
+ CheckedDeleteKeyData(&aesKeyData);
+ CheckedDeleteKeyData(&hmacKeyData);
+ CheckedDeleteKeyData(&rsaKeyData);
+ CheckedDeleteKeyData(&ecdsaKeyData);
+}
+
+// This is a more comprenhensive test, but it can only be run on a machine which is still in early
+// boot stage, which no proper Android device is by the time we can run VTS. To use this,
+// un-disable it and modify vold to remove the call to earlyBootEnded(). Running the test will end
+// early boot, so you'll have to reboot between runs.
+TEST_P(EarlyBootKeyTest, DISABLED_FullTest) {
+ // Should be able to create keys, since early boot has not ended
+ auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] =
+ CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::OK);
+
+ // TAG_EARLY_BOOT_ONLY should be in hw-enforced.
+ EXPECT_TRUE(contains(aesKeyData.characteristics.hardwareEnforced, TAG_EARLY_BOOT_ONLY));
+ EXPECT_TRUE(contains(hmacKeyData.characteristics.hardwareEnforced, TAG_EARLY_BOOT_ONLY));
+ EXPECT_TRUE(contains(rsaKeyData.characteristics.hardwareEnforced, TAG_EARLY_BOOT_ONLY));
+ EXPECT_TRUE(contains(ecdsaKeyData.characteristics.hardwareEnforced, TAG_EARLY_BOOT_ONLY));
+
+ // Should be able to use keys, since early boot has not ended
+ EXPECT_EQ(ErrorCode::OK, UseAesKey(aesKeyData.blob));
+ EXPECT_EQ(ErrorCode::OK, UseHmacKey(hmacKeyData.blob));
+ EXPECT_EQ(ErrorCode::OK, UseRsaKey(rsaKeyData.blob));
+ EXPECT_EQ(ErrorCode::OK, UseEcdsaKey(ecdsaKeyData.blob));
+
+ // End early boot
+ Return<ErrorCode> earlyBootResult = keymaster().earlyBootEnded();
+ EXPECT_TRUE(earlyBootResult.isOk());
+ EXPECT_EQ(earlyBootResult, ErrorCode::OK);
+
+ // Should not be able to use already-created keys.
+ EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseAesKey(aesKeyData.blob));
+ EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseHmacKey(hmacKeyData.blob));
+ EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseRsaKey(rsaKeyData.blob));
+ EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseEcdsaKey(ecdsaKeyData.blob));
+
+ CheckedDeleteKeyData(&aesKeyData);
+ CheckedDeleteKeyData(&hmacKeyData);
+ CheckedDeleteKeyData(&rsaKeyData);
+ CheckedDeleteKeyData(&ecdsaKeyData);
+
+ // Should not be able to create new keys
+ std::tie(aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData) =
+ CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::EARLY_BOOT_ENDED);
+
+ CheckedDeleteKeyData(&aesKeyData);
+ CheckedDeleteKeyData(&hmacKeyData);
+ CheckedDeleteKeyData(&rsaKeyData);
+ CheckedDeleteKeyData(&ecdsaKeyData);
+}
+
+INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(EarlyBootKeyTest);
} // namespace android::hardware::keymaster::V4_1::test
diff --git a/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.cpp b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.cpp
new file mode 100644
index 0000000..efedf28
--- /dev/null
+++ b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 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 "Keymaster4_1HidlTest.h"
+
+namespace android::hardware::keymaster::V4_1::test {
+
+using std::string;
+
+void Keymaster4_1HidlTest::SetUp() {
+ keymaster41_ = IKeymasterDevice::getService(GetParam());
+ InitializeKeymaster(keymaster41_);
+}
+
+auto Keymaster4_1HidlTest::ProcessMessage(const HidlBuf& key_blob, KeyPurpose operation,
+ const string& message, const AuthorizationSet& in_params)
+ -> std::tuple<ErrorCode, string, AuthorizationSet /* out_params */> {
+ AuthorizationSet begin_out_params;
+ V4_0::ErrorCode result = Begin(operation, key_blob, in_params, &begin_out_params, &op_handle_);
+ AuthorizationSet out_params(std::move(begin_out_params));
+ if (result != V4_0::ErrorCode::OK) {
+ return {convert(result), {}, out_params};
+ }
+
+ string output;
+ size_t consumed = 0;
+ AuthorizationSet update_params;
+ AuthorizationSet update_out_params;
+ result = Update(op_handle_, update_params, message, &update_out_params, &output, &consumed);
+ out_params.push_back(update_out_params);
+ if (result != V4_0::ErrorCode::OK) {
+ return {convert(result), output, out_params};
+ }
+
+ string unused;
+ AuthorizationSet finish_params;
+ AuthorizationSet finish_out_params;
+ result = Finish(op_handle_, finish_params, message.substr(consumed), unused, &finish_out_params,
+ &output);
+ op_handle_ = V4_0::test::kOpHandleSentinel;
+ out_params.push_back(finish_out_params);
+
+ return {convert(result), output, out_params};
+}
+
+} // namespace android::hardware::keymaster::V4_1::test
diff --git a/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h
new file mode 100644
index 0000000..6332c43
--- /dev/null
+++ b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#pragma once
+
+#include <android/hardware/keymaster/4.1/IKeymasterDevice.h>
+
+#include <KeymasterHidlTest.h>
+#include <keymasterV4_1/authorization_set.h>
+
+namespace android::hardware::keymaster::V4_1::test {
+
+using V4_0::test::HidlBuf;
+
+class Keymaster4_1HidlTest : public V4_0::test::KeymasterHidlTest {
+ public:
+ using super = V4_0::test::KeymasterHidlTest;
+
+ ErrorCode convert(V4_0::ErrorCode error_code) { return static_cast<ErrorCode>(error_code); }
+
+ // These methods hide the base class versions.
+ void SetUp();
+ IKeymasterDevice& keymaster() { return *keymaster41_; };
+
+ struct KeyData {
+ HidlBuf blob;
+ KeyCharacteristics characteristics;
+ };
+
+ std::tuple<ErrorCode, KeyData> GenerateKeyData(const AuthorizationSet& keyDescription) {
+ KeyData keyData;
+ ErrorCode errorCode = convert(
+ super::GenerateKey(keyDescription, &keyData.blob, &keyData.characteristics));
+ return {errorCode, keyData};
+ }
+
+ void CheckedDeleteKeyData(KeyData* keyData) { CheckedDeleteKey(&keyData->blob); }
+
+ template <typename TagType>
+ std::tuple<KeyData /* aesKey */, KeyData /* hmacKey */, KeyData /* rsaKey */,
+ KeyData /* ecdsaKey */>
+ CreateTestKeys(TagType tagToTest, ErrorCode expectedReturn) {
+ ErrorCode errorCode;
+
+ /* AES */
+ KeyData aesKeyData;
+ std::tie(errorCode, aesKeyData) =
+ GenerateKeyData(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(tagToTest)
+ .BlockMode(BlockMode::ECB)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED));
+ EXPECT_EQ(expectedReturn, errorCode);
+
+ /* HMAC */
+ KeyData hmacKeyData;
+ std::tie(errorCode, hmacKeyData) =
+ GenerateKeyData(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Authorization(tagToTest)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)
+ .Authorization(TAG_NO_AUTH_REQUIRED));
+ EXPECT_EQ(expectedReturn, errorCode);
+
+ /* RSA */
+ KeyData rsaKeyData;
+ std::tie(errorCode, rsaKeyData) =
+ GenerateKeyData(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Authorization(tagToTest)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED));
+ EXPECT_EQ(expectedReturn, errorCode);
+
+ /* ECDSA */
+ KeyData ecdsaKeyData;
+ std::tie(errorCode, ecdsaKeyData) =
+ GenerateKeyData(AuthorizationSetBuilder()
+ .EcdsaSigningKey(256)
+ .Authorization(tagToTest)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_NO_AUTH_REQUIRED));
+ EXPECT_EQ(expectedReturn, errorCode);
+
+ return {aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData};
+ }
+
+ std::tuple<ErrorCode, std::string /* processedMessage */, AuthorizationSet /* out_params */>
+ ProcessMessage(const HidlBuf& key_blob, KeyPurpose operation, const std::string& message,
+ const AuthorizationSet& in_params);
+
+ ErrorCode UseAesKey(const HidlBuf& aesKeyBlob) {
+ auto [result, ciphertext, out_params] = ProcessMessage(
+ aesKeyBlob, KeyPurpose::ENCRYPT, "1234567890123456",
+ AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE));
+ return result;
+ }
+
+ ErrorCode UseHmacKey(const HidlBuf& hmacKeyBlob) {
+ auto [result, mac, out_params] =
+ ProcessMessage(hmacKeyBlob, KeyPurpose::SIGN, "1234567890123456",
+ AuthorizationSetBuilder().Authorization(TAG_MAC_LENGTH, 128));
+ return result;
+ }
+
+ ErrorCode UseRsaKey(const HidlBuf& rsaKeyBlob) {
+ std::string message(2048 / 8, 'a');
+ auto [result, signature, out_params] = ProcessMessage(
+ rsaKeyBlob, KeyPurpose::SIGN, message,
+ AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+ return result;
+ }
+
+ ErrorCode UseEcdsaKey(const HidlBuf& ecdsaKeyBlob) {
+ auto [result, signature, out_params] =
+ ProcessMessage(ecdsaKeyBlob, KeyPurpose::SIGN, "a",
+ AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
+ return result;
+ }
+
+ static std::vector<std::string> build_params() {
+ auto params = android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor);
+ return params;
+ }
+
+ private:
+ sp<IKeymasterDevice> keymaster41_;
+};
+
+template <typename TypedTag>
+bool contains(hidl_vec<KeyParameter>& set, TypedTag typedTag) {
+ return std::find_if(set.begin(), set.end(), [&](const KeyParameter& param) {
+ return param.tag == static_cast<V4_0::Tag>(typedTag);
+ }) != set.end();
+}
+
+#define INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(name) \
+ INSTANTIATE_TEST_SUITE_P(PerInstance, name, \
+ testing::ValuesIn(Keymaster4_1HidlTest::build_params()), \
+ android::hardware::PrintInstanceNameToString)
+
+} // namespace android::hardware::keymaster::V4_1::test
diff --git a/keymaster/4.1/vts/functional/UnlockedDeviceRequiredTest.cpp b/keymaster/4.1/vts/functional/UnlockedDeviceRequiredTest.cpp
new file mode 100644
index 0000000..671bbbf
--- /dev/null
+++ b/keymaster/4.1/vts/functional/UnlockedDeviceRequiredTest.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 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 "Keymaster4_1HidlTest.h"
+
+#include <keymasterV4_1/authorization_set.h>
+
+namespace android::hardware::keymaster::V4_1::test {
+
+using UnlockedDeviceRequiredTest = Keymaster4_1HidlTest;
+
+// This may be a problematic test. It can't be run repeatedly without unlocking the device in
+// between runs... and on most test devices there are no enrolled credentials so it can't be
+// unlocked at all, meaning the only way to get the test to pass again on a properly-functioning
+// device is to reboot it. For that reason, this is disabled by default. It can be used as part of
+// a manual test process, which includes unlocking between runs, which is why it's included here.
+// Well, that and the fact that it's the only test we can do without also making calls into the
+// Gatekeeper HAL. We haven't written any cross-HAL tests, and don't know what all of the
+// implications might be, so that may or may not be a solution.
+//
+// TODO(swillden): Use the Gatekeeper HAL to enroll some test credentials which we can verify to get
+// an unlock auth token. If that works, enable the improved test.
+TEST_P(UnlockedDeviceRequiredTest, DISABLED_KeysBecomeUnusable) {
+ auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] =
+ CreateTestKeys(TAG_UNLOCKED_DEVICE_REQUIRED, ErrorCode::OK);
+
+ EXPECT_EQ(ErrorCode::OK, UseAesKey(aesKeyData.blob));
+ EXPECT_EQ(ErrorCode::OK, UseHmacKey(hmacKeyData.blob));
+ EXPECT_EQ(ErrorCode::OK, UseRsaKey(rsaKeyData.blob));
+ EXPECT_EQ(ErrorCode::OK, UseEcdsaKey(ecdsaKeyData.blob));
+
+ Return<ErrorCode> rc =
+ keymaster().deviceLocked(false /* passwordOnly */, {} /* verificationToken */);
+ ASSERT_TRUE(rc.isOk());
+ ASSERT_EQ(ErrorCode::OK, static_cast<ErrorCode>(rc));
+
+ EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseAesKey(aesKeyData.blob));
+ EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseHmacKey(hmacKeyData.blob));
+ EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseRsaKey(rsaKeyData.blob));
+ EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseEcdsaKey(ecdsaKeyData.blob));
+
+ CheckedDeleteKeyData(&aesKeyData);
+ CheckedDeleteKeyData(&hmacKeyData);
+ CheckedDeleteKeyData(&rsaKeyData);
+ CheckedDeleteKeyData(&ecdsaKeyData);
+}
+
+INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(UnlockedDeviceRequiredTest);
+
+} // namespace android::hardware::keymaster::V4_1::test
diff --git a/neuralnetworks/1.3/IDevice.hal b/neuralnetworks/1.3/IDevice.hal
index 9afd778..8dc41f7 100644
--- a/neuralnetworks/1.3/IDevice.hal
+++ b/neuralnetworks/1.3/IDevice.hal
@@ -48,9 +48,14 @@
/**
* Gets the supported operations in a model.
*
- * getSupportedOperations indicates which operations of a model are fully
- * supported by the vendor driver. If an operation may not be supported for
- * any reason, getSupportedOperations must return false for that operation.
+ * getSupportedOperations indicates which operations of the top-level
+ * subgraph are fully supported by the vendor driver. If an operation may
+ * not be supported for any reason, getSupportedOperations must return
+ * false for that operation.
+ *
+ * The {@link OperationType::IF} and {@link OperationType::WHILE}
+ * operations may only be fully supported if the vendor driver fully
+ * supports all operations in the referenced subgraphs.
*
* @param model A model whose operations--and their corresponding operands--
* are to be verified by the driver.
diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal
index 6c8fe43..a6d274a 100644
--- a/neuralnetworks/1.3/types.hal
+++ b/neuralnetworks/1.3/types.hal
@@ -17,9 +17,10 @@
package android.hardware.neuralnetworks@1.3;
import @1.0::DataLocation;
-import @1.0::OperandLifeTime;
import @1.0::PerformanceInfo;
import @1.0::RequestArgument;
+import @1.2::Model.ExtensionNameAndPrefix;
+import @1.2::Model.ExtensionTypeEncoding;
import @1.2::OperandType;
import @1.2::OperationType;
import @1.2::SymmPerChannelQuantParams;
@@ -40,6 +41,13 @@
*/
TENSOR_QUANT8_ASYMM_SIGNED = 14,
+ /**
+ * A reference to a subgraph.
+ *
+ * Must have the lifetime {@link OperandLifeTime::SUBGRAPH}.
+ */
+ SUBGRAPH = 15,
+
/*
* DEPRECATED. Since HAL version 1.2, extensions are the preferred
* alternative to OEM operation and data types.
@@ -68,7 +76,7 @@
enum OperandTypeRange : uint32_t {
BASE_MIN = 0,
FUNDAMENTAL_MIN = 0,
- FUNDAMENTAL_MAX = 14,
+ FUNDAMENTAL_MAX = 15,
OEM_MIN = 10000,
OEM_MAX = 10001,
BASE_MAX = 0xFFFF,
@@ -4877,6 +4885,92 @@
QUANTIZED_LSTM = 95,
/**
+ * Executes one of the two referenced subgraphs as determined by a boolean
+ * value.
+ *
+ * The inputs and outputs of the two referenced subgraphs must agree with the
+ * signature of this operation. That is, if the operation has (3 + n) inputs
+ * and m outputs, both subgraphs must have n inputs and m outputs with the same
+ * types as the corresponding operation inputs and outputs.
+ *
+ * Inputs:
+ * * 0: A value of type {@link OperandType::TENSOR_BOOL8} and shape [1]
+ * that determines which of the two referenced subgraphs to execute.
+ * * 1: A {@link OperandType::SUBGRAPH} reference to the subgraph to be
+ * executed if the condition is true.
+ * * 2: A {@link OperandType::SUBGRAPH} reference to the subgraph to be
+ * executed if the condition is false.
+ * * 3 ~ (n + 2): Inputs to be passed to the subgraph selected for execution.
+ *
+ * Outputs:
+ * * 0 ~ (m - 1): Outputs produced by the selected subgraph.
+ */
+ IF = 96,
+
+ /**
+ * Executes the body subgraph until the condition subgraph outputs false.
+ *
+ * The inputs to this operation are the condition subgraph, the body subgraph,
+ * and operand values for the first iteration of the loop. The values are
+ * implicitly split into three groups of input-output, state-only, and
+ * input-only values, as described below.
+ *
+ * The outputs of this operation are the final values of input-output
+ * operands.
+ *
+ * Both the condition and body subgraph receive (m + k + n) inputs.
+ * * The first m (m >= 1) inputs are input-output operands. For the first
+ * iteration, these are initialized from the corresponding inputs of the
+ * WHILE operation. In subsequent iterations, their values come from the
+ * corresponding outputs of the body subgraph produced during the previous
+ * iteration.
+ * * The next k (k >= 0) inputs are state-only operands. They are similar to
+ * the input-output operands, except that their values are no longer
+ * available after the loop terminates.
+ * * The last n (n >= 0) inputs are input-only operands. Their values come
+ * from the corresponding inputs of the WHILE operation.
+ *
+ * The body subgraph produces (m + k) outputs.
+ * * The first m outputs are input-output operands. They become the outputs
+ * of the WHILE operation when a termination condition is reached.
+ * * The last k outputs are state-only operands. Their values are no longer
+ * available after the loop terminates.
+ *
+ * The numbers m, k, and n are inferred by the driver as follows:
+ * m = (WHILE operation output count)
+ * k = (body subgraph output count) - m
+ * n = (body subgraph input count) - m - k
+ *
+ * The pseudo-code below illustrates the flow of a WHILE operation with
+ * inputs condition, body, initial_input_output, initial_state, input_only
+ * (m = 1, k = 1, n = 1):
+ *
+ * input_output = initial_input_output
+ * state = initial_state
+ * while condition(input_output, state, input_only):
+ * input_output, state = body(input_output, state, input_only)
+ * return input_output
+ *
+ * Inputs:
+ * * 0: A {@link OperandType::SUBGRAPH} reference to the condition
+ * subgraph. The subgraph must have (m + k + n) inputs with
+ * the same types as the corresponding inputs of the WHILE operation
+ * and exactly one output of {@link OperandType::TENSOR_BOOL8}
+ * and shape [1].
+ * * 1: A {@link OperandType::SUBGRAPH} reference to the body subgraph.
+ * The subgraph must have (m + k + n) inputs and (m + k) outputs with
+ * the same types as the corresponding inputs and outputs of the WHILE
+ * operation.
+ * * (m inputs): Initial values for input-output operands.
+ * * (k inputs): Initial values for state-only operands.
+ * * (n inputs): Values for input-only operands.
+ *
+ * Outputs:
+ * * 0 ~ (m - 1): Outputs produced by the loop.
+ */
+ WHILE = 97,
+
+ /**
* DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to
* OEM operation and data types.
*
@@ -4898,13 +4992,12 @@
enum OperationTypeRange : uint32_t {
BASE_MIN = 0,
FUNDAMENTAL_MIN = 0,
- FUNDAMENTAL_MAX = 95,
+ FUNDAMENTAL_MAX = 97,
OEM_MIN = 10000,
OEM_MAX = 10000,
BASE_MAX = 0xFFFF,
};
-
/**
* The capabilities of a driver.
*
@@ -4966,6 +5059,59 @@
};
/**
+ * How an operand is used.
+ */
+enum OperandLifeTime : int32_t {
+ /**
+ * The operand is internal to the model. It's created by an operation and
+ * consumed by other operations. It must be an output operand of
+ * exactly one operation.
+ */
+ TEMPORARY_VARIABLE,
+
+ /**
+ * The operand is an input of a subgraph. It must not be an output
+ * operand of any operation.
+ *
+ * An operand can't be both input and output of a subgraph.
+ */
+ SUBGRAPH_INPUT,
+
+ /**
+ * The operand is an output of a subgraph. It must be an output
+ * operand of exactly one operation.
+ *
+ * An operand can't be both input and output of a subgraph.
+ */
+ SUBGRAPH_OUTPUT,
+
+ /**
+ * The operand is a constant found in Model.operandValues. It must
+ * not be an output operand of any operation.
+ */
+ CONSTANT_COPY,
+
+ /**
+ * The operand is a constant that was specified via a Memory
+ * object. It must not be an output operand of any operation.
+ */
+ CONSTANT_REFERENCE,
+
+ /**
+ * The operand does not have a value. This is valid only for optional
+ * arguments of operations.
+ */
+ NO_VALUE,
+
+ /**
+ * The operand is a reference to a subgraph. It must be an input to one
+ * or more {@link OperationType::IF} or {@link OperationType::WHILE}
+ * operations.
+ */
+ SUBGRAPH,
+};
+
+/**
* Describes one operand of the model's graph.
*/
struct Operand {
@@ -5001,7 +5147,7 @@
* . The operand has lifetime CONSTANT_COPY or
* CONSTANT_REFERENCE.
*
- * . The operand has lifetime MODEL_INPUT. Fully
+ * . The operand has lifetime SUBGRAPH_INPUT. Fully
* specified dimensions must either be present in the
* Operand or they must be provided in the corresponding
* RequestArgument.
@@ -5049,8 +5195,8 @@
/**
* Where to find the data for this operand.
- * If the lifetime is TEMPORARY_VARIABLE, MODEL_INPUT, MODEL_OUTPUT, or
- * NO_VALUE:
+ * If the lifetime is TEMPORARY_VARIABLE, SUBGRAPH_INPUT, SUBGRAPH_OUTPUT,
+ * or NO_VALUE:
* - All the fields must be 0.
* If the lifetime is CONSTANT_COPY:
* - location.poolIndex is 0.
@@ -5060,6 +5206,11 @@
* - location.poolIndex is set.
* - location.offset is the offset in bytes into the specified pool.
* - location.length is set.
+ * If the lifetime is SUBGRAPH:
+ * - location.poolIndex is 0.
+ * - location.offset is the index of the referenced subgraph in
+ * {@link Model::referenced}.
+ * - location.length is 0.
*/
DataLocation location;
@@ -5098,32 +5249,19 @@
*/
struct Model {
/**
- * All operands included in the model.
+ * The top-level subgraph.
*/
- vec<Operand> operands;
+ Subgraph main;
/**
- * All operations included in the model.
+ * Referenced subgraphs.
*
- * The operations are sorted into execution order. Every operand
- * with lifetime MODEL_OUTPUT or TEMPORARY_VARIABLE must be
- * written before it is read.
- */
- vec<Operation> operations;
-
- /**
- * Input indexes of the model. There must be at least one.
+ * Each subgraph is referenced by the main subgraph or at least one other
+ * referenced subgraph.
*
- * Each value corresponds to the index of the operand in "operands".
+ * There must be no reference cycles.
*/
- vec<uint32_t> inputIndexes;
-
- /**
- * Output indexes of the model. There must be at least one.
- *
- * Each value corresponds to the index of the operand in "operands".
- */
- vec<uint32_t> outputIndexes;
+ vec<Subgraph> referenced;
/**
* A byte buffer containing operand data that were copied into the model.
@@ -5157,9 +5295,9 @@
* {@link OperandTypeRange::BASE_MAX} or
* {@link OperationTypeRange::BASE_MAX} respectively should be interpreted
* as an extension operand. The low
- * {@link Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the value
- * correspond to the type ID within the extension and the high
- * {@link Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode
+ * {@link @1.2::Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the
+ * value correspond to the type ID within the extension and the high
+ * {@link @1.2::Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode
* the "prefix", which maps uniquely to the extension name.
*
* For example, if a model contains an operation whose value is
@@ -5172,39 +5310,40 @@
* prefix corresponding to each extension name and at most one extension
* name corresponding to each prefix.
*/
- vec<ExtensionNameAndPrefix> extensionNameToPrefix;
+ vec<@1.2::Model.ExtensionNameAndPrefix> extensionNameToPrefix;
+};
+
+/**
+ * An excerpt of the execution graph.
+ */
+struct Subgraph {
+ /**
+ * All operands included in the subgraph.
+ */
+ vec<Operand> operands;
/**
- * A correspondence between an extension name and a prefix of operand and
- * operation type values.
+ * All operations included in the subgraph.
+ *
+ * The operations are sorted into execution order. Every operand
+ * with lifetime SUBGRAPH_OUTPUT or TEMPORARY_VARIABLE must be
+ * written before it is read.
*/
- struct ExtensionNameAndPrefix {
- /**
- * The extension name.
- *
- * See {@link Extension::name} for the format specification.
- */
- string name;
-
- /**
- * The unique extension identifier within the model.
- *
- * See {@link Model::extensionNameToPrefix}.
- */
- uint16_t prefix;
- };
+ vec<Operation> operations;
/**
- * Numeric values of extension operand and operation types have the
- * following structure:
- * - 16 high bits represent the "prefix", which corresponds uniquely to the
- * extension name.
- * - 16 low bits represent the type ID within the extension.
+ * Input indexes of the subgraph. There must be at least one.
+ *
+ * Each value corresponds to the index of the operand in "operands".
*/
- enum ExtensionTypeEncoding : uint8_t {
- HIGH_BITS_PREFIX = 16,
- LOW_BITS_TYPE = 16,
- };
+ vec<uint32_t> inputIndexes;
+
+ /**
+ * Output indexes of the subgraph. There must be at least one.
+ *
+ * Each value corresponds to the index of the operand in "operands".
+ */
+ vec<uint32_t> outputIndexes;
};
/**
diff --git a/neuralnetworks/1.3/types.t b/neuralnetworks/1.3/types.t
index b1c72a9..f3319e5 100644
--- a/neuralnetworks/1.3/types.t
+++ b/neuralnetworks/1.3/types.t
@@ -19,9 +19,10 @@
package android.hardware.neuralnetworks@1.3;
import @1.0::DataLocation;
-import @1.0::OperandLifeTime;
import @1.0::PerformanceInfo;
import @1.0::RequestArgument;
+import @1.2::Model.ExtensionNameAndPrefix;
+import @1.2::Model.ExtensionTypeEncoding;
import @1.2::OperandType;
import @1.2::OperationType;
import @1.2::SymmPerChannelQuantParams;
@@ -88,7 +89,6 @@
BASE_MAX = 0xFFFF,
};
-
/**
* The capabilities of a driver.
*
@@ -150,6 +150,59 @@
};
/**
+ * How an operand is used.
+ */
+enum OperandLifeTime : int32_t {
+ /**
+ * The operand is internal to the model. It's created by an operation and
+ * consumed by other operations. It must be an output operand of
+ * exactly one operation.
+ */
+ TEMPORARY_VARIABLE,
+
+ /**
+ * The operand is an input of a subgraph. It must not be an output
+ * operand of any operation.
+ *
+ * An operand can't be both input and output of a subgraph.
+ */
+ SUBGRAPH_INPUT,
+
+ /**
+ * The operand is an output of a subgraph. It must be an output
+ * operand of exactly one operation.
+ *
+ * An operand can't be both input and output of a subgraph.
+ */
+ SUBGRAPH_OUTPUT,
+
+ /**
+ * The operand is a constant found in Model.operandValues. It must
+ * not be an output operand of any operation.
+ */
+ CONSTANT_COPY,
+
+ /**
+ * The operand is a constant that was specified via a Memory
+ * object. It must not be an output operand of any operation.
+ */
+ CONSTANT_REFERENCE,
+
+ /**
+ * The operand does not have a value. This is valid only for optional
+ * arguments of operations.
+ */
+ NO_VALUE,
+
+ /**
+ * The operand is a reference to a subgraph. It must be an input to one
+ * or more {@link OperationType::IF} or {@link OperationType::WHILE}
+ * operations.
+ */
+ SUBGRAPH,
+};
+
+/**
* Describes one operand of the model's graph.
*/
struct Operand {
@@ -185,7 +238,7 @@
* . The operand has lifetime CONSTANT_COPY or
* CONSTANT_REFERENCE.
*
- * . The operand has lifetime MODEL_INPUT. Fully
+ * . The operand has lifetime SUBGRAPH_INPUT. Fully
* specified dimensions must either be present in the
* Operand or they must be provided in the corresponding
* RequestArgument.
@@ -233,8 +286,8 @@
/**
* Where to find the data for this operand.
- * If the lifetime is TEMPORARY_VARIABLE, MODEL_INPUT, MODEL_OUTPUT, or
- * NO_VALUE:
+ * If the lifetime is TEMPORARY_VARIABLE, SUBGRAPH_INPUT, SUBGRAPH_OUTPUT,
+ * or NO_VALUE:
* - All the fields must be 0.
* If the lifetime is CONSTANT_COPY:
* - location.poolIndex is 0.
@@ -244,6 +297,11 @@
* - location.poolIndex is set.
* - location.offset is the offset in bytes into the specified pool.
* - location.length is set.
+ * If the lifetime is SUBGRAPH:
+ * - location.poolIndex is 0.
+ * - location.offset is the index of the referenced subgraph in
+ * {@link Model::referenced}.
+ * - location.length is 0.
*/
DataLocation location;
@@ -282,32 +340,19 @@
*/
struct Model {
/**
- * All operands included in the model.
+ * The top-level subgraph.
*/
- vec<Operand> operands;
+ Subgraph main;
/**
- * All operations included in the model.
+ * Referenced subgraphs.
*
- * The operations are sorted into execution order. Every operand
- * with lifetime MODEL_OUTPUT or TEMPORARY_VARIABLE must be
- * written before it is read.
- */
- vec<Operation> operations;
-
- /**
- * Input indexes of the model. There must be at least one.
+ * Each subgraph is referenced by the main subgraph or at least one other
+ * referenced subgraph.
*
- * Each value corresponds to the index of the operand in "operands".
+ * There must be no reference cycles.
*/
- vec<uint32_t> inputIndexes;
-
- /**
- * Output indexes of the model. There must be at least one.
- *
- * Each value corresponds to the index of the operand in "operands".
- */
- vec<uint32_t> outputIndexes;
+ vec<Subgraph> referenced;
/**
* A byte buffer containing operand data that were copied into the model.
@@ -341,9 +386,9 @@
* {@link OperandTypeRange::BASE_MAX} or
* {@link OperationTypeRange::BASE_MAX} respectively should be interpreted
* as an extension operand. The low
- * {@link Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the value
- * correspond to the type ID within the extension and the high
- * {@link Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode
+ * {@link @1.2::Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the
+ * value correspond to the type ID within the extension and the high
+ * {@link @1.2::Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode
* the "prefix", which maps uniquely to the extension name.
*
* For example, if a model contains an operation whose value is
@@ -356,39 +401,40 @@
* prefix corresponding to each extension name and at most one extension
* name corresponding to each prefix.
*/
- vec<ExtensionNameAndPrefix> extensionNameToPrefix;
+ vec<@1.2::Model.ExtensionNameAndPrefix> extensionNameToPrefix;
+};
+
+/**
+ * An excerpt of the execution graph.
+ */
+struct Subgraph {
+ /**
+ * All operands included in the subgraph.
+ */
+ vec<Operand> operands;
/**
- * A correspondence between an extension name and a prefix of operand and
- * operation type values.
+ * All operations included in the subgraph.
+ *
+ * The operations are sorted into execution order. Every operand
+ * with lifetime SUBGRAPH_OUTPUT or TEMPORARY_VARIABLE must be
+ * written before it is read.
*/
- struct ExtensionNameAndPrefix {
- /**
- * The extension name.
- *
- * See {@link Extension::name} for the format specification.
- */
- string name;
-
- /**
- * The unique extension identifier within the model.
- *
- * See {@link Model::extensionNameToPrefix}.
- */
- uint16_t prefix;
- };
+ vec<Operation> operations;
/**
- * Numeric values of extension operand and operation types have the
- * following structure:
- * - 16 high bits represent the "prefix", which corresponds uniquely to the
- * extension name.
- * - 16 low bits represent the type ID within the extension.
+ * Input indexes of the subgraph. There must be at least one.
+ *
+ * Each value corresponds to the index of the operand in "operands".
*/
- enum ExtensionTypeEncoding : uint8_t {
- HIGH_BITS_PREFIX = 16,
- LOW_BITS_TYPE = 16,
- };
+ vec<uint32_t> inputIndexes;
+
+ /**
+ * Output indexes of the subgraph. There must be at least one.
+ *
+ * Each value corresponds to the index of the operand in "operands".
+ */
+ vec<uint32_t> outputIndexes;
};
/**
diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
index fe8d907..5cb466f 100644
--- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
@@ -308,7 +308,7 @@
model,
[&fullySupportsModel, &model](ErrorStatus status, const hidl_vec<bool>& supported) {
ASSERT_EQ(ErrorStatus::NONE, status);
- ASSERT_EQ(supported.size(), model.operations.size());
+ ASSERT_EQ(supported.size(), model.main.operations.size());
fullySupportsModel = std::all_of(supported.begin(), supported.end(),
[](bool valid) { return valid; });
});
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
index 4f747f4..805d5b5 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
@@ -59,7 +59,6 @@
using implementation::PreparedModelCallback;
using V1_0::DataLocation;
using V1_0::ErrorStatus;
-using V1_0::OperandLifeTime;
using V1_0::RequestArgument;
using V1_1::ExecutionPreference;
using V1_2::Constant;
@@ -269,10 +268,10 @@
}
}
- return {.operands = std::move(operands),
- .operations = std::move(operations),
- .inputIndexes = testModel.inputIndexes,
- .outputIndexes = testModel.outputIndexes,
+ return {.main = {.operands = std::move(operands),
+ .operations = std::move(operations),
+ .inputIndexes = testModel.inputIndexes,
+ .outputIndexes = testModel.outputIndexes},
.operandValues = std::move(operandValues),
.pools = std::move(pools),
.relaxComputationFloat32toFloat16 = testModel.isRelaxed};
@@ -290,8 +289,8 @@
}
static void makeOutputDimensionsUnspecified(Model* model) {
- for (auto i : model->outputIndexes) {
- auto& dims = model->operands[i].dimensions;
+ for (auto i : model->main.outputIndexes) {
+ auto& dims = model->main.operands[i].dimensions;
std::fill(dims.begin(), dims.end(), 0);
}
}
diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
index 8395111..cc86264 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
@@ -25,7 +25,6 @@
using implementation::PreparedModelCallback;
using V1_0::ErrorStatus;
-using V1_0::OperandLifeTime;
using V1_1::ExecutionPreference;
using V1_2::SymmPerChannelQuantParams;
using HidlToken =
@@ -83,22 +82,22 @@
}
static uint32_t addOperand(Model* model) {
- return hidl_vec_push_back(&model->operands,
+ return hidl_vec_push_back(&model->main.operands,
{
.type = OperandType::INT32,
.dimensions = {},
.numberOfConsumers = 0,
.scale = 0.0f,
.zeroPoint = 0,
- .lifetime = OperandLifeTime::MODEL_INPUT,
+ .lifetime = OperandLifeTime::SUBGRAPH_INPUT,
.location = {.poolIndex = 0, .offset = 0, .length = 0},
});
}
static uint32_t addOperand(Model* model, OperandLifeTime lifetime) {
uint32_t index = addOperand(model);
- model->operands[index].numberOfConsumers = 1;
- model->operands[index].lifetime = lifetime;
+ model->main.operands[index].numberOfConsumers = 1;
+ model->main.operands[index].lifetime = lifetime;
return index;
}
@@ -112,13 +111,13 @@
};
static void mutateOperandTypeTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+ for (size_t operand = 0; operand < model.main.operands.size(); ++operand) {
for (uint32_t invalidOperandType : invalidOperandTypes) {
const std::string message = "mutateOperandTypeTest: operand " +
std::to_string(operand) + " set to value " +
std::to_string(invalidOperandType);
validate(device, message, model, [operand, invalidOperandType](Model* model) {
- model->operands[operand].type = static_cast<OperandType>(invalidOperandType);
+ model->main.operands[operand].type = static_cast<OperandType>(invalidOperandType);
});
}
}
@@ -150,15 +149,15 @@
}
static void mutateOperandRankTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operand = 0; operand < model.operands.size(); ++operand) {
- const uint32_t invalidRank = getInvalidRank(model.operands[operand].type);
+ for (size_t operand = 0; operand < model.main.operands.size(); ++operand) {
+ const uint32_t invalidRank = getInvalidRank(model.main.operands[operand].type);
if (invalidRank == 0) {
continue;
}
const std::string message = "mutateOperandRankTest: operand " + std::to_string(operand) +
" has rank of " + std::to_string(invalidRank);
validate(device, message, model, [operand, invalidRank](Model* model) {
- model->operands[operand].dimensions = std::vector<uint32_t>(invalidRank, 0);
+ model->main.operands[operand].dimensions = std::vector<uint32_t>(invalidRank, 0);
});
}
}
@@ -190,12 +189,12 @@
}
static void mutateOperandScaleTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operand = 0; operand < model.operands.size(); ++operand) {
- const float invalidScale = getInvalidScale(model.operands[operand].type);
+ for (size_t operand = 0; operand < model.main.operands.size(); ++operand) {
+ const float invalidScale = getInvalidScale(model.main.operands[operand].type);
const std::string message = "mutateOperandScaleTest: operand " + std::to_string(operand) +
" has scale of " + std::to_string(invalidScale);
validate(device, message, model, [operand, invalidScale](Model* model) {
- model->operands[operand].scale = invalidScale;
+ model->main.operands[operand].scale = invalidScale;
});
}
}
@@ -229,15 +228,15 @@
}
static void mutateOperandZeroPointTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+ for (size_t operand = 0; operand < model.main.operands.size(); ++operand) {
const std::vector<int32_t> invalidZeroPoints =
- getInvalidZeroPoints(model.operands[operand].type);
+ getInvalidZeroPoints(model.main.operands[operand].type);
for (int32_t invalidZeroPoint : invalidZeroPoints) {
const std::string message = "mutateOperandZeroPointTest: operand " +
std::to_string(operand) + " has zero point of " +
std::to_string(invalidZeroPoint);
validate(device, message, model, [operand, invalidZeroPoint](Model* model) {
- model->operands[operand].zeroPoint = invalidZeroPoint;
+ model->main.operands[operand].zeroPoint = invalidZeroPoint;
});
}
}
@@ -310,11 +309,11 @@
static bool mutateOperationOperandTypeSkip(size_t operand, OperandType type, const Model& model) {
// Do not test OEM types
- if (type == model.operands[operand].type || type == OperandType::OEM ||
+ if (type == model.main.operands[operand].type || type == OperandType::OEM ||
type == OperandType::TENSOR_OEM_BYTE) {
return true;
}
- for (const Operation& operation : model.operations) {
+ for (const Operation& operation : model.main.operations) {
// Skip mutateOperationOperandTypeTest for the following operations.
// - LSH_PROJECTION's second argument is allowed to have any type.
// - ARGMIN and ARGMAX's first argument can be any of
@@ -401,7 +400,7 @@
}
static void mutateOperationOperandTypeTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+ for (size_t operand = 0; operand < model.main.operands.size(); ++operand) {
for (OperandType invalidOperandType : hidl_enum_range<OperandType>{}) {
if (mutateOperationOperandTypeSkip(operand, invalidOperandType, model)) {
continue;
@@ -410,7 +409,7 @@
std::to_string(operand) + " set to type " +
toString(invalidOperandType);
validate(device, message, model, [operand, invalidOperandType](Model* model) {
- mutateOperand(&model->operands[operand], invalidOperandType);
+ mutateOperand(&model->main.operands[operand], invalidOperandType);
});
}
}
@@ -425,13 +424,13 @@
};
static void mutateOperationTypeTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+ for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
for (uint32_t invalidOperationType : invalidOperationTypes) {
const std::string message = "mutateOperationTypeTest: operation " +
std::to_string(operation) + " set to value " +
std::to_string(invalidOperationType);
validate(device, message, model, [operation, invalidOperationType](Model* model) {
- model->operations[operation].type =
+ model->main.operations[operation].type =
static_cast<OperationType>(invalidOperationType);
});
}
@@ -441,14 +440,14 @@
///////////////////////// VALIDATE MODEL OPERATION INPUT OPERAND INDEX /////////////////////////
static void mutateOperationInputOperandIndexTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operation = 0; operation < model.operations.size(); ++operation) {
- const uint32_t invalidOperand = model.operands.size();
- for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) {
+ for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
+ const uint32_t invalidOperand = model.main.operands.size();
+ for (size_t input = 0; input < model.main.operations[operation].inputs.size(); ++input) {
const std::string message = "mutateOperationInputOperandIndexTest: operation " +
std::to_string(operation) + " input " +
std::to_string(input);
validate(device, message, model, [operation, input, invalidOperand](Model* model) {
- model->operations[operation].inputs[input] = invalidOperand;
+ model->main.operations[operation].inputs[input] = invalidOperand;
});
}
}
@@ -457,14 +456,15 @@
///////////////////////// VALIDATE MODEL OPERATION OUTPUT OPERAND INDEX /////////////////////////
static void mutateOperationOutputOperandIndexTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operation = 0; operation < model.operations.size(); ++operation) {
- const uint32_t invalidOperand = model.operands.size();
- for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) {
+ for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
+ const uint32_t invalidOperand = model.main.operands.size();
+ for (size_t output = 0; output < model.main.operations[operation].outputs.size();
+ ++output) {
const std::string message = "mutateOperationOutputOperandIndexTest: operation " +
std::to_string(operation) + " output " +
std::to_string(output);
validate(device, message, model, [operation, output, invalidOperand](Model* model) {
- model->operations[operation].outputs[output] = invalidOperand;
+ model->main.operations[operation].outputs[output] = invalidOperand;
});
}
}
@@ -485,17 +485,17 @@
}
static void removeOperand(Model* model, uint32_t index) {
- hidl_vec_removeAt(&model->operands, index);
- for (Operation& operation : model->operations) {
+ hidl_vec_removeAt(&model->main.operands, index);
+ for (Operation& operation : model->main.operations) {
removeValueAndDecrementGreaterValues(&operation.inputs, index);
removeValueAndDecrementGreaterValues(&operation.outputs, index);
}
- removeValueAndDecrementGreaterValues(&model->inputIndexes, index);
- removeValueAndDecrementGreaterValues(&model->outputIndexes, index);
+ removeValueAndDecrementGreaterValues(&model->main.inputIndexes, index);
+ removeValueAndDecrementGreaterValues(&model->main.outputIndexes, index);
}
static bool removeOperandSkip(size_t operand, const Model& model) {
- for (const Operation& operation : model.operations) {
+ for (const Operation& operation : model.main.operations) {
// Skip removeOperandTest for the following operations.
// - SPLIT's outputs are not checked during prepareModel.
if (operation.type == OperationType::SPLIT) {
@@ -520,7 +520,7 @@
}
static void removeOperandTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+ for (size_t operand = 0; operand < model.main.operands.size(); ++operand) {
if (removeOperandSkip(operand, model)) {
continue;
}
@@ -533,14 +533,14 @@
///////////////////////// REMOVE OPERATION /////////////////////////
static void removeOperation(Model* model, uint32_t index) {
- for (uint32_t operand : model->operations[index].inputs) {
- model->operands[operand].numberOfConsumers--;
+ for (uint32_t operand : model->main.operations[index].inputs) {
+ model->main.operands[operand].numberOfConsumers--;
}
- hidl_vec_removeAt(&model->operations, index);
+ hidl_vec_removeAt(&model->main.operations, index);
}
static void removeOperationTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+ for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
const std::string message = "removeOperationTest: operation " + std::to_string(operation);
validate(device, message, model,
[operation](Model* model) { removeOperation(model, operation); });
@@ -615,9 +615,9 @@
}
static void removeOperationInputTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operation = 0; operation < model.operations.size(); ++operation) {
- for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) {
- const Operation& op = model.operations[operation];
+ for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
+ for (size_t input = 0; input < model.main.operations[operation].inputs.size(); ++input) {
+ const Operation& op = model.main.operations[operation];
if (removeOperationInputSkip(op, input)) {
continue;
}
@@ -625,9 +625,9 @@
std::to_string(operation) + ", input " +
std::to_string(input);
validate(device, message, model, [operation, input](Model* model) {
- uint32_t operand = model->operations[operation].inputs[input];
- model->operands[operand].numberOfConsumers--;
- hidl_vec_removeAt(&model->operations[operation].inputs, input);
+ uint32_t operand = model->main.operations[operation].inputs[input];
+ model->main.operands[operand].numberOfConsumers--;
+ hidl_vec_removeAt(&model->main.operations[operation].inputs, input);
});
}
}
@@ -636,13 +636,14 @@
///////////////////////// REMOVE OPERATION OUTPUT /////////////////////////
static void removeOperationOutputTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operation = 0; operation < model.operations.size(); ++operation) {
- for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) {
+ for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
+ for (size_t output = 0; output < model.main.operations[operation].outputs.size();
+ ++output) {
const std::string message = "removeOperationOutputTest: operation " +
std::to_string(operation) + ", output " +
std::to_string(output);
validate(device, message, model, [operation, output](Model* model) {
- hidl_vec_removeAt(&model->operations[operation].outputs, output);
+ hidl_vec_removeAt(&model->main.operations[operation].outputs, output);
});
}
}
@@ -669,15 +670,15 @@
}
static void addOperationInputTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operation = 0; operation < model.operations.size(); ++operation) {
- if (addOperationInputSkip(model.operations[operation])) {
+ for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
+ if (addOperationInputSkip(model.main.operations[operation])) {
continue;
}
const std::string message = "addOperationInputTest: operation " + std::to_string(operation);
validate(device, message, model, [operation](Model* model) {
- uint32_t index = addOperand(model, OperandLifeTime::MODEL_INPUT);
- hidl_vec_push_back(&model->operations[operation].inputs, index);
- hidl_vec_push_back(&model->inputIndexes, index);
+ uint32_t index = addOperand(model, OperandLifeTime::SUBGRAPH_INPUT);
+ hidl_vec_push_back(&model->main.operations[operation].inputs, index);
+ hidl_vec_push_back(&model->main.inputIndexes, index);
});
}
}
@@ -685,13 +686,13 @@
///////////////////////// ADD OPERATION OUTPUT /////////////////////////
static void addOperationOutputTest(const sp<IDevice>& device, const Model& model) {
- for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+ for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
const std::string message =
"addOperationOutputTest: operation " + std::to_string(operation);
validate(device, message, model, [operation](Model* model) {
- uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT);
- hidl_vec_push_back(&model->operations[operation].outputs, index);
- hidl_vec_push_back(&model->outputIndexes, index);
+ uint32_t index = addOperand(model, OperandLifeTime::SUBGRAPH_OUTPUT);
+ hidl_vec_push_back(&model->main.operations[operation].outputs, index);
+ hidl_vec_push_back(&model->main.outputIndexes, index);
});
}
}
diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal
index 3afe37d..2eaab36 100644
--- a/tv/tuner/1.0/types.hal
+++ b/tv/tuner/1.0/types.hal
@@ -1131,9 +1131,14 @@
@export
enum FrontendAnalogType : uint32_t {
UNDEFINED = 0,
- PAL = 1 << 0,
- SECAM = 1 << 1,
- NTSC = 1 << 2,
+ AUTO = 1 << 0,
+ PAL = 1 << 1,
+ PAL_M = 1 << 2,
+ PAL_N = 1 << 3,
+ PAL_60 = 1 << 4,
+ NTSC = 1 << 5,
+ NTSC_443 = 1 << 6,
+ SECAM = 1 << 7,
};
/**
@@ -1142,23 +1147,24 @@
@export
enum FrontendAnalogSifStandard : uint32_t {
UNDEFINED = 0,
- BG = 1 << 0,
- BG_A2 = 1 << 1,
- BG_NICAM = 1 << 2,
- I = 1 << 3,
- DK = 1 << 4,
- DK1 = 1 << 5,
- DK2 = 1 << 6,
- DK3 = 1 << 7,
- DK_NICAM = 1 << 8,
- L = 1 << 9,
- M = 1 << 10,
- M_BTSC = 1 << 11,
- M_A2 = 1 << 12,
- M_EIA_J = 1 << 13,
- I_NICAM = 1 << 14,
- L_NICAM = 1 << 15,
- L_PRIME = 1 << 16,
+ AUTO = 1 << 0,
+ BG = 1 << 1,
+ BG_A2 = 1 << 2,
+ BG_NICAM = 1 << 3,
+ I = 1 << 4,
+ DK = 1 << 5,
+ DK1_A2 = 1 << 6,
+ DK2_A2 = 1 << 7,
+ DK3_A2 = 1 << 8,
+ DK_NICAM = 1 << 9,
+ L = 1 << 10,
+ M = 1 << 11,
+ M_BTSC = 1 << 12,
+ M_A2 = 1 << 13,
+ M_EIAJ = 1 << 14,
+ I_NICAM = 1 << 15,
+ L_NICAM = 1 << 16,
+ L_PRIME = 1 << 17,
};
/**