aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2023-03-07 17:58:33 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-03-07 17:58:33 +0000
commitce042e9b5c61123ff5314fc340a17b2f1b44ac6d (patch)
tree797704be08247a9fdea0e2e0224beeb3e8694291
parent69388231a08659049b705280a09bee607feb9899 (diff)
parent59bdf195df137c74b30665120cb5ae763fead8af (diff)
downloadlibese-ce042e9b5c61123ff5314fc340a17b2f1b44ac6d.tar.gz
Merge "Added android reay_se HAL implementation" am: 98fa81cbdd am: 59bdf195df
Original change: https://android-review.googlesource.com/c/platform/external/libese/+/2082579 Change-Id: I0b71f2fde08da7814869b3ecdc42d90e040bb166 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--ready_se/google/keymint/KM200/HAL/.clang-format10
-rw-r--r--ready_se/google/keymint/KM200/HAL/Android.bp122
-rw-r--r--ready_se/google/keymint/KM200/HAL/CborConverter.cpp512
-rw-r--r--ready_se/google/keymint/KM200/HAL/CborConverter.h139
-rw-r--r--ready_se/google/keymint/KM200/HAL/ITransport.h55
-rw-r--r--ready_se/google/keymint/KM200/HAL/JavacardKeyMintDevice.cpp454
-rw-r--r--ready_se/google/keymint/KM200/HAL/JavacardKeyMintDevice.h124
-rw-r--r--ready_se/google/keymint/KM200/HAL/JavacardKeyMintOperation.cpp300
-rw-r--r--ready_se/google/keymint/KM200/HAL/JavacardKeyMintOperation.h136
-rw-r--r--ready_se/google/keymint/KM200/HAL/JavacardRemotelyProvisionedComponentDevice.cpp284
-rw-r--r--ready_se/google/keymint/KM200/HAL/JavacardRemotelyProvisionedComponentDevice.h80
-rw-r--r--ready_se/google/keymint/KM200/HAL/JavacardSecureElement.cpp157
-rw-r--r--ready_se/google/keymint/KM200/HAL/JavacardSecureElement.h114
-rw-r--r--ready_se/google/keymint/KM200/HAL/JavacardSharedSecret.cpp61
-rw-r--r--ready_se/google/keymint/KM200/HAL/JavacardSharedSecret.h34
-rw-r--r--ready_se/google/keymint/KM200/HAL/LICENSE202
-rw-r--r--ready_se/google/keymint/KM200/HAL/METADATA3
-rw-r--r--ready_se/google/keymint/KM200/HAL/OWNERS3
-rw-r--r--ready_se/google/keymint/KM200/HAL/OmapiTransport.cpp276
-rw-r--r--ready_se/google/keymint/KM200/HAL/OmapiTransport.h65
-rw-r--r--ready_se/google/keymint/KM200/HAL/SocketTransport.cpp144
-rw-r--r--ready_se/google/keymint/KM200/HAL/SocketTransport.h55
-rw-r--r--ready_se/google/keymint/KM200/HAL/android.hardware.hardware_keystore.jc-strongbox-keymint.xml17
-rw-r--r--ready_se/google/keymint/KM200/HAL/android.hardware.security.keymint-service.strongbox.rc3
-rw-r--r--ready_se/google/keymint/KM200/HAL/android.hardware.security.keymint-service.strongbox.xml10
-rw-r--r--ready_se/google/keymint/KM200/HAL/android.hardware.security.sharedsecret-service.strongbox.xml6
-rw-r--r--ready_se/google/keymint/KM200/HAL/keymint_utils.cpp130
-rw-r--r--ready_se/google/keymint/KM200/HAL/keymint_utils.h47
-rw-r--r--ready_se/google/keymint/KM200/HAL/service.cpp95
29 files changed, 3638 insertions, 0 deletions
diff --git a/ready_se/google/keymint/KM200/HAL/.clang-format b/ready_se/google/keymint/KM200/HAL/.clang-format
new file mode 100644
index 0000000..b0dc94c
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/.clang-format
@@ -0,0 +1,10 @@
+BasedOnStyle: LLVM
+IndentWidth: 4
+UseTab: Never
+BreakBeforeBraces: Attach
+AllowShortFunctionsOnASingleLine: Inline
+AllowShortIfStatementsOnASingleLine: true
+IndentCaseLabels: false
+ColumnLimit: 100
+PointerBindsToType: true
+SpacesBeforeTrailingComments: 2
diff --git a/ready_se/google/keymint/KM200/HAL/Android.bp b/ready_se/google/keymint/KM200/HAL/Android.bp
new file mode 100644
index 0000000..a5b1768
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/Android.bp
@@ -0,0 +1,122 @@
+// 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.
+//
+
+cc_library {
+ name: "libjc_keymint",
+ defaults: [
+ "keymaster_defaults",
+ "keymint_use_latest_hal_aidl_ndk_shared",
+ ],
+ srcs: [
+ "CborConverter.cpp",
+ "JavacardKeyMintDevice.cpp",
+ "JavacardKeyMintOperation.cpp",
+ "JavacardRemotelyProvisionedComponentDevice.cpp",
+ "JavacardSecureElement.cpp",
+ "JavacardSharedSecret.cpp",
+ "keymint_utils.cpp",
+ ],
+ cflags: ["-O0"],
+ shared_libs: [
+ "android.hardware.security.secureclock-V1-ndk",
+ "android.hardware.security.sharedsecret-V1-ndk",
+ "android.hardware.security.rkp-V3-ndk",
+ "lib_android_keymaster_keymint_utils",
+ "libbase",
+ "libcppbor_external",
+ "libkeymaster_portable",
+ "libkeymaster_messages",
+ "libsoft_attestation_cert",
+ "liblog",
+ "libcrypto",
+ "libcutils",
+ "libjc_keymint_transport",
+ "libbinder_ndk",
+ ],
+ export_include_dirs: [
+ ".",
+ ],
+ vendor_available: true,
+}
+
+cc_library {
+ name: "libjc_keymint_transport",
+ vendor_available: true,
+ defaults: [
+ "keymint_use_latest_hal_aidl_ndk_shared",
+ ],
+ srcs: [
+ "SocketTransport.cpp",
+ "OmapiTransport.cpp",
+ ],
+ export_include_dirs: [
+ ".",
+ ],
+ shared_libs: [
+ "libbinder",
+ "libbase",
+ "liblog",
+ "libbinder_ndk",
+ "android.se.omapi-V1-ndk",
+ "libhardware",
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.security.keymint-service.strongbox",
+ relative_install_path: "hw",
+ init_rc: ["android.hardware.security.keymint-service.strongbox.rc"],
+ vintf_fragments: [
+ "android.hardware.security.keymint-service.strongbox.xml",
+ "android.hardware.security.sharedsecret-service.strongbox.xml",
+ ],
+ vendor: true,
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ ],
+ defaults: [
+ "keymint_use_latest_hal_aidl_ndk_shared",
+ ],
+ shared_libs: [
+ "android.hardware.security.sharedsecret-V1-ndk",
+ "lib_android_keymaster_keymint_utils",
+ "android.hardware.security.rkp-V3-ndk",
+ "libbase",
+ "libbinder_ndk",
+ "libcppbor_external",
+ "libcrypto",
+ "libkeymaster_portable",
+ "libjc_keymint",
+ "libjc_keymint_transport",
+ "liblog",
+ "libutils",
+ "android.se.omapi-V1-ndk",
+ ],
+ srcs: [
+ "service.cpp",
+ ],
+ required: [
+ "RemoteProvisioner",
+ "android.hardware.hardware_keystore.jc-strongbox-keymint.xml",
+ ],
+}
+
+prebuilt_etc {
+ name: "android.hardware.hardware_keystore.jc-strongbox-keymint.xml",
+ sub_dir: "permissions",
+ vendor: true,
+ src: "android.hardware.hardware_keystore.jc-strongbox-keymint.xml",
+}
diff --git a/ready_se/google/keymint/KM200/HAL/CborConverter.cpp b/ready_se/google/keymint/KM200/HAL/CborConverter.cpp
new file mode 100644
index 0000000..d7e6c11
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/CborConverter.cpp
@@ -0,0 +1,512 @@
+/*
+ **
+ ** 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 "CborConverter.h"
+
+#include <map>
+#include <string>
+
+#include <android-base/logging.h>
+
+#include <KeyMintUtils.h>
+
+namespace keymint::javacard {
+using ::aidl::android::hardware::security::keymint::KeyParameterValue;
+using ::aidl::android::hardware::security::keymint::SecurityLevel;
+using ::aidl::android::hardware::security::keymint::km_utils::kmParam2Aidl;
+using ::aidl::android::hardware::security::keymint::km_utils::legacy_enum_conversion;
+using ::aidl::android::hardware::security::keymint::km_utils::typeFromTag;
+
+constexpr int SB_ENFORCED = 0;
+constexpr int TEE_ENFORCED = 1;
+constexpr int SW_ENFORCED = 2;
+
+namespace {
+
+template <KeyParameterValue::Tag aidl_tag>
+std::optional<uint32_t> aidlEnumVal2Uint32(const KeyParameterValue& value) {
+ return (value.getTag() == aidl_tag)
+ ? std::optional(static_cast<uint32_t>(value.get<aidl_tag>()))
+ : std::nullopt;
+}
+
+std::optional<uint32_t> aidlEnumParam2Uint32(const KeyParameter& param) {
+ auto tag = legacy_enum_conversion(param.tag);
+ switch (tag) {
+ case KM_TAG_PURPOSE:
+ return aidlEnumVal2Uint32<KeyParameterValue::keyPurpose>(param.value);
+ case KM_TAG_ALGORITHM:
+ return aidlEnumVal2Uint32<KeyParameterValue::algorithm>(param.value);
+ case KM_TAG_BLOCK_MODE:
+ return aidlEnumVal2Uint32<KeyParameterValue::blockMode>(param.value);
+ case KM_TAG_DIGEST:
+ case KM_TAG_RSA_OAEP_MGF_DIGEST:
+ return aidlEnumVal2Uint32<KeyParameterValue::digest>(param.value);
+ case KM_TAG_PADDING:
+ return aidlEnumVal2Uint32<KeyParameterValue::paddingMode>(param.value);
+ case KM_TAG_EC_CURVE:
+ return aidlEnumVal2Uint32<KeyParameterValue::ecCurve>(param.value);
+ case KM_TAG_USER_AUTH_TYPE:
+ return aidlEnumVal2Uint32<KeyParameterValue::hardwareAuthenticatorType>(param.value);
+ case KM_TAG_ORIGIN:
+ return aidlEnumVal2Uint32<KeyParameterValue::origin>(param.value);
+ case KM_TAG_BLOB_USAGE_REQUIREMENTS:
+ case KM_TAG_KDF:
+ default:
+ CHECK(false) << "Unknown or unused enum tag: Something is broken";
+ return std::nullopt;
+ }
+}
+
+} // namespace
+
+bool CborConverter::addAttestationKey(Array& array,
+ const std::optional<AttestationKey>& attestationKey) {
+ if (attestationKey.has_value()) {
+ array.add(Bstr(attestationKey->keyBlob));
+ addKeyparameters(array, attestationKey->attestKeyParams);
+ array.add(Bstr(attestationKey->issuerSubjectName));
+ } else {
+ array.add(std::move(Bstr(vector<uint8_t>(0))));
+ array.add(std::move(Map()));
+ array.add(std::move(Bstr(vector<uint8_t>(0))));
+ }
+ return true;
+}
+
+bool CborConverter::addKeyparameters(Array& array, const vector<KeyParameter>& keyParams) {
+ Map map;
+ std::map<uint64_t, vector<uint8_t>> enum_repetition;
+ std::map<uint64_t, Array> uint_repetition;
+ for (auto& param : keyParams) {
+ auto tag = legacy_enum_conversion(param.tag);
+ switch (typeFromTag(tag)) {
+ case KM_ENUM: {
+ auto paramEnum = aidlEnumParam2Uint32(param);
+ if (paramEnum.has_value()) {
+ map.add(static_cast<uint64_t>(tag), *paramEnum);
+ }
+ break;
+ }
+ case KM_UINT:
+ if (param.value.getTag() == KeyParameterValue::integer) {
+ auto intVal = param.value.get<KeyParameterValue::integer>();
+ map.add(static_cast<uint64_t>(tag), intVal);
+ }
+ break;
+ case KM_UINT_REP:
+ if (param.value.getTag() == KeyParameterValue::integer) {
+ auto intVal = param.value.get<KeyParameterValue::integer>();
+ uint_repetition[static_cast<uint64_t>(tag)].add(intVal);
+ }
+ break;
+ case KM_ENUM_REP: {
+ auto paramEnumRep = aidlEnumParam2Uint32(param);
+ if (paramEnumRep.has_value()) {
+ enum_repetition[static_cast<uint64_t>(tag)].push_back(*paramEnumRep);
+ }
+ break;
+ }
+ case KM_ULONG:
+ if (param.value.getTag() == KeyParameterValue::longInteger) {
+ auto longVal = param.value.get<KeyParameterValue::longInteger>();
+ map.add(static_cast<uint64_t>(tag), longVal);
+ }
+ break;
+ case KM_ULONG_REP:
+ if (param.value.getTag() == KeyParameterValue::longInteger) {
+ auto longVal = param.value.get<KeyParameterValue::longInteger>();
+ uint_repetition[static_cast<uint64_t>(tag & 0x00000000ffffffff)].add(longVal);
+ }
+ break;
+ case KM_DATE:
+ if (param.value.getTag() == KeyParameterValue::dateTime) {
+ auto dateVal = param.value.get<KeyParameterValue::dateTime>();
+ map.add(static_cast<uint64_t>(tag), dateVal);
+ }
+ break;
+ case KM_BOOL:
+ map.add(static_cast<uint64_t>(tag), 1 /* true */);
+ break;
+ case KM_BIGNUM:
+ case KM_BYTES:
+ if (param.value.getTag() == KeyParameterValue::blob) {
+ const auto& value = param.value.get<KeyParameterValue::blob>();
+ map.add(static_cast<uint64_t>(tag & 0x00000000ffffffff), value);
+ }
+ break;
+ case KM_INVALID:
+ break;
+ }
+ }
+
+ for (auto const& [key, val] : enum_repetition) {
+ Bstr bstr(val);
+ map.add(key, std::move(bstr));
+ }
+
+ for (auto& [key, val] : uint_repetition) {
+ map.add(key, std::move(val));
+ }
+ array.add(std::move(map));
+ return true;
+}
+
+// Array of three maps
+std::optional<vector<KeyCharacteristics>>
+CborConverter::getKeyCharacteristics(const unique_ptr<Item>& item, const uint32_t pos) {
+ vector<KeyCharacteristics> keyCharacteristics;
+ auto arrayItem = getItemAtPos(item, pos);
+ if (!arrayItem || (MajorType::ARRAY != getType(arrayItem.value()))) {
+ return std::nullopt;
+ }
+ KeyCharacteristics swEnf{SecurityLevel::KEYSTORE, {}};
+ KeyCharacteristics teeEnf{SecurityLevel::TRUSTED_ENVIRONMENT, {}};
+ KeyCharacteristics sbEnf{SecurityLevel::STRONGBOX, {}};
+
+ auto optSbEnf = getKeyParameters(arrayItem.value(), SB_ENFORCED);
+ if (!optSbEnf) {
+ return std::nullopt;
+ }
+ sbEnf.authorizations = std::move(optSbEnf.value());
+ auto optTeeEnf = getKeyParameters(arrayItem.value(), TEE_ENFORCED);
+ if (!optTeeEnf) {
+ return std::nullopt;
+ }
+ teeEnf.authorizations = std::move(optTeeEnf.value());
+ auto optSwEnf = getKeyParameters(arrayItem.value(), SW_ENFORCED);
+ if (!optSwEnf) {
+ return std::nullopt;
+ }
+ swEnf.authorizations = std::move(optSwEnf.value());
+ // VTS will fail if the authorizations list is empty.
+ if (!sbEnf.authorizations.empty()) keyCharacteristics.push_back(std::move(sbEnf));
+ if (!teeEnf.authorizations.empty()) keyCharacteristics.push_back(std::move(teeEnf));
+ if (!swEnf.authorizations.empty()) keyCharacteristics.push_back(std::move(swEnf));
+ return keyCharacteristics;
+}
+
+std::optional<std::vector<KeyParameter>> CborConverter::getKeyParameter(
+ const std::pair<const std::unique_ptr<Item>&, const std::unique_ptr<Item>&> pair) {
+ std::vector<KeyParameter> keyParams;
+ keymaster_tag_t key;
+ auto optValue = getUint64(pair.first);
+ if (!optValue) {
+ return std::nullopt;
+ }
+ key = static_cast<keymaster_tag_t>(optValue.value());
+ switch (keymaster_tag_get_type(key)) {
+ case KM_ENUM_REP: {
+ /* ENUM_REP contains values encoded in a Byte string */
+ const Bstr* bstr = pair.second.get()->asBstr();
+ if (bstr == nullptr) {
+ return std::nullopt;
+ }
+ for (auto bchar : bstr->value()) {
+ keymaster_key_param_t keyParam;
+ keyParam.tag = key;
+ keyParam.enumerated = bchar;
+ keyParams.push_back(kmParam2Aidl(keyParam));
+ }
+ return keyParams;
+ }
+ case KM_ENUM: {
+ keymaster_key_param_t keyParam;
+ keyParam.tag = key;
+ if (!(optValue = getUint64(pair.second))) {
+ return std::nullopt;
+ }
+ keyParam.enumerated = static_cast<uint32_t>(optValue.value());
+ keyParams.push_back(kmParam2Aidl(keyParam));
+ return keyParams;
+ }
+ case KM_UINT: {
+ keymaster_key_param_t keyParam;
+ keyParam.tag = key;
+ if (!(optValue = getUint64(pair.second))) {
+ return std::nullopt;
+ }
+ keyParam.integer = static_cast<uint32_t>(optValue.value());
+ keyParams.push_back(kmParam2Aidl(keyParam));
+ return keyParams;
+ }
+ case KM_ULONG: {
+ keymaster_key_param_t keyParam;
+ keyParam.tag = key;
+ if (!(optValue = getUint64(pair.second))) {
+ return std::nullopt;
+ }
+ keyParam.long_integer = optValue.value();
+ keyParams.push_back(kmParam2Aidl(keyParam));
+ return keyParams;
+ }
+ case KM_UINT_REP: {
+ /* UINT_REP contains values encoded in a Array */
+ Array* array = const_cast<Array*>(pair.second.get()->asArray());
+ if (array == nullptr) return std::nullopt;
+ for (int i = 0; i < array->size(); i++) {
+ keymaster_key_param_t keyParam;
+ keyParam.tag = key;
+ const std::unique_ptr<Item>& item = array->get(i);
+ if (!(optValue = getUint64(item))) {
+ return std::nullopt;
+ }
+ keyParam.integer = static_cast<uint32_t>(optValue.value());
+ keyParams.push_back(kmParam2Aidl(keyParam));
+ }
+ return keyParams;
+ }
+ case KM_ULONG_REP: {
+ /* ULONG_REP contains values encoded in a Array */
+ Array* array = const_cast<Array*>(pair.second.get()->asArray());
+ if (array == nullptr) return std::nullopt;
+ for (int i = 0; i < array->size(); i++) {
+ keymaster_key_param_t keyParam;
+ keyParam.tag = key;
+ const std::unique_ptr<Item>& item = array->get(i);
+ if (!(optValue = getUint64(item))) {
+ return std::nullopt;
+ }
+ keyParam.long_integer = optValue.value();
+ keyParams.push_back(kmParam2Aidl(keyParam));
+ }
+ return keyParams;
+ }
+ case KM_DATE: {
+ keymaster_key_param_t keyParam;
+ keyParam.tag = key;
+ if (!(optValue = getUint64(pair.second))) {
+ return std::nullopt;
+ }
+ keyParam.date_time = optValue.value();
+ keyParams.push_back(kmParam2Aidl(keyParam));
+ return keyParams;
+ }
+ case KM_BOOL: {
+ keymaster_key_param_t keyParam;
+ keyParam.tag = key;
+ if (!(optValue = getUint64(pair.second))) {
+ return std::nullopt;
+ }
+ // If a tag with this type is present, the value is true. If absent, false.
+ keyParam.boolean = true;
+ keyParams.push_back(kmParam2Aidl(keyParam));
+ return keyParams;
+ }
+ case KM_BIGNUM:
+ case KM_BYTES: {
+ keymaster_key_param_t keyParam;
+ keyParam.tag = key;
+ const Bstr* bstr = pair.second.get()->asBstr();
+ if (bstr == nullptr) return std::nullopt;
+ keyParam.blob.data = bstr->value().data();
+ keyParam.blob.data_length = bstr->value().size();
+ keyParams.push_back(kmParam2Aidl(keyParam));
+ return keyParams;
+ }
+ case KM_INVALID:
+ break;
+ }
+ return std::nullopt;
+}
+
+// array of a blobs
+std::optional<vector<Certificate>>
+CborConverter::getCertificateChain(const std::unique_ptr<Item>& item, const uint32_t pos) {
+ vector<Certificate> certChain;
+ auto arrayItem = getItemAtPos(item, pos);
+ if (!arrayItem || (MajorType::ARRAY != getType(arrayItem.value()))) return std::nullopt;
+
+ const Array* arr = arrayItem.value().get()->asArray();
+ for (int i = 0; i < arr->size(); i++) {
+ Certificate cert;
+ auto optTemp = getByteArrayVec(arrayItem.value(), i);
+ if (!optTemp) return std::nullopt;
+ cert.encodedCertificate = std::move(optTemp.value());
+ certChain.push_back(std::move(cert));
+ }
+ return certChain;
+}
+
+std::optional<string> CborConverter::getByteArrayStr(const unique_ptr<Item>& item,
+ const uint32_t pos) {
+ auto optTemp = getByteArrayVec(item, pos);
+ if (!optTemp) {
+ return std::nullopt;
+ }
+ std::string str(optTemp->begin(), optTemp->end());
+ return str;
+}
+
+std::optional<std::vector<uint8_t>> CborConverter::getByteArrayVec(const unique_ptr<Item>& item,
+ const uint32_t pos) {
+ auto strItem = getItemAtPos(item, pos);
+ if (!strItem || (MajorType::BSTR != getType(strItem.value()))) {
+ return std::nullopt;
+ }
+ const Bstr* bstr = strItem.value().get()->asBstr();
+ return bstr->value();
+}
+
+std::optional<SharedSecretParameters>
+CborConverter::getSharedSecretParameters(const unique_ptr<Item>& item, const uint32_t pos) {
+ SharedSecretParameters params;
+ // Array [seed, nonce]
+ auto arrayItem = getItemAtPos(item, pos);
+ if (!arrayItem || (MajorType::ARRAY != getType(arrayItem.value()))) {
+ return std::nullopt;
+ }
+ auto optSeed = getByteArrayVec(arrayItem.value(), 0);
+ auto optNonce = getByteArrayVec(arrayItem.value(), 1);
+ if (!optSeed || !optNonce) {
+ return std::nullopt;
+ }
+ params.seed = std::move(optSeed.value());
+ params.nonce = std::move(optNonce.value());
+ return params;
+}
+
+bool CborConverter::addSharedSecretParameters(Array& array,
+ const vector<SharedSecretParameters>& params) {
+ Array cborParamsVec;
+ for (auto param : params) {
+ Array cborParam;
+ cborParam.add(Bstr(param.seed));
+ cborParam.add(Bstr(param.nonce));
+ cborParamsVec.add(std::move(cborParam));
+ }
+ array.add(std::move(cborParamsVec));
+ return true;
+}
+
+bool CborConverter::addTimeStampToken(Array& array, const TimeStampToken& token) {
+ Array vToken;
+ vToken.add(static_cast<uint64_t>(token.challenge));
+ vToken.add(static_cast<uint64_t>(token.timestamp.milliSeconds));
+ vToken.add((std::vector<uint8_t>(token.mac)));
+ array.add(std::move(vToken));
+ return true;
+}
+
+bool CborConverter::addHardwareAuthToken(Array& array, const HardwareAuthToken& authToken) {
+
+ Array hwAuthToken;
+ hwAuthToken.add(static_cast<uint64_t>(authToken.challenge));
+ hwAuthToken.add(static_cast<uint64_t>(authToken.userId));
+ hwAuthToken.add(static_cast<uint64_t>(authToken.authenticatorId));
+ hwAuthToken.add(static_cast<uint64_t>(authToken.authenticatorType));
+ hwAuthToken.add(static_cast<uint64_t>(authToken.timestamp.milliSeconds));
+ hwAuthToken.add((std::vector<uint8_t>(authToken.mac)));
+ array.add(std::move(hwAuthToken));
+ return true;
+}
+
+std::optional<TimeStampToken> CborConverter::getTimeStampToken(const unique_ptr<Item>& item,
+ const uint32_t pos) {
+ TimeStampToken token;
+ // {challenge, timestamp, Mac}
+ auto optChallenge = getUint64(item, pos);
+ auto optTimestampMillis = getUint64(item, pos + 1);
+ auto optTemp = getByteArrayVec(item, pos + 2);
+ if (!optChallenge || !optTimestampMillis || !optTemp) {
+ return std::nullopt;
+ }
+ token.mac = std::move(optTemp.value());
+ token.challenge = static_cast<long>(std::move(optChallenge.value()));
+ token.timestamp.milliSeconds = static_cast<long>(std::move(optTimestampMillis.value()));
+ return token;
+}
+
+std::optional<Array> CborConverter::getArrayItem(const std::unique_ptr<Item>& item,
+ const uint32_t pos) {
+ Array array;
+ auto arrayItem = getItemAtPos(item, pos);
+ if (!arrayItem || (MajorType::ARRAY != getType(arrayItem.value()))) {
+ return std::nullopt;
+ }
+ array = std::move(*(arrayItem.value().get()->asArray()));
+ return array;
+}
+
+std::optional<Map> CborConverter::getMapItem(const std::unique_ptr<Item>& item,
+ const uint32_t pos) {
+ Map map;
+ auto mapItem = getItemAtPos(item, pos);
+ if (!mapItem || (MajorType::MAP != getType(mapItem.value()))) {
+ return std::nullopt;
+ }
+ map = std::move(*(mapItem.value().get()->asMap()));
+ return map;
+}
+
+std::optional<vector<KeyParameter>> CborConverter::getKeyParameters(const unique_ptr<Item>& item,
+ const uint32_t pos) {
+ vector<KeyParameter> params;
+ auto mapItem = getItemAtPos(item, pos);
+ if (!mapItem || (MajorType::MAP != getType(mapItem.value()))) return std::nullopt;
+ const Map* map = mapItem.value().get()->asMap();
+ size_t mapSize = map->size();
+ for (int i = 0; i < mapSize; i++) {
+ auto optKeyParams = getKeyParameter((*map)[i]);
+ if (optKeyParams) {
+ params.insert(params.end(), optKeyParams->begin(), optKeyParams->end());
+ } else {
+ return std::nullopt;
+ }
+ }
+ return params;
+}
+
+std::tuple<std::unique_ptr<Item>, keymaster_error_t>
+CborConverter::decodeData(const std::vector<uint8_t>& response) {
+ auto [item, pos, message] = cppbor::parse(response);
+ if (!item || MajorType::ARRAY != getType(item)) {
+ return {nullptr, KM_ERROR_UNKNOWN_ERROR};
+ }
+ auto optErrorCode = getErrorCode(item, 0);
+ if (!optErrorCode) {
+ return {nullptr, KM_ERROR_UNKNOWN_ERROR};
+ }
+ return {std::move(item), optErrorCode.value()};
+}
+
+std::optional<keymaster_error_t>
+CborConverter::getErrorCode(const std::unique_ptr<cppbor::Item>& item, const uint32_t pos) {
+ auto optErrorVal = getUint64(item, pos);
+ if (!optErrorVal) {
+ return std::nullopt;
+ }
+ return static_cast<keymaster_error_t>(0 - optErrorVal.value());
+}
+
+std::optional<uint64_t> CborConverter::getUint64(const unique_ptr<Item>& item) {
+ if ((item == nullptr) || (MajorType::UINT != getType(item))) {
+ return std::nullopt;
+ }
+ const Uint* uintVal = item.get()->asUint();
+ return uintVal->unsignedValue();
+}
+
+std::optional<uint64_t> CborConverter::getUint64(const unique_ptr<Item>& item, const uint32_t pos) {
+ auto intItem = getItemAtPos(item, pos);
+ if (!intItem) {
+ return std::nullopt;
+ }
+ return getUint64(intItem.value());
+}
+
+} // namespace keymint::javacard
diff --git a/ready_se/google/keymint/KM200/HAL/CborConverter.h b/ready_se/google/keymint/KM200/HAL/CborConverter.h
new file mode 100644
index 0000000..b49273b
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/CborConverter.h
@@ -0,0 +1,139 @@
+/*
+ **
+ ** 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 <iostream>
+#include <memory>
+#include <numeric>
+#include <vector>
+
+#include <cppbor.h>
+#include <cppbor_parse.h>
+
+#include <aidl/android/hardware/security/keymint/Certificate.h>
+#include <aidl/android/hardware/security/keymint/IKeyMintDevice.h>
+#include <aidl/android/hardware/security/secureclock/TimeStampToken.h>
+#include <aidl/android/hardware/security/sharedsecret/ISharedSecret.h>
+
+#include <keymaster/android_keymaster_messages.h>
+
+namespace keymint::javacard {
+using aidl::android::hardware::security::keymint::AttestationKey;
+using aidl::android::hardware::security::keymint::Certificate;
+using aidl::android::hardware::security::keymint::HardwareAuthToken;
+using aidl::android::hardware::security::keymint::KeyCharacteristics;
+using aidl::android::hardware::security::keymint::KeyParameter;
+using aidl::android::hardware::security::secureclock::TimeStampToken;
+using aidl::android::hardware::security::sharedsecret::SharedSecretParameters;
+using cppbor::Array;
+using cppbor::Bstr;
+using cppbor::EncodedItem;
+using cppbor::Item;
+using cppbor::MajorType;
+using cppbor::Map;
+using cppbor::Nint;
+using cppbor::Uint;
+using std::string;
+using std::unique_ptr;
+using std::vector;
+
+class CborConverter {
+ public:
+ CborConverter() = default;
+
+ ~CborConverter() = default;
+
+ std::tuple<std::unique_ptr<Item>, keymaster_error_t>
+ decodeData(const std::vector<uint8_t>& response);
+
+ std::optional<uint64_t> getUint64(const unique_ptr<Item>& item);
+
+ std::optional<uint64_t> getUint64(const unique_ptr<Item>& item, const uint32_t pos);
+
+ std::optional<SharedSecretParameters>
+ getSharedSecretParameters(const std::unique_ptr<Item>& item, const uint32_t pos);
+
+ std::optional<string> getByteArrayStr(const unique_ptr<Item>& item, const uint32_t pos);
+
+ std::optional<std::vector<uint8_t>> getByteArrayVec(const unique_ptr<Item>& item,
+ const uint32_t pos);
+
+ std::optional<vector<KeyParameter>> getKeyParameters(const unique_ptr<Item>& item,
+ const uint32_t pos);
+
+ bool addKeyparameters(Array& array, const vector<KeyParameter>& keyParams);
+
+ bool addAttestationKey(Array& array, const std::optional<AttestationKey>& attestationKey);
+
+ bool addHardwareAuthToken(Array& array, const HardwareAuthToken& authToken);
+
+ bool addSharedSecretParameters(Array& array, const vector<SharedSecretParameters>& params);
+
+ std::optional<TimeStampToken> getTimeStampToken(const std::unique_ptr<Item>& item,
+ const uint32_t pos);
+
+ std::optional<vector<KeyCharacteristics>>
+ getKeyCharacteristics(const std::unique_ptr<Item>& item, const uint32_t pos);
+
+ std::optional<vector<Certificate>> getCertificateChain(const std::unique_ptr<Item>& item,
+ const uint32_t pos);
+
+ std::optional<vector<vector<uint8_t>>> getMultiByteArray(const unique_ptr<Item>& item,
+ const uint32_t pos);
+
+ bool addTimeStampToken(Array& array, const TimeStampToken& token);
+
+ std::optional<Map> getMapItem(const std::unique_ptr<Item>& item, const uint32_t pos);
+
+ std::optional<Array> getArrayItem(const std::unique_ptr<Item>& item, const uint32_t pos);
+
+ std::optional<keymaster_error_t> getErrorCode(const std::unique_ptr<Item>& item,
+ const uint32_t pos);
+
+ private:
+ /**
+ * Get the type of the Item pointer.
+ */
+ inline MajorType getType(const unique_ptr<Item>& item) { return item.get()->type(); }
+
+ /**
+ * Construct Keyparameter structure from the pair of key and value. If TagType is ENUM_REP the
+ * value contains binary string. If TagType is UINT_REP or ULONG_REP the value contains Array of
+ * unsigned integers.
+ */
+ std::optional<std::vector<KeyParameter>> getKeyParameter(
+ const std::pair<const std::unique_ptr<Item>&, const std::unique_ptr<Item>&> pair);
+
+ /**
+ * Get the sub item pointer from the root item pointer at the given position.
+ */
+ inline std::optional<unique_ptr<Item>> getItemAtPos(const unique_ptr<Item>& item,
+ const uint32_t pos) {
+ Array* arr = nullptr;
+
+ if (MajorType::ARRAY != getType(item)) {
+ return std::nullopt;
+ }
+ arr = const_cast<Array*>(item.get()->asArray());
+ if (arr->size() < (pos + 1)) {
+ return std::nullopt;
+ }
+ return std::move((*arr)[pos]);
+ }
+};
+
+} // namespace keymint::javacard
diff --git a/ready_se/google/keymint/KM200/HAL/ITransport.h b/ready_se/google/keymint/KM200/HAL/ITransport.h
new file mode 100644
index 0000000..ca100be
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/ITransport.h
@@ -0,0 +1,55 @@
+/*
+ **
+ ** 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 <memory>
+#include <vector>
+
+#include <hardware/keymaster_defs.h>
+
+namespace keymint::javacard {
+using std::shared_ptr;
+using std::vector;
+
+/**
+ * ITransport is an interface with a set of virtual methods that allow communication between the
+ * HAL and the applet on the secure element.
+ */
+class ITransport {
+ public:
+ virtual ~ITransport() {}
+
+ /**
+ * Opens connection.
+ */
+ virtual keymaster_error_t openConnection() = 0;
+ /**
+ * Send data over communication channel and receives data back from the remote end.
+ */
+ virtual keymaster_error_t sendData(const vector<uint8_t>& inData, vector<uint8_t>& output) = 0;
+ /**
+ * Closes the connection.
+ */
+ virtual keymaster_error_t closeConnection() = 0;
+ /**
+ * Returns the state of the connection status. Returns true if the connection is active, false
+ * if connection is broken.
+ */
+ virtual bool isConnected() = 0;
+};
+
+} // namespace keymint::javacard
diff --git a/ready_se/google/keymint/KM200/HAL/JavacardKeyMintDevice.cpp b/ready_se/google/keymint/KM200/HAL/JavacardKeyMintDevice.cpp
new file mode 100644
index 0000000..bd68b48
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/JavacardKeyMintDevice.cpp
@@ -0,0 +1,454 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "javacard.keymint.device.strongbox-impl"
+
+#include "JavacardKeyMintDevice.h"
+
+#include <regex.h>
+
+#include <algorithm>
+#include <iostream>
+#include <iterator>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <KeyMintUtils.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <hardware/hw_auth_token.h>
+#include <keymaster/android_keymaster_messages.h>
+#include <keymaster/wrapped_key.h>
+
+#include "JavacardKeyMintOperation.h"
+#include "JavacardSharedSecret.h"
+
+namespace aidl::android::hardware::security::keymint {
+using cppbor::Bstr;
+using cppbor::EncodedItem;
+using cppbor::Uint;
+using ::keymaster::AuthorizationSet;
+using ::keymaster::dup_buffer;
+using ::keymaster::KeymasterBlob;
+using ::keymaster::KeymasterKeyBlob;
+using ::keymint::javacard::Instruction;
+using std::string;
+
+ScopedAStatus JavacardKeyMintDevice::defaultHwInfo(KeyMintHardwareInfo* info) {
+ info->versionNumber = 2;
+ info->keyMintAuthorName = "Google";
+ info->keyMintName = "JavacardKeymintDevice";
+ info->securityLevel = securitylevel_;
+ info->timestampTokenRequired = true;
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus JavacardKeyMintDevice::getHardwareInfo(KeyMintHardwareInfo* info) {
+ auto [item, err] = card_->sendRequest(Instruction::INS_GET_HW_INFO_CMD);
+ std::optional<string> optKeyMintName;
+ std::optional<string> optKeyMintAuthorName;
+ std::optional<uint64_t> optSecLevel;
+ std::optional<uint64_t> optVersion;
+ std::optional<uint64_t> optTsRequired;
+ if (err != KM_ERROR_OK || !(optVersion = cbor_.getUint64(item, 1)) ||
+ !(optSecLevel = cbor_.getUint64(item, 2)) ||
+ !(optKeyMintName = cbor_.getByteArrayStr(item, 3)) ||
+ !(optKeyMintAuthorName = cbor_.getByteArrayStr(item, 4)) ||
+ !(optTsRequired = cbor_.getUint64(item, 5))) {
+ LOG(ERROR) << "Error in response of getHardwareInfo.";
+ LOG(INFO) << "Returning defaultHwInfo in getHardwareInfo.";
+ return defaultHwInfo(info);
+ }
+ card_->initializeJavacard();
+ info->keyMintName = std::move(optKeyMintName.value());
+ info->keyMintAuthorName = std::move(optKeyMintAuthorName.value());
+ info->timestampTokenRequired = (optTsRequired.value() == 1);
+ info->securityLevel = static_cast<SecurityLevel>(std::move(optSecLevel.value()));
+ info->versionNumber = static_cast<int32_t>(std::move(optVersion.value()));
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus JavacardKeyMintDevice::generateKey(const vector<KeyParameter>& keyParams,
+ const optional<AttestationKey>& attestationKey,
+ KeyCreationResult* creationResult) {
+ cppbor::Array array;
+ // add key params
+ cbor_.addKeyparameters(array, keyParams);
+ // add attestation key if any
+ cbor_.addAttestationKey(array, attestationKey);
+ auto [item, err] = card_->sendRequest(Instruction::INS_GENERATE_KEY_CMD, array);
+ if (err != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in sending generateKey.";
+ return km_utils::kmError2ScopedAStatus(err);
+ }
+ auto optKeyBlob = cbor_.getByteArrayVec(item, 1);
+ auto optKeyChars = cbor_.getKeyCharacteristics(item, 2);
+ auto optCertChain = cbor_.getCertificateChain(item, 3);
+ if (!optKeyBlob || !optKeyChars || !optCertChain) {
+ LOG(ERROR) << "Error in decoding og response in generateKey.";
+ return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR);
+ }
+ creationResult->keyCharacteristics = std::move(optKeyChars.value());
+ creationResult->certificateChain = std::move(optCertChain.value());
+ creationResult->keyBlob = std::move(optKeyBlob.value());
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus JavacardKeyMintDevice::addRngEntropy(const vector<uint8_t>& data) {
+ cppbor::Array request;
+ // add key data
+ request.add(Bstr(data));
+ auto [item, err] = card_->sendRequest(Instruction::INS_ADD_RNG_ENTROPY_CMD, request);
+ if (err != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in sending addRngEntropy.";
+ return km_utils::kmError2ScopedAStatus(err);
+ }
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus JavacardKeyMintDevice::importKey(const vector<KeyParameter>& keyParams,
+ KeyFormat keyFormat, const vector<uint8_t>& keyData,
+ const optional<AttestationKey>& attestationKey,
+ KeyCreationResult* creationResult) {
+
+ cppbor::Array request;
+ // add key params
+ cbor_.addKeyparameters(request, keyParams);
+ // add key format
+ request.add(Uint(static_cast<uint8_t>(keyFormat)));
+ // add key data
+ request.add(Bstr(keyData));
+ // add attestation key if any
+ cbor_.addAttestationKey(request, attestationKey);
+
+ auto [item, err] = card_->sendRequest(Instruction::INS_IMPORT_KEY_CMD, request);
+ if (err != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in sending data in importKey.";
+ return km_utils::kmError2ScopedAStatus(err);
+ }
+ auto optKeyBlob = cbor_.getByteArrayVec(item, 1);
+ auto optKeyChars = cbor_.getKeyCharacteristics(item, 2);
+ auto optCertChain = cbor_.getCertificateChain(item, 3);
+ if (!optKeyBlob || !optKeyChars || !optCertChain) {
+ LOG(ERROR) << "Error in decoding response in importKey.";
+ return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR);
+ }
+ creationResult->keyCharacteristics = std::move(optKeyChars.value());
+ creationResult->certificateChain = std::move(optCertChain.value());
+ creationResult->keyBlob = std::move(optKeyBlob.value());
+ return ScopedAStatus::ok();
+}
+
+// import wrapped key is divided into 2 stage operation.
+ScopedAStatus JavacardKeyMintDevice::importWrappedKey(const vector<uint8_t>& wrappedKeyData,
+ const vector<uint8_t>& wrappingKeyBlob,
+ const vector<uint8_t>& maskingKey,
+ const vector<KeyParameter>& unwrappingParams,
+ int64_t passwordSid, int64_t biometricSid,
+ KeyCreationResult* creationResult) {
+ cppbor::Array request;
+ std::unique_ptr<Item> item;
+ vector<uint8_t> keyBlob;
+ std::vector<uint8_t> response;
+ vector<KeyCharacteristics> keyCharacteristics;
+ std::vector<uint8_t> iv;
+ std::vector<uint8_t> transitKey;
+ std::vector<uint8_t> secureKey;
+ std::vector<uint8_t> tag;
+ vector<KeyParameter> authList;
+ KeyFormat keyFormat;
+ std::vector<uint8_t> wrappedKeyDescription;
+ keymaster_error_t errorCode = parseWrappedKey(wrappedKeyData, iv, transitKey, secureKey, tag,
+ authList, keyFormat, wrappedKeyDescription);
+ if (errorCode != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in parse wrapped key in importWrappedKey.";
+ return km_utils::kmError2ScopedAStatus(errorCode);
+ }
+
+ // begin import
+ std::tie(item, errorCode) =
+ sendBeginImportWrappedKeyCmd(transitKey, wrappingKeyBlob, maskingKey, unwrappingParams);
+ if (errorCode != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in send begin import wrapped key in importWrappedKey.";
+ return km_utils::kmError2ScopedAStatus(errorCode);
+ }
+ // Finish the import
+ std::tie(item, errorCode) = sendFinishImportWrappedKeyCmd(
+ authList, keyFormat, secureKey, tag, iv, wrappedKeyDescription, passwordSid, biometricSid);
+ if (errorCode != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in send finish import wrapped key in importWrappedKey.";
+ return km_utils::kmError2ScopedAStatus(errorCode);
+ }
+ auto optKeyBlob = cbor_.getByteArrayVec(item, 1);
+ auto optKeyChars = cbor_.getKeyCharacteristics(item, 2);
+ auto optCertChain = cbor_.getCertificateChain(item, 3);
+ if (!optKeyBlob || !optKeyChars || !optCertChain) {
+ LOG(ERROR) << "Error in decoding the response in importWrappedKey.";
+ return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR);
+ }
+ creationResult->keyCharacteristics = std::move(optKeyChars.value());
+ creationResult->certificateChain = std::move(optCertChain.value());
+ creationResult->keyBlob = std::move(optKeyBlob.value());
+ return ScopedAStatus::ok();
+}
+
+std::tuple<std::unique_ptr<Item>, keymaster_error_t>
+JavacardKeyMintDevice::sendBeginImportWrappedKeyCmd(const std::vector<uint8_t>& transitKey,
+ const std::vector<uint8_t>& wrappingKeyBlob,
+ const std::vector<uint8_t>& maskingKey,
+ const vector<KeyParameter>& unwrappingParams) {
+ Array request;
+ request.add(std::vector<uint8_t>(transitKey));
+ request.add(std::vector<uint8_t>(wrappingKeyBlob));
+ request.add(std::vector<uint8_t>(maskingKey));
+ cbor_.addKeyparameters(request, unwrappingParams);
+ return card_->sendRequest(Instruction::INS_BEGIN_IMPORT_WRAPPED_KEY_CMD, request);
+}
+
+std::tuple<std::unique_ptr<Item>, keymaster_error_t>
+JavacardKeyMintDevice::sendFinishImportWrappedKeyCmd(
+ const vector<KeyParameter>& keyParams, KeyFormat keyFormat,
+ const std::vector<uint8_t>& secureKey, const std::vector<uint8_t>& tag,
+ const std::vector<uint8_t>& iv, const std::vector<uint8_t>& wrappedKeyDescription,
+ int64_t passwordSid, int64_t biometricSid) {
+ Array request;
+ cbor_.addKeyparameters(request, keyParams);
+ request.add(static_cast<uint64_t>(keyFormat));
+ request.add(std::vector<uint8_t>(secureKey));
+ request.add(std::vector<uint8_t>(tag));
+ request.add(std::vector<uint8_t>(iv));
+ request.add(std::vector<uint8_t>(wrappedKeyDescription));
+ request.add(Uint(passwordSid));
+ request.add(Uint(biometricSid));
+ return card_->sendRequest(Instruction::INS_FINISH_IMPORT_WRAPPED_KEY_CMD, request);
+}
+
+ScopedAStatus JavacardKeyMintDevice::upgradeKey(const vector<uint8_t>& keyBlobToUpgrade,
+ const vector<KeyParameter>& upgradeParams,
+ vector<uint8_t>* keyBlob) {
+ cppbor::Array request;
+ // add key blob
+ request.add(Bstr(keyBlobToUpgrade));
+ // add key params
+ cbor_.addKeyparameters(request, upgradeParams);
+ auto [item, err] = card_->sendRequest(Instruction::INS_UPGRADE_KEY_CMD, request);
+ if (err != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in sending in upgradeKey.";
+ return km_utils::kmError2ScopedAStatus(err);
+ }
+ auto optKeyBlob = cbor_.getByteArrayVec(item, 1);
+ if (!optKeyBlob) {
+ LOG(ERROR) << "Error in decoding the response in upgradeKey.";
+ return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR);
+ }
+ *keyBlob = std::move(optKeyBlob.value());
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus JavacardKeyMintDevice::deleteKey(const vector<uint8_t>& keyBlob) {
+ Array request;
+ request.add(Bstr(keyBlob));
+ auto [item, err] = card_->sendRequest(Instruction::INS_DELETE_KEY_CMD, request);
+ if (err != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in sending in deleteKey.";
+ return km_utils::kmError2ScopedAStatus(err);
+ }
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus JavacardKeyMintDevice::deleteAllKeys() {
+ auto [item, err] = card_->sendRequest(Instruction::INS_DELETE_ALL_KEYS_CMD);
+ if (err != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in sending in deleteAllKeys.";
+ return km_utils::kmError2ScopedAStatus(err);
+ }
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus JavacardKeyMintDevice::destroyAttestationIds() {
+ auto [item, err] = card_->sendRequest(Instruction::INS_DESTROY_ATT_IDS_CMD);
+ if (err != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in sending in destroyAttestationIds.";
+ return km_utils::kmError2ScopedAStatus(err);
+ }
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus JavacardKeyMintDevice::begin(KeyPurpose purpose, const std::vector<uint8_t>& keyBlob,
+ const std::vector<KeyParameter>& params,
+ const std::optional<HardwareAuthToken>& authToken,
+ BeginResult* result) {
+
+ cppbor::Array array;
+ std::vector<uint8_t> response;
+ // make request
+ array.add(Uint(static_cast<uint64_t>(purpose)));
+ array.add(Bstr(keyBlob));
+ cbor_.addKeyparameters(array, params);
+ HardwareAuthToken token = authToken.value_or(HardwareAuthToken());
+ cbor_.addHardwareAuthToken(array, token);
+
+ // Send earlyBootEnded if there is any pending earlybootEnded event.
+ auto retErr = card_->sendEarlyBootEndedEvent(false);
+ if (retErr != KM_ERROR_OK) {
+ return km_utils::kmError2ScopedAStatus(retErr);
+ ;
+ }
+
+ auto [item, err] = card_->sendRequest(Instruction::INS_BEGIN_OPERATION_CMD, array);
+ if (err != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in sending in begin.";
+ return km_utils::kmError2ScopedAStatus(err);
+ }
+ // return the result
+ auto keyParams = cbor_.getKeyParameters(item, 1);
+ auto optOpHandle = cbor_.getUint64(item, 2);
+ auto optBufMode = cbor_.getUint64(item, 3);
+ auto optMacLength = cbor_.getUint64(item, 4);
+
+ if (!keyParams || !optOpHandle || !optBufMode || !optMacLength) {
+ LOG(ERROR) << "Error in decoding the response in begin.";
+ return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR);
+ }
+ result->params = std::move(keyParams.value());
+ result->challenge = optOpHandle.value();
+ result->operation = ndk::SharedRefBase::make<JavacardKeyMintOperation>(
+ static_cast<keymaster_operation_handle_t>(optOpHandle.value()),
+ static_cast<BufferingMode>(optBufMode.value()), optMacLength.value(), card_);
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus
+JavacardKeyMintDevice::deviceLocked(bool passwordOnly,
+ const std::optional<TimeStampToken>& timestampToken) {
+ Array request;
+ int8_t password = 1;
+ if (!passwordOnly) {
+ password = 0;
+ }
+ request.add(Uint(password));
+ cbor_.addTimeStampToken(request, timestampToken.value_or(TimeStampToken()));
+ auto [item, err] = card_->sendRequest(Instruction::INS_DEVICE_LOCKED_CMD, request);
+ if (err != KM_ERROR_OK) {
+ return km_utils::kmError2ScopedAStatus(err);
+ }
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus JavacardKeyMintDevice::earlyBootEnded() {
+ auto err = card_->sendEarlyBootEndedEvent(true);
+ if (err != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in sending earlyBootEndedEvent.";
+ return km_utils::kmError2ScopedAStatus(err);
+ }
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus JavacardKeyMintDevice::getKeyCharacteristics(
+ const std::vector<uint8_t>& keyBlob, const std::vector<uint8_t>& appId,
+ const std::vector<uint8_t>& appData, std::vector<KeyCharacteristics>* result) {
+ cppbor::Array request;
+ request.add(vector<uint8_t>(keyBlob));
+ request.add(vector<uint8_t>(appId));
+ request.add(vector<uint8_t>(appData));
+ auto [item, err] = card_->sendRequest(Instruction::INS_GET_KEY_CHARACTERISTICS_CMD, request);
+ if (err != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in sending in getKeyCharacteristics.";
+ return km_utils::kmError2ScopedAStatus(err);
+ }
+ auto optKeyChars = cbor_.getKeyCharacteristics(item, 1);
+ if (!optKeyChars) {
+ LOG(ERROR) << "Error in sending in upgradeKey.";
+ return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR);
+ }
+ *result = std::move(optKeyChars.value());
+ return ScopedAStatus::ok();
+}
+
+keymaster_error_t
+JavacardKeyMintDevice::parseWrappedKey(const vector<uint8_t>& wrappedKeyData,
+ std::vector<uint8_t>& iv, std::vector<uint8_t>& transitKey,
+ std::vector<uint8_t>& secureKey, std::vector<uint8_t>& tag,
+ vector<KeyParameter>& authList, KeyFormat& keyFormat,
+ std::vector<uint8_t>& wrappedKeyDescription) {
+ KeymasterBlob kmIv;
+ KeymasterKeyBlob kmTransitKey;
+ KeymasterKeyBlob kmSecureKey;
+ KeymasterBlob kmTag;
+ AuthorizationSet authSet;
+ keymaster_key_format_t kmKeyFormat;
+ KeymasterBlob kmWrappedKeyDescription;
+
+ size_t keyDataLen = wrappedKeyData.size();
+ uint8_t* keyData = dup_buffer(wrappedKeyData.data(), keyDataLen);
+ keymaster_key_blob_t keyMaterial = {keyData, keyDataLen};
+ keymaster_error_t error =
+ parse_wrapped_key(KeymasterKeyBlob(keyMaterial), &kmIv, &kmTransitKey, &kmSecureKey, &kmTag,
+ &authSet, &kmKeyFormat, &kmWrappedKeyDescription);
+ if (error != KM_ERROR_OK) {
+ LOG(ERROR) << "Error parsing wrapped key.";
+ return error;
+ }
+ iv = km_utils::kmBlob2vector(kmIv);
+ transitKey = km_utils::kmBlob2vector(kmTransitKey);
+ secureKey = km_utils::kmBlob2vector(kmSecureKey);
+ tag = km_utils::kmBlob2vector(kmTag);
+ authList = km_utils::kmParamSet2Aidl(authSet);
+ keyFormat = static_cast<KeyFormat>(kmKeyFormat);
+ wrappedKeyDescription = km_utils::kmBlob2vector(kmWrappedKeyDescription);
+ return KM_ERROR_OK;
+}
+
+ScopedAStatus JavacardKeyMintDevice::convertStorageKeyToEphemeral(
+ const std::vector<uint8_t>& /* storageKeyBlob */,
+ std::vector<uint8_t>* /* ephemeralKeyBlob */) {
+ return km_utils::kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
+}
+
+ScopedAStatus JavacardKeyMintDevice::getRootOfTrustChallenge(array<uint8_t, 16>* challenge) {
+ auto [item, err] = card_->sendRequest(Instruction::INS_GET_ROT_CHALLENGE_CMD);
+ if (err != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in sending in getRootOfTrustChallenge.";
+ return km_utils::kmError2ScopedAStatus(err);
+ }
+ auto optChallenge = cbor_.getByteArrayVec(item, 1);
+ if (!optChallenge) {
+ LOG(ERROR) << "Error in sending in upgradeKey.";
+ return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR);
+ }
+ std::move(optChallenge->begin(), optChallenge->begin() + 16, challenge->begin());
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus JavacardKeyMintDevice::getRootOfTrust(const array<uint8_t, 16>& /*challenge*/,
+ vector<uint8_t>* /*rootOfTrust*/) {
+ return km_utils::kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
+}
+
+ScopedAStatus JavacardKeyMintDevice::sendRootOfTrust(const vector<uint8_t>& rootOfTrust) {
+ cppbor::Array request;
+ request.add(EncodedItem(rootOfTrust)); // taggedItem.
+ auto [item, err] = card_->sendRequest(Instruction::INS_SEND_ROT_DATA_CMD, request);
+ if (err != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in sending in sendRootOfTrust.";
+ return km_utils::kmError2ScopedAStatus(err);
+ }
+ LOG(INFO) << "JavacardKeyMintDevice::sendRootOfTrust success";
+ return ScopedAStatus::ok();
+}
+
+} // namespace aidl::android::hardware::security::keymint
diff --git a/ready_se/google/keymint/KM200/HAL/JavacardKeyMintDevice.h b/ready_se/google/keymint/KM200/HAL/JavacardKeyMintDevice.h
new file mode 100644
index 0000000..adf0f7d
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/JavacardKeyMintDevice.h
@@ -0,0 +1,124 @@
+/*
+ * 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 <aidl/android/hardware/security/keymint/BnKeyMintDevice.h>
+#include <aidl/android/hardware/security/keymint/BnKeyMintOperation.h>
+#include <aidl/android/hardware/security/keymint/HardwareAuthToken.h>
+#include <aidl/android/hardware/security/sharedsecret/SharedSecretParameters.h>
+
+#include "CborConverter.h"
+#include "JavacardSecureElement.h"
+
+namespace aidl::android::hardware::security::keymint {
+using cppbor::Item;
+using ::keymint::javacard::CborConverter;
+using ::keymint::javacard::JavacardSecureElement;
+using ndk::ScopedAStatus;
+using secureclock::TimeStampToken;
+using std::array;
+using std::optional;
+using std::shared_ptr;
+using std::vector;
+
+class JavacardKeyMintDevice : public BnKeyMintDevice {
+ public:
+ explicit JavacardKeyMintDevice(shared_ptr<JavacardSecureElement> card)
+ : securitylevel_(SecurityLevel::STRONGBOX), card_(card) {
+ card_->initializeJavacard();
+ }
+ virtual ~JavacardKeyMintDevice() {}
+
+ ScopedAStatus getHardwareInfo(KeyMintHardwareInfo* info) override;
+
+ ScopedAStatus addRngEntropy(const vector<uint8_t>& data) override;
+
+ ScopedAStatus generateKey(const vector<KeyParameter>& keyParams,
+ const optional<AttestationKey>& attestationKey,
+ KeyCreationResult* creationResult) override;
+
+ ScopedAStatus importKey(const vector<KeyParameter>& keyParams, KeyFormat keyFormat,
+ const vector<uint8_t>& keyData,
+ const optional<AttestationKey>& attestationKey,
+ KeyCreationResult* creationResult) override;
+
+ ScopedAStatus importWrappedKey(const vector<uint8_t>& wrappedKeyData,
+ const vector<uint8_t>& wrappingKeyBlob,
+ const vector<uint8_t>& maskingKey,
+ const vector<KeyParameter>& unwrappingParams,
+ int64_t passwordSid, int64_t biometricSid,
+ KeyCreationResult* creationResult) override;
+
+ ScopedAStatus upgradeKey(const vector<uint8_t>& keyBlobToUpgrade,
+ const vector<KeyParameter>& upgradeParams,
+ vector<uint8_t>* keyBlob) override;
+
+ ScopedAStatus deleteKey(const vector<uint8_t>& keyBlob) override;
+ ScopedAStatus deleteAllKeys() override;
+ ScopedAStatus destroyAttestationIds() override;
+
+ virtual ScopedAStatus begin(KeyPurpose in_purpose, const std::vector<uint8_t>& in_keyBlob,
+ const std::vector<KeyParameter>& in_params,
+ const std::optional<HardwareAuthToken>& in_authToken,
+ BeginResult* _aidl_return) override;
+
+ ScopedAStatus deviceLocked(bool passwordOnly,
+ const optional<TimeStampToken>& timestampToken) override;
+
+ ScopedAStatus earlyBootEnded() override;
+
+ ScopedAStatus getKeyCharacteristics(const std::vector<uint8_t>& in_keyBlob,
+ const std::vector<uint8_t>& in_appId,
+ const std::vector<uint8_t>& in_appData,
+ std::vector<KeyCharacteristics>* _aidl_return) override;
+
+ ScopedAStatus convertStorageKeyToEphemeral(const std::vector<uint8_t>& storageKeyBlob,
+ std::vector<uint8_t>* ephemeralKeyBlob) override;
+
+ ScopedAStatus getRootOfTrustChallenge(array<uint8_t, 16>* challenge) override;
+
+ ScopedAStatus getRootOfTrust(const array<uint8_t, 16>& challenge,
+ vector<uint8_t>* rootOfTrust) override;
+
+ ScopedAStatus sendRootOfTrust(const vector<uint8_t>& rootOfTrust) override;
+
+ private:
+ keymaster_error_t parseWrappedKey(const vector<uint8_t>& wrappedKeyData,
+ std::vector<uint8_t>& iv, std::vector<uint8_t>& transitKey,
+ std::vector<uint8_t>& secureKey, std::vector<uint8_t>& tag,
+ vector<KeyParameter>& authList, KeyFormat& keyFormat,
+ std::vector<uint8_t>& wrappedKeyDescription);
+
+ std::tuple<std::unique_ptr<Item>, keymaster_error_t> sendBeginImportWrappedKeyCmd(
+ const std::vector<uint8_t>& transitKey, const std::vector<uint8_t>& wrappingKeyBlob,
+ const std::vector<uint8_t>& maskingKey, const vector<KeyParameter>& unwrappingParams);
+
+ std::tuple<std::unique_ptr<Item>, keymaster_error_t>
+ sendFinishImportWrappedKeyCmd(const vector<KeyParameter>& keyParams, KeyFormat keyFormat,
+ const std::vector<uint8_t>& secureKey,
+ const std::vector<uint8_t>& tag, const std::vector<uint8_t>& iv,
+ const std::vector<uint8_t>& wrappedKeyDescription,
+ int64_t passwordSid, int64_t biometricSid);
+
+ ScopedAStatus defaultHwInfo(KeyMintHardwareInfo* info);
+
+ const SecurityLevel securitylevel_;
+ const shared_ptr<JavacardSecureElement> card_;
+ CborConverter cbor_;
+};
+
+} // namespace aidl::android::hardware::security::keymint
diff --git a/ready_se/google/keymint/KM200/HAL/JavacardKeyMintOperation.cpp b/ready_se/google/keymint/KM200/HAL/JavacardKeyMintOperation.cpp
new file mode 100644
index 0000000..a46f066
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/JavacardKeyMintOperation.cpp
@@ -0,0 +1,300 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "javacard.strongbox.keymint.operation-impl"
+
+#include "JavacardKeyMintOperation.h"
+
+#include <KeyMintUtils.h>
+#include <aidl/android/hardware/security/keymint/ErrorCode.h>
+#include <aidl/android/hardware/security/secureclock/ISecureClock.h>
+#include <android-base/logging.h>
+
+#include "CborConverter.h"
+
+namespace aidl::android::hardware::security::keymint {
+using cppbor::Bstr;
+using cppbor::Uint;
+using secureclock::TimeStampToken;
+
+JavacardKeyMintOperation::~JavacardKeyMintOperation() {
+ if (opHandle_ != 0) {
+ JavacardKeyMintOperation::abort();
+ }
+}
+
+ScopedAStatus JavacardKeyMintOperation::updateAad(const vector<uint8_t>& input,
+ const optional<HardwareAuthToken>& authToken,
+ const optional<TimeStampToken>& timestampToken) {
+ cppbor::Array request;
+ request.add(Uint(opHandle_));
+ request.add(Bstr(input));
+ cbor_.addHardwareAuthToken(request, authToken.value_or(HardwareAuthToken()));
+ cbor_.addTimeStampToken(request, timestampToken.value_or(TimeStampToken()));
+ auto [item, err] = card_->sendRequest(Instruction::INS_UPDATE_AAD_OPERATION_CMD, request);
+ if (err != KM_ERROR_OK) {
+ return km_utils::kmError2ScopedAStatus(err);
+ }
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus JavacardKeyMintOperation::update(const vector<uint8_t>& input,
+ const optional<HardwareAuthToken>& authToken,
+ const optional<TimeStampToken>& timestampToken,
+ vector<uint8_t>* output) {
+ HardwareAuthToken aToken = authToken.value_or(HardwareAuthToken());
+ TimeStampToken tToken = timestampToken.value_or(TimeStampToken());
+ DataView view = {.buffer = {}, .data = input, .start = 0, .length = input.size()};
+ keymaster_error_t err = bufferData(view);
+ if (err != KM_ERROR_OK) {
+ return km_utils::kmError2ScopedAStatus(err);
+ }
+ if (!(bufferingMode_ == BufferingMode::EC_NO_DIGEST ||
+ bufferingMode_ == BufferingMode::RSA_DECRYPT_OR_NO_DIGEST)) {
+ if (view.length > MAX_CHUNK_SIZE) {
+ err = updateInChunks(view, aToken, tToken, output);
+ if (err != KM_ERROR_OK) {
+ return km_utils::kmError2ScopedAStatus(err);
+ }
+ }
+ vector<uint8_t> remaining = popNextChunk(view, view.length);
+ err = sendUpdate(remaining, aToken, tToken, *output);
+ }
+ return km_utils::kmError2ScopedAStatus(err);
+}
+
+ScopedAStatus JavacardKeyMintOperation::finish(const optional<vector<uint8_t>>& input,
+ const optional<vector<uint8_t>>& signature,
+ const optional<HardwareAuthToken>& authToken,
+ const optional<TimeStampToken>& timestampToken,
+ const optional<vector<uint8_t>>& confirmationToken,
+ vector<uint8_t>* output) {
+ HardwareAuthToken aToken = authToken.value_or(HardwareAuthToken());
+ TimeStampToken tToken = timestampToken.value_or(TimeStampToken());
+ const vector<uint8_t> confToken = confirmationToken.value_or(vector<uint8_t>());
+ const vector<uint8_t> inData = input.value_or(vector<uint8_t>());
+ DataView view = {.buffer = {}, .data = inData, .start = 0, .length = inData.size()};
+ const vector<uint8_t> sign = signature.value_or(vector<uint8_t>());
+ if (!(bufferingMode_ == BufferingMode::EC_NO_DIGEST ||
+ bufferingMode_ == BufferingMode::RSA_DECRYPT_OR_NO_DIGEST)) {
+ appendBufferedData(view);
+ if (view.length > MAX_CHUNK_SIZE) {
+ auto err = updateInChunks(view, aToken, tToken, output);
+ if (err != KM_ERROR_OK) {
+ return km_utils::kmError2ScopedAStatus(err);
+ }
+ }
+ } else {
+ keymaster_error_t err = bufferData(view);
+ if (err != KM_ERROR_OK) {
+ return km_utils::kmError2ScopedAStatus(err);
+ }
+ appendBufferedData(view);
+ }
+ vector<uint8_t> remaining = popNextChunk(view, view.length);
+ return km_utils::kmError2ScopedAStatus(
+ sendFinish(remaining, sign, aToken, tToken, confToken, *output));
+}
+
+ScopedAStatus JavacardKeyMintOperation::abort() {
+ Array request;
+ request.add(Uint(opHandle_));
+ auto [item, err] = card_->sendRequest(Instruction::INS_ABORT_OPERATION_CMD, request);
+ opHandle_ = 0;
+ buffer_.clear();
+ return km_utils::kmError2ScopedAStatus(err);
+}
+
+void JavacardKeyMintOperation::blockAlign(DataView& view, uint16_t blockSize) {
+ appendBufferedData(view);
+ uint16_t offset = getDataViewOffset(view, blockSize);
+ if (view.buffer.empty() && !view.data.empty()) {
+ buffer_.insert(buffer_.end(), view.data.begin() + offset, view.data.end());
+ } else if (view.data.empty() && !view.buffer.empty()) {
+ buffer_.insert(buffer_.end(), view.buffer.begin() + offset, view.buffer.end());
+ } else {
+ if (offset < view.buffer.size()) {
+ buffer_.insert(buffer_.end(), view.buffer.begin() + offset, view.buffer.end());
+ buffer_.insert(buffer_.end(), view.data.begin(), view.data.end());
+ } else {
+ offset = offset - view.buffer.size();
+ buffer_.insert(buffer_.end(), view.data.begin() + offset, view.data.end());
+ }
+ }
+ // adjust the view length by removing the buffered data size from it.
+ view.length = view.length - buffer_.size();
+}
+
+uint16_t JavacardKeyMintOperation::getDataViewOffset(DataView& view, uint16_t blockSize) {
+ uint16_t offset = 0;
+ uint16_t remaining = 0;
+ switch (bufferingMode_) {
+ case BufferingMode::BUF_DES_DECRYPT_PKCS7_BLOCK_ALIGNED:
+ case BufferingMode::BUF_AES_DECRYPT_PKCS7_BLOCK_ALIGNED:
+ offset = ((view.length / blockSize)) * blockSize;
+ remaining = (view.length % blockSize);
+ if (offset >= blockSize && remaining == 0) {
+ offset -= blockSize;
+ }
+ break;
+ case BufferingMode::BUF_DES_ENCRYPT_PKCS7_BLOCK_ALIGNED:
+ case BufferingMode::BUF_AES_ENCRYPT_PKCS7_BLOCK_ALIGNED:
+ offset = ((view.length / blockSize)) * blockSize;
+ break;
+ case BufferingMode::BUF_AES_GCM_DECRYPT_BLOCK_ALIGNED:
+ if (view.length > macLength_) {
+ offset = (view.length - macLength_);
+ }
+ break;
+ default:
+ break;
+ }
+ return offset;
+}
+
+keymaster_error_t JavacardKeyMintOperation::bufferData(DataView& view) {
+ if (view.data.empty()) return KM_ERROR_OK; // nothing to buffer
+ switch (bufferingMode_) {
+ case BufferingMode::RSA_DECRYPT_OR_NO_DIGEST:
+ buffer_.insert(buffer_.end(), view.data.begin(), view.data.end());
+ if (buffer_.size() > RSA_BUFFER_SIZE) {
+ abort();
+ return KM_ERROR_INVALID_INPUT_LENGTH;
+ }
+ view.start = 0;
+ view.length = 0;
+ break;
+ case BufferingMode::EC_NO_DIGEST:
+ if (buffer_.size() < EC_BUFFER_SIZE) {
+ buffer_.insert(buffer_.end(), view.data.begin(), view.data.end());
+ // Truncate the buffered data if greater then allowed EC buffer size.
+ if (buffer_.size() > EC_BUFFER_SIZE) {
+ buffer_.erase(buffer_.begin() + EC_BUFFER_SIZE, buffer_.end());
+ }
+ }
+ view.start = 0;
+ view.length = 0;
+ break;
+ case BufferingMode::BUF_AES_ENCRYPT_PKCS7_BLOCK_ALIGNED:
+ case BufferingMode::BUF_AES_DECRYPT_PKCS7_BLOCK_ALIGNED:
+ blockAlign(view, AES_BLOCK_SIZE);
+ break;
+ case BufferingMode::BUF_AES_GCM_DECRYPT_BLOCK_ALIGNED:
+ blockAlign(view, macLength_);
+ break;
+ case BufferingMode::BUF_DES_ENCRYPT_PKCS7_BLOCK_ALIGNED:
+ case BufferingMode::BUF_DES_DECRYPT_PKCS7_BLOCK_ALIGNED:
+ blockAlign(view, DES_BLOCK_SIZE);
+ break;
+ case BufferingMode::NONE:
+ break;
+ }
+ return KM_ERROR_OK;
+}
+
+// Incrementally send the request using multiple updates.
+keymaster_error_t JavacardKeyMintOperation::updateInChunks(DataView& view,
+ HardwareAuthToken& authToken,
+ TimeStampToken& timestampToken,
+ vector<uint8_t>* output) {
+ keymaster_error_t sendError = KM_ERROR_UNKNOWN_ERROR;
+ while (view.length > MAX_CHUNK_SIZE) {
+ vector<uint8_t> chunk = popNextChunk(view, MAX_CHUNK_SIZE);
+ sendError = sendUpdate(chunk, authToken, timestampToken, *output);
+ if (sendError != KM_ERROR_OK) {
+ return sendError;
+ }
+ // Clear tokens
+ if (!authToken.mac.empty()) authToken = HardwareAuthToken();
+ if (!timestampToken.mac.empty()) timestampToken = TimeStampToken();
+ }
+ return KM_ERROR_OK;
+}
+
+vector<uint8_t> JavacardKeyMintOperation::popNextChunk(DataView& view, uint32_t chunkSize) {
+ uint32_t start = view.start;
+ uint32_t end = start + ((view.length < chunkSize) ? view.length : chunkSize);
+ vector<uint8_t> chunk;
+ if (start < view.buffer.size()) {
+ if (end < view.buffer.size()) {
+ chunk = {view.buffer.begin() + start, view.buffer.begin() + end};
+ } else {
+ end = end - view.buffer.size();
+ chunk = {view.buffer.begin() + start, view.buffer.end()};
+ chunk.insert(chunk.end(), view.data.begin(), view.data.begin() + end);
+ }
+ } else {
+ start = start - view.buffer.size();
+ end = end - view.buffer.size();
+ chunk = {view.data.begin() + start, view.data.begin() + end};
+ }
+ view.start = view.start + chunk.size();
+ view.length = view.length - chunk.size();
+ return chunk;
+}
+
+keymaster_error_t JavacardKeyMintOperation::sendUpdate(const vector<uint8_t>& input,
+ const HardwareAuthToken& authToken,
+ const TimeStampToken& timestampToken,
+ vector<uint8_t>& output) {
+ if (input.empty()) {
+ return KM_ERROR_OK;
+ }
+ cppbor::Array request;
+ request.add(Uint(opHandle_));
+ request.add(Bstr(input));
+ cbor_.addHardwareAuthToken(request, authToken);
+ cbor_.addTimeStampToken(request, timestampToken);
+ auto [item, error] = card_->sendRequest(Instruction::INS_UPDATE_OPERATION_CMD, request);
+ if (error != KM_ERROR_OK) {
+ return error;
+ }
+ auto optTemp = cbor_.getByteArrayVec(item, 1);
+ if (!optTemp) {
+ return KM_ERROR_UNKNOWN_ERROR;
+ }
+ output.insert(output.end(), optTemp.value().begin(), optTemp.value().end());
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t JavacardKeyMintOperation::sendFinish(const vector<uint8_t>& data,
+ const vector<uint8_t>& sign,
+ const HardwareAuthToken& authToken,
+ const TimeStampToken& timestampToken,
+ const vector<uint8_t>& confToken,
+ vector<uint8_t>& output) {
+ cppbor::Array request;
+ request.add(Uint(opHandle_));
+ request.add(Bstr(data));
+ request.add(Bstr(sign));
+ cbor_.addHardwareAuthToken(request, authToken);
+ cbor_.addTimeStampToken(request, timestampToken);
+ request.add(Bstr(confToken));
+
+ auto [item, err] = card_->sendRequest(Instruction::INS_FINISH_OPERATION_CMD, request);
+ if (err != KM_ERROR_OK) {
+ return err;
+ }
+ auto optTemp = cbor_.getByteArrayVec(item, 1);
+ if (!optTemp) {
+ return KM_ERROR_UNKNOWN_ERROR;
+ }
+ opHandle_ = 0;
+ output.insert(output.end(), optTemp.value().begin(), optTemp.value().end());
+ return KM_ERROR_OK;
+}
+
+} // namespace aidl::android::hardware::security::keymint
diff --git a/ready_se/google/keymint/KM200/HAL/JavacardKeyMintOperation.h b/ready_se/google/keymint/KM200/HAL/JavacardKeyMintOperation.h
new file mode 100644
index 0000000..c1d967a
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/JavacardKeyMintOperation.h
@@ -0,0 +1,136 @@
+/*
+ * 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 <vector>
+
+#include <aidl/android/hardware/security/keymint/BnKeyMintOperation.h>
+#include <aidl/android/hardware/security/secureclock/ISecureClock.h>
+#include <hardware/keymaster_defs.h>
+
+#include "CborConverter.h"
+#include "JavacardSecureElement.h"
+
+#define AES_BLOCK_SIZE 16
+#define DES_BLOCK_SIZE 8
+#define RSA_BUFFER_SIZE 256
+#define EC_BUFFER_SIZE 32
+#define MAX_CHUNK_SIZE 256
+
+namespace aidl::android::hardware::security::keymint {
+using cppbor::Array;
+using cppbor::Item;
+using ::keymint::javacard::CborConverter;
+using ::keymint::javacard::Instruction;
+using ::keymint::javacard::JavacardSecureElement;
+using ::ndk::ScopedAStatus;
+using secureclock::TimeStampToken;
+using std::optional;
+using std::shared_ptr;
+using std::vector;
+
+// Bufferig modes for update
+enum class BufferingMode : int32_t {
+ NONE = 0, // Send everything to javacard - most of the assymteric operations
+ RSA_DECRYPT_OR_NO_DIGEST =
+ 1, // Buffer everything in update upto 256 bytes and send in finish. If
+ // input data is greater then 256 bytes then it is an error. Javacard
+ // will further check according to exact key size and crypto provider.
+ EC_NO_DIGEST = 2, // Buffer upto 65 bytes and then truncate. Javacard will further truncate
+ // upto exact keysize.
+ BUF_AES_ENCRYPT_PKCS7_BLOCK_ALIGNED = 3, // Buffer 16 bytes.
+ BUF_AES_DECRYPT_PKCS7_BLOCK_ALIGNED = 4, // Buffer 16 bytes.
+ BUF_DES_ENCRYPT_PKCS7_BLOCK_ALIGNED = 5, // Buffer 8 bytes.
+ BUF_DES_DECRYPT_PKCS7_BLOCK_ALIGNED = 6, // Buffer 8 bytes.
+ BUF_AES_GCM_DECRYPT_BLOCK_ALIGNED = 7, // Buffer 16 bytes.
+
+};
+
+// The is the view in the input data being processed by update/finish funcion.
+
+struct DataView {
+ vector<uint8_t> buffer; // previously buffered data from cycle n-1
+ const vector<uint8_t>& data; // current data in cycle n.
+ uint32_t start; // start of the view
+ size_t length; // length of the view
+};
+
+class JavacardKeyMintOperation : public BnKeyMintOperation {
+ public:
+ explicit JavacardKeyMintOperation(keymaster_operation_handle_t opHandle,
+ BufferingMode bufferingMode, uint16_t macLength,
+ shared_ptr<JavacardSecureElement> card)
+ : buffer_(vector<uint8_t>()), bufferingMode_(bufferingMode), macLength_(macLength),
+ card_(card), opHandle_(opHandle) {}
+ virtual ~JavacardKeyMintOperation();
+
+ ScopedAStatus updateAad(const vector<uint8_t>& input,
+ const optional<HardwareAuthToken>& authToken,
+ const optional<TimeStampToken>& timestampToken) override;
+
+ ScopedAStatus update(const vector<uint8_t>& input, const optional<HardwareAuthToken>& authToken,
+ const optional<TimeStampToken>& timestampToken,
+ vector<uint8_t>* output) override;
+
+ ScopedAStatus finish(const optional<vector<uint8_t>>& input,
+ const optional<vector<uint8_t>>& signature,
+ const optional<HardwareAuthToken>& authToken,
+ const optional<TimeStampToken>& timestampToken,
+ const optional<vector<uint8_t>>& confirmationToken,
+ vector<uint8_t>* output) override;
+
+ ScopedAStatus abort() override;
+
+ private:
+ vector<uint8_t> popNextChunk(DataView& view, uint32_t chunkSize);
+
+ keymaster_error_t updateInChunks(DataView& data, HardwareAuthToken& authToken,
+ TimeStampToken& timestampToken, vector<uint8_t>* output);
+
+ keymaster_error_t sendFinish(const vector<uint8_t>& data, const vector<uint8_t>& signature,
+ const HardwareAuthToken& authToken,
+ const TimeStampToken& timestampToken,
+ const vector<uint8_t>& confToken, vector<uint8_t>& output);
+
+ keymaster_error_t sendUpdate(const vector<uint8_t>& data, const HardwareAuthToken& authToken,
+ const TimeStampToken& timestampToken, vector<uint8_t>& output);
+
+ inline void appendBufferedData(DataView& view) {
+ if (!buffer_.empty()) {
+ view.buffer = buffer_;
+ view.length = view.length + buffer_.size();
+ view.start = 0;
+ // view.buffer = insert(data.begin(), buffer_.begin(), buffer_.end());
+ buffer_.clear();
+ }
+ }
+
+ std::tuple<std::unique_ptr<Item>, keymaster_error_t> sendRequest(Instruction ins,
+ Array& request);
+ keymaster_error_t bufferData(DataView& data);
+ void blockAlign(DataView& data, uint16_t blockSize);
+ uint16_t getDataViewOffset(DataView& view, uint16_t blockSize);
+
+ vector<uint8_t> buffer_;
+ BufferingMode bufferingMode_;
+ uint16_t macLength_;
+ const shared_ptr<JavacardSecureElement> card_;
+ keymaster_operation_handle_t opHandle_;
+ CborConverter cbor_;
+};
+
+} // namespace aidl::android::hardware::security::keymint
diff --git a/ready_se/google/keymint/KM200/HAL/JavacardRemotelyProvisionedComponentDevice.cpp b/ready_se/google/keymint/KM200/HAL/JavacardRemotelyProvisionedComponentDevice.cpp
new file mode 100644
index 0000000..fe9821b
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/JavacardRemotelyProvisionedComponentDevice.cpp
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "javacard.keymint.device.rkp.strongbox-impl"
+
+#include "JavacardRemotelyProvisionedComponentDevice.h"
+
+#include <aidl/android/hardware/security/keymint/MacedPublicKey.h>
+
+#include <KeyMintUtils.h>
+#include <android-base/logging.h>
+#include <keymaster/cppcose/cppcose.h>
+#include <keymaster/remote_provisioning_utils.h>
+
+namespace aidl::android::hardware::security::keymint {
+using cppbor::Array;
+using cppbor::EncodedItem;
+using cppcose::kCoseMac0EntryCount;
+using cppcose::kCoseMac0Payload;
+using ::keymint::javacard::Instruction;
+using std::string;
+
+// RKP error codes defined in keymint applet.
+constexpr int32_t kStatusFailed = 32000;
+constexpr int32_t kStatusInvalidMac = 32001;
+constexpr int32_t kStatusProductionKeyInTestRequest = 32002;
+constexpr int32_t kStatusTestKeyInProductionRequest = 32003;
+constexpr int32_t kStatusInvalidEek = 32004;
+constexpr int32_t kStatusInvalidState = 32005;
+
+namespace {
+
+keymaster_error_t translateRkpErrorCode(int32_t error) {
+ switch (-error) {
+ case kStatusFailed:
+ case kStatusInvalidState:
+ return static_cast<keymaster_error_t>(BnRemotelyProvisionedComponent::STATUS_FAILED);
+ case kStatusInvalidMac:
+ return static_cast<keymaster_error_t>(BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
+ case kStatusProductionKeyInTestRequest:
+ return static_cast<keymaster_error_t>(
+ BnRemotelyProvisionedComponent::STATUS_PRODUCTION_KEY_IN_TEST_REQUEST);
+ case kStatusTestKeyInProductionRequest:
+ return static_cast<keymaster_error_t>(
+ BnRemotelyProvisionedComponent::STATUS_TEST_KEY_IN_PRODUCTION_REQUEST);
+ case kStatusInvalidEek:
+ return static_cast<keymaster_error_t>(BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
+ }
+ return static_cast<keymaster_error_t>(error);
+}
+
+ScopedAStatus defaultHwInfo(RpcHardwareInfo* info) {
+ info->versionNumber = 2;
+ info->rpcAuthorName = "Google";
+ info->supportedEekCurve = RpcHardwareInfo::CURVE_P256;
+ info->uniqueId = "strongbox keymint";
+ return ScopedAStatus::ok();
+}
+
+uint32_t coseKeyEncodedSize(const std::vector<MacedPublicKey>& keysToSign) {
+ uint32_t size = 0;
+ for (auto& macKey : keysToSign) {
+ auto [macedKeyItem, _, coseMacErrMsg] = cppbor::parse(macKey.macedKey);
+ if (!macedKeyItem || !macedKeyItem->asArray() ||
+ macedKeyItem->asArray()->size() != kCoseMac0EntryCount) {
+ LOG(ERROR) << "Invalid COSE_Mac0 structure";
+ return 0;
+ }
+ auto payload = macedKeyItem->asArray()->get(kCoseMac0Payload)->asBstr();
+ if (!payload) return 0;
+ size += payload->value().size();
+ }
+ return size;
+}
+
+} // namespace
+
+ScopedAStatus JavacardRemotelyProvisionedComponentDevice::getHardwareInfo(RpcHardwareInfo* info) {
+ auto [item, err] = card_->sendRequest(Instruction::INS_GET_RKP_HARDWARE_INFO);
+ std::optional<uint64_t> optVersionNumber;
+ std::optional<uint64_t> optSupportedEekCurve;
+ std::optional<string> optRpcAuthorName;
+ std::optional<string> optUniqueId;
+ if (err != KM_ERROR_OK || !(optVersionNumber = cbor_.getUint64(item, 1)) ||
+ !(optRpcAuthorName = cbor_.getByteArrayStr(item, 2)) ||
+ !(optSupportedEekCurve = cbor_.getUint64(item, 3)) ||
+ !(optUniqueId = cbor_.getByteArrayStr(item, 4))) {
+ LOG(ERROR) << "Error in response of getHardwareInfo.";
+ LOG(INFO) << "Returning defaultHwInfo in getHardwareInfo.";
+ return defaultHwInfo(info);
+ }
+ info->rpcAuthorName = std::move(optRpcAuthorName.value());
+ info->versionNumber = static_cast<int32_t>(std::move(optVersionNumber.value()));
+ info->supportedEekCurve = static_cast<int32_t>(std::move(optSupportedEekCurve.value()));
+ info->uniqueId = std::move(optUniqueId.value());
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus JavacardRemotelyProvisionedComponentDevice::generateEcdsaP256KeyPair(
+ bool testMode, MacedPublicKey* macedPublicKey, std::vector<uint8_t>* privateKeyHandle) {
+ cppbor::Array array;
+ array.add(testMode);
+ auto [item, err] = card_->sendRequest(Instruction::INS_GENERATE_RKP_KEY_CMD, array);
+ if (err != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in sending generateEcdsaP256KeyPair.";
+ return km_utils::kmError2ScopedAStatus(translateRkpErrorCode(err));
+ }
+ std::optional<std::vector<uint8_t>> optMacedKey;
+ std::optional<std::vector<uint8_t>> optPKeyHandle;
+ if (!(optMacedKey = cbor_.getByteArrayVec(item, 1)) ||
+ !(optPKeyHandle = cbor_.getByteArrayVec(item, 2))) {
+ LOG(ERROR) << "Error in decoding og response in generateEcdsaP256KeyPair.";
+ return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR);
+ }
+ *privateKeyHandle = std::move(optPKeyHandle.value());
+ macedPublicKey->macedKey = std::move(optMacedKey.value());
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus JavacardRemotelyProvisionedComponentDevice::beginSendData(
+ bool testMode, const std::vector<MacedPublicKey>& keysToSign) {
+ uint32_t totalEncodedSize = coseKeyEncodedSize(keysToSign);
+ cppbor::Array array;
+ array.add(keysToSign.size());
+ array.add(totalEncodedSize);
+ array.add(testMode);
+ auto [_, err] = card_->sendRequest(Instruction::INS_BEGIN_SEND_DATA_CMD, array);
+ if (err != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in beginSendData.";
+ return km_utils::kmError2ScopedAStatus(translateRkpErrorCode(err));
+ }
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus JavacardRemotelyProvisionedComponentDevice::updateMacedKey(
+ const std::vector<MacedPublicKey>& keysToSign) {
+ for (auto& macedPublicKey : keysToSign) {
+ cppbor::Array array;
+ array.add(EncodedItem(macedPublicKey.macedKey));
+ auto [_, err] = card_->sendRequest(Instruction::INS_UPDATE_KEY_CMD, array);
+ if (err != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in updateMacedKey.";
+ return km_utils::kmError2ScopedAStatus(translateRkpErrorCode(err));
+ }
+ }
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus
+JavacardRemotelyProvisionedComponentDevice::updateChallenge(const std::vector<uint8_t>& challenge) {
+ Array array;
+ array.add(challenge);
+ auto [_, err] = card_->sendRequest(Instruction::INS_UPDATE_CHALLENGE_CMD, array);
+ if (err != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in updateChallenge.";
+ return km_utils::kmError2ScopedAStatus(translateRkpErrorCode(err));
+ }
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus JavacardRemotelyProvisionedComponentDevice::updateEEK(
+ const std::vector<uint8_t>& endpointEncCertChain) {
+ std::vector<uint8_t> eekChain = endpointEncCertChain;
+ auto [_, err] = card_->sendRequest(Instruction::INS_UPDATE_EEK_CHAIN_CMD, eekChain);
+ if (err != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in updateEEK.";
+ return km_utils::kmError2ScopedAStatus(translateRkpErrorCode(err));
+ }
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus JavacardRemotelyProvisionedComponentDevice::finishSendData(
+ std::vector<uint8_t>* keysToSignMac, DeviceInfo* deviceInfo,
+ std::vector<uint8_t>& coseEncryptProtectedHeader, cppbor::Map& coseEncryptUnProtectedHeader,
+ std::vector<uint8_t>& partialCipheredData, uint32_t& respFlag) {
+
+ auto [item, err] = card_->sendRequest(Instruction::INS_FINISH_SEND_DATA_CMD);
+ if (err != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in finishSendData.";
+ return km_utils::kmError2ScopedAStatus(translateRkpErrorCode(err));
+ }
+ auto optDecodedKeysToSignMac = cbor_.getByteArrayVec(item, 1);
+ auto optDecodedDeviceInfo = cbor_.getByteArrayVec(item, 2);
+ auto optCEncryptProtectedHeader = cbor_.getByteArrayVec(item, 3);
+ auto optCEncryptUnProtectedHeader = cbor_.getMapItem(item, 4);
+ auto optPCipheredData = cbor_.getByteArrayVec(item, 5);
+ auto optRespFlag = cbor_.getUint64(item, 6);
+ if (!optDecodedKeysToSignMac || !optDecodedDeviceInfo || !optCEncryptProtectedHeader ||
+ !optCEncryptUnProtectedHeader || !optPCipheredData || !optRespFlag) {
+ LOG(ERROR) << "Error in decoding og response in finishSendData.";
+ return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR);
+ }
+ *keysToSignMac = std::move(optDecodedKeysToSignMac.value());
+ deviceInfo->deviceInfo = std::move(optDecodedDeviceInfo.value());
+ coseEncryptProtectedHeader = std::move(optCEncryptProtectedHeader.value());
+ coseEncryptUnProtectedHeader = std::move(optCEncryptUnProtectedHeader.value());
+ partialCipheredData.insert(partialCipheredData.end(), optPCipheredData->begin(),
+ optPCipheredData->end());
+ respFlag = std::move(optRespFlag.value());
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus
+JavacardRemotelyProvisionedComponentDevice::getResponse(std::vector<uint8_t>& partialCipheredData,
+ cppbor::Array& recepientStructure,
+ uint32_t& respFlag) {
+ auto [item, err] = card_->sendRequest(Instruction::INS_GET_RESPONSE_CMD);
+ if (err != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in getResponse.";
+ return km_utils::kmError2ScopedAStatus(translateRkpErrorCode(err));
+ }
+ auto optPCipheredData = cbor_.getByteArrayVec(item, 1);
+ auto optArray = cbor_.getArrayItem(item, 2);
+ auto optRespFlag = cbor_.getUint64(item, 3);
+ if (!optPCipheredData || !optArray || !optRespFlag) {
+ LOG(ERROR) << "Error in decoding og response in getResponse.";
+ return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR);
+ }
+ recepientStructure = std::move(optArray.value());
+ partialCipheredData.insert(partialCipheredData.end(), optPCipheredData->begin(),
+ optPCipheredData->end());
+ respFlag = std::move(optRespFlag.value());
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus JavacardRemotelyProvisionedComponentDevice::generateCertificateRequest(
+ bool testMode, const std::vector<MacedPublicKey>& keysToSign,
+ const std::vector<uint8_t>& endpointEncCertChain, const std::vector<uint8_t>& challenge,
+ DeviceInfo* deviceInfo, ProtectedData* protectedData, std::vector<uint8_t>* keysToSignMac) {
+ std::vector<uint8_t> coseEncryptProtectedHeader;
+ cppbor::Map coseEncryptUnProtectedHeader;
+ cppbor::Array recipients;
+ std::vector<uint8_t> cipheredData;
+ uint32_t respFlag;
+ auto ret = beginSendData(testMode, keysToSign);
+ if (!ret.isOk()) return ret;
+
+ ret = updateMacedKey(keysToSign);
+ if (!ret.isOk()) return ret;
+
+ ret = updateChallenge(challenge);
+ if (!ret.isOk()) return ret;
+
+ ret = updateEEK(endpointEncCertChain);
+ if (!ret.isOk()) return ret;
+
+ ret = finishSendData(keysToSignMac, deviceInfo, coseEncryptProtectedHeader,
+ coseEncryptUnProtectedHeader, cipheredData, respFlag);
+ if (!ret.isOk()) return ret;
+
+ while (respFlag != 0) { // more data is pending to receive
+ ret = getResponse(cipheredData, recipients, respFlag);
+ if (!ret.isOk()) return ret;
+ }
+ // Create ConseEncrypt structure.
+ protectedData->protectedData = cppbor::Array()
+ .add(coseEncryptProtectedHeader) // Protected
+ .add(std::move(coseEncryptUnProtectedHeader)) // Unprotected
+ .add(cipheredData) // Payload
+ .add(std::move(recipients))
+ .encode();
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus JavacardRemotelyProvisionedComponentDevice::generateCertificateRequestV2(
+ const std::vector<MacedPublicKey>& /*keysToSign*/, const std::vector<uint8_t>& /*challenge*/,
+ std::vector<uint8_t>* /*csr*/) {
+ return km_utils::kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
+}
+
+} // namespace aidl::android::hardware::security::keymint
diff --git a/ready_se/google/keymint/KM200/HAL/JavacardRemotelyProvisionedComponentDevice.h b/ready_se/google/keymint/KM200/HAL/JavacardRemotelyProvisionedComponentDevice.h
new file mode 100644
index 0000000..7f41891
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/JavacardRemotelyProvisionedComponentDevice.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cppbor.h>
+
+#include <aidl/android/hardware/security/keymint/BnRemotelyProvisionedComponent.h>
+#include <aidl/android/hardware/security/keymint/RpcHardwareInfo.h>
+#include <aidl/android/hardware/security/keymint/SecurityLevel.h>
+
+#include <keymaster/UniquePtr.h>
+#include <keymaster/android_keymaster.h>
+
+#include "CborConverter.h"
+#include "JavacardSecureElement.h"
+
+namespace aidl::android::hardware::security::keymint {
+using ::keymint::javacard::CborConverter;
+using ::keymint::javacard::JavacardSecureElement;
+using ndk::ScopedAStatus;
+using std::shared_ptr;
+
+class JavacardRemotelyProvisionedComponentDevice : public BnRemotelyProvisionedComponent {
+ public:
+ explicit JavacardRemotelyProvisionedComponentDevice(shared_ptr<JavacardSecureElement> card)
+ : card_(card) {}
+
+ virtual ~JavacardRemotelyProvisionedComponentDevice() = default;
+
+ ScopedAStatus getHardwareInfo(RpcHardwareInfo* info) override;
+
+ ScopedAStatus generateEcdsaP256KeyPair(bool testMode, MacedPublicKey* macedPublicKey,
+ std::vector<uint8_t>* privateKeyHandle) override;
+
+ ScopedAStatus generateCertificateRequest(bool testMode,
+ const std::vector<MacedPublicKey>& keysToSign,
+ const std::vector<uint8_t>& endpointEncCertChain,
+ const std::vector<uint8_t>& challenge,
+ DeviceInfo* deviceInfo, ProtectedData* protectedData,
+ std::vector<uint8_t>* keysToSignMac) override;
+
+ ScopedAStatus generateCertificateRequestV2(const std::vector<MacedPublicKey>& keysToSign,
+ const std::vector<uint8_t>& challenge,
+ std::vector<uint8_t>* csr) override;
+
+ private:
+ ScopedAStatus beginSendData(bool testMode, const std::vector<MacedPublicKey>& keysToSign);
+
+ ScopedAStatus updateMacedKey(const std::vector<MacedPublicKey>& keysToSign);
+
+ ScopedAStatus updateChallenge(const std::vector<uint8_t>& challenge);
+
+ ScopedAStatus updateEEK(const std::vector<uint8_t>& endpointEncCertChain);
+
+ ScopedAStatus finishSendData(std::vector<uint8_t>* keysToSignMac, DeviceInfo* deviceInfo,
+ std::vector<uint8_t>& coseEncryptProtectedHeader,
+ cppbor::Map& coseEncryptUnProtectedHeader,
+ std::vector<uint8_t>& partialCipheredData, uint32_t& respFlag);
+
+ ScopedAStatus getResponse(std::vector<uint8_t>& partialCipheredData,
+ cppbor::Array& recepientStructure, uint32_t& respFlag);
+ std::shared_ptr<JavacardSecureElement> card_;
+ CborConverter cbor_;
+};
+
+} // namespace aidl::android::hardware::security::keymint
diff --git a/ready_se/google/keymint/KM200/HAL/JavacardSecureElement.cpp b/ready_se/google/keymint/KM200/HAL/JavacardSecureElement.cpp
new file mode 100644
index 0000000..7c4f038
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/JavacardSecureElement.cpp
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "javacard.keymint.device.strongbox-impl"
+#include "JavacardSecureElement.h"
+
+#include <algorithm>
+#include <iostream>
+#include <iterator>
+#include <memory>
+#include <regex.h>
+#include <string>
+#include <vector>
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <keymaster/android_keymaster_messages.h>
+
+#include "keymint_utils.h"
+
+namespace keymint::javacard {
+
+keymaster_error_t JavacardSecureElement::initializeJavacard() {
+ Array request;
+ request.add(Uint(getOsVersion()));
+ request.add(Uint(getOsPatchlevel()));
+ request.add(Uint(getVendorPatchlevel()));
+ auto [item, err] = sendRequest(Instruction::INS_INIT_STRONGBOX_CMD, request);
+ return err;
+}
+
+keymaster_error_t JavacardSecureElement::sendEarlyBootEndedEvent(bool eventTriggered) {
+ isEarlyBootEventPending |= eventTriggered;
+ if (!isEarlyBootEventPending) {
+ return KM_ERROR_OK;
+ }
+ auto [item, err] = sendRequest(Instruction::INS_EARLY_BOOT_ENDED_CMD);
+ if (err != KM_ERROR_OK) {
+ // Incase of failure cache the event and send in the next immediate request to Applet.
+ isEarlyBootEventPending = true;
+ return err;
+ }
+ isEarlyBootEventPending = false;
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t JavacardSecureElement::constructApduMessage(Instruction& ins,
+ std::vector<uint8_t>& inputData,
+ std::vector<uint8_t>& apduOut) {
+ apduOut.push_back(static_cast<uint8_t>(APDU_CLS)); // CLS
+ apduOut.push_back(static_cast<uint8_t>(ins)); // INS
+ apduOut.push_back(static_cast<uint8_t>(APDU_P1)); // P1
+ apduOut.push_back(static_cast<uint8_t>(APDU_P2)); // P2
+
+ if (USHRT_MAX >= inputData.size()) {
+ // Send extended length APDU always as response size is not known to HAL.
+ // Case 1: Lc > 0 CLS | INS | P1 | P2 | 00 | 2 bytes of Lc | CommandData | 2 bytes of Le
+ // all set to 00. Case 2: Lc = 0 CLS | INS | P1 | P2 | 3 bytes of Le all set to 00.
+ // Extended length 3 bytes, starts with 0x00
+ apduOut.push_back(static_cast<uint8_t>(0x00));
+ if (inputData.size() > 0) {
+ apduOut.push_back(static_cast<uint8_t>(inputData.size() >> 8));
+ apduOut.push_back(static_cast<uint8_t>(inputData.size() & 0xFF));
+ // Data
+ apduOut.insert(apduOut.end(), inputData.begin(), inputData.end());
+ }
+ // Expected length of output.
+ // Accepting complete length of output every time.
+ apduOut.push_back(static_cast<uint8_t>(0x00));
+ apduOut.push_back(static_cast<uint8_t>(0x00));
+ } else {
+ LOG(ERROR) << "Error in constructApduMessage.";
+ return (KM_ERROR_INVALID_INPUT_LENGTH);
+ }
+ return (KM_ERROR_OK); // success
+}
+
+keymaster_error_t JavacardSecureElement::sendData(Instruction ins, std::vector<uint8_t>& inData,
+ std::vector<uint8_t>& response) {
+ keymaster_error_t ret = KM_ERROR_UNKNOWN_ERROR;
+ std::vector<uint8_t> apdu;
+
+ ret = constructApduMessage(ins, inData, apdu);
+
+ if (ret != KM_ERROR_OK) {
+ return ret;
+ }
+
+ ret = transport_->sendData(apdu, response);
+ if (ret != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in sending data in sendData. " << static_cast<int>(ret);
+ return ret;
+ }
+
+ // Response size should be greater than 2. Cbor output data followed by two bytes of APDU
+ // status.
+ if ((response.size() <= 2) || (getApduStatus(response) != APDU_RESP_STATUS_OK)) {
+ LOG(ERROR) << "Response of the sendData is wrong: response size = " << response.size()
+ << " apdu status = " << getApduStatus(response);
+ return (KM_ERROR_UNKNOWN_ERROR);
+ }
+ // remove the status bytes
+ response.pop_back();
+ response.pop_back();
+ return (KM_ERROR_OK); // success
+}
+
+std::tuple<std::unique_ptr<Item>, keymaster_error_t>
+JavacardSecureElement::sendRequest(Instruction ins, Array& request) {
+ vector<uint8_t> response;
+ // encode request
+ std::vector<uint8_t> command = request.encode();
+ auto sendError = sendData(ins, command, response);
+ if (sendError != KM_ERROR_OK) {
+ return {unique_ptr<Item>(nullptr), sendError};
+ }
+ // decode the response and send that back
+ return cbor_.decodeData(response);
+}
+
+std::tuple<std::unique_ptr<Item>, keymaster_error_t>
+JavacardSecureElement::sendRequest(Instruction ins, std::vector<uint8_t>& command) {
+ vector<uint8_t> response;
+ auto sendError = sendData(ins, command, response);
+ if (sendError != KM_ERROR_OK) {
+ return {unique_ptr<Item>(nullptr), sendError};
+ }
+ // decode the response and send that back
+ return cbor_.decodeData(response);
+}
+
+std::tuple<std::unique_ptr<Item>, keymaster_error_t>
+JavacardSecureElement::sendRequest(Instruction ins) {
+ vector<uint8_t> response;
+ vector<uint8_t> emptyRequest;
+ auto sendError = sendData(ins, emptyRequest, response);
+ if (sendError != KM_ERROR_OK) {
+ return {unique_ptr<Item>(nullptr), sendError};
+ }
+ // decode the response and send that back
+ return cbor_.decodeData(response);
+}
+
+} // namespace keymint::javacard
diff --git a/ready_se/google/keymint/KM200/HAL/JavacardSecureElement.h b/ready_se/google/keymint/KM200/HAL/JavacardSecureElement.h
new file mode 100644
index 0000000..2ea5fe4
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/JavacardSecureElement.h
@@ -0,0 +1,114 @@
+/*
+ * 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 <ITransport.h>
+
+#include "CborConverter.h"
+
+#define APDU_CLS 0x80
+#define APDU_P1 0x50
+#define APDU_P2 0x00
+#define APDU_RESP_STATUS_OK 0x9000
+
+#define KEYMINT_CMD_APDU_START 0x20
+
+namespace keymint::javacard {
+using std::shared_ptr;
+using std::vector;
+
+enum class Instruction {
+ // Keymaster commands
+ INS_GENERATE_KEY_CMD = KEYMINT_CMD_APDU_START + 1,
+ INS_IMPORT_KEY_CMD = KEYMINT_CMD_APDU_START + 2,
+ INS_IMPORT_WRAPPED_KEY_CMD = KEYMINT_CMD_APDU_START + 3,
+ INS_EXPORT_KEY_CMD = KEYMINT_CMD_APDU_START + 4,
+ INS_ATTEST_KEY_CMD = KEYMINT_CMD_APDU_START + 5,
+ INS_UPGRADE_KEY_CMD = KEYMINT_CMD_APDU_START + 6,
+ INS_DELETE_KEY_CMD = KEYMINT_CMD_APDU_START + 7,
+ INS_DELETE_ALL_KEYS_CMD = KEYMINT_CMD_APDU_START + 8,
+ INS_ADD_RNG_ENTROPY_CMD = KEYMINT_CMD_APDU_START + 9,
+ INS_COMPUTE_SHARED_SECRET_CMD = KEYMINT_CMD_APDU_START + 10,
+ INS_DESTROY_ATT_IDS_CMD = KEYMINT_CMD_APDU_START + 11,
+ INS_VERIFY_AUTHORIZATION_CMD = KEYMINT_CMD_APDU_START + 12,
+ INS_GET_SHARED_SECRET_PARAM_CMD = KEYMINT_CMD_APDU_START + 13,
+ INS_GET_KEY_CHARACTERISTICS_CMD = KEYMINT_CMD_APDU_START + 14,
+ INS_GET_HW_INFO_CMD = KEYMINT_CMD_APDU_START + 15,
+ INS_BEGIN_OPERATION_CMD = KEYMINT_CMD_APDU_START + 16,
+ INS_UPDATE_OPERATION_CMD = KEYMINT_CMD_APDU_START + 17,
+ INS_FINISH_OPERATION_CMD = KEYMINT_CMD_APDU_START + 18,
+ INS_ABORT_OPERATION_CMD = KEYMINT_CMD_APDU_START + 19,
+ INS_DEVICE_LOCKED_CMD = KEYMINT_CMD_APDU_START + 20,
+ INS_EARLY_BOOT_ENDED_CMD = KEYMINT_CMD_APDU_START + 21,
+ INS_GET_CERT_CHAIN_CMD = KEYMINT_CMD_APDU_START + 22,
+ INS_UPDATE_AAD_OPERATION_CMD = KEYMINT_CMD_APDU_START + 23,
+ INS_BEGIN_IMPORT_WRAPPED_KEY_CMD = KEYMINT_CMD_APDU_START + 24,
+ INS_FINISH_IMPORT_WRAPPED_KEY_CMD = KEYMINT_CMD_APDU_START + 25,
+ INS_INIT_STRONGBOX_CMD = KEYMINT_CMD_APDU_START + 26,
+ // RKP Commands
+ INS_GET_RKP_HARDWARE_INFO = KEYMINT_CMD_APDU_START + 27,
+ INS_GENERATE_RKP_KEY_CMD = KEYMINT_CMD_APDU_START + 28,
+ INS_BEGIN_SEND_DATA_CMD = KEYMINT_CMD_APDU_START + 29,
+ INS_UPDATE_KEY_CMD = KEYMINT_CMD_APDU_START + 30,
+ INS_UPDATE_EEK_CHAIN_CMD = KEYMINT_CMD_APDU_START + 31,
+ INS_UPDATE_CHALLENGE_CMD = KEYMINT_CMD_APDU_START + 32,
+ INS_FINISH_SEND_DATA_CMD = KEYMINT_CMD_APDU_START + 33,
+ INS_GET_RESPONSE_CMD = KEYMINT_CMD_APDU_START + 34,
+ // SE ROT Commands
+ INS_GET_ROT_CHALLENGE_CMD = KEYMINT_CMD_APDU_START + 45,
+ INS_GET_ROT_DATA_CMD = KEYMINT_CMD_APDU_START + 46,
+ INS_SEND_ROT_DATA_CMD = KEYMINT_CMD_APDU_START + 47,
+};
+
+class JavacardSecureElement {
+ public:
+ explicit JavacardSecureElement(shared_ptr<ITransport> transport, uint32_t osVersion,
+ uint32_t osPatchLevel, uint32_t vendorPatchLevel)
+ : transport_(transport), osVersion_(osVersion), osPatchLevel_(osPatchLevel),
+ vendorPatchLevel_(vendorPatchLevel), isEarlyBootEventPending(false) {
+ transport_->openConnection();
+ }
+ virtual ~JavacardSecureElement() { transport_->closeConnection(); }
+
+ std::tuple<std::unique_ptr<Item>, keymaster_error_t> sendRequest(Instruction ins,
+ Array& request);
+ std::tuple<std::unique_ptr<Item>, keymaster_error_t> sendRequest(Instruction ins);
+ std::tuple<std::unique_ptr<Item>, keymaster_error_t> sendRequest(Instruction ins,
+ std::vector<uint8_t>& command);
+
+ keymaster_error_t sendData(Instruction ins, std::vector<uint8_t>& inData,
+ std::vector<uint8_t>& response);
+
+ keymaster_error_t constructApduMessage(Instruction& ins, std::vector<uint8_t>& inputData,
+ std::vector<uint8_t>& apduOut);
+ keymaster_error_t initializeJavacard();
+ keymaster_error_t sendEarlyBootEndedEvent(bool eventTriggered);
+ inline uint16_t getApduStatus(std::vector<uint8_t>& inputData) {
+ // Last two bytes are the status SW0SW1
+ uint8_t SW0 = inputData.at(inputData.size() - 2);
+ uint8_t SW1 = inputData.at(inputData.size() - 1);
+ return (SW0 << 8 | SW1);
+ }
+
+ shared_ptr<ITransport> transport_;
+ uint32_t osVersion_;
+ uint32_t osPatchLevel_;
+ uint32_t vendorPatchLevel_;
+ bool isEarlyBootEventPending;
+ CborConverter cbor_;
+};
+} // namespace keymint::javacard
diff --git a/ready_se/google/keymint/KM200/HAL/JavacardSharedSecret.cpp b/ready_se/google/keymint/KM200/HAL/JavacardSharedSecret.cpp
new file mode 100644
index 0000000..c5cf9a2
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/JavacardSharedSecret.cpp
@@ -0,0 +1,61 @@
+#define LOG_TAG "javacard.strongbox.keymint.operation-impl"
+#include "JavacardSharedSecret.h"
+
+#include <android-base/logging.h>
+
+#include <KeyMintUtils.h>
+
+namespace aidl::android::hardware::security::sharedsecret {
+using ::keymint::javacard::Instruction;
+
+ScopedAStatus JavacardSharedSecret::getSharedSecretParameters(SharedSecretParameters* params) {
+ auto error = card_->initializeJavacard();
+ if (error != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in initializing javacard.";
+ return keymint::km_utils::kmError2ScopedAStatus(error);
+ }
+ auto [item, err] = card_->sendRequest(Instruction::INS_GET_SHARED_SECRET_PARAM_CMD);
+ if (err != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in sending in getSharedSecretParameters.";
+ return keymint::km_utils::kmError2ScopedAStatus(err);
+ }
+ auto optSSParams = cbor_.getSharedSecretParameters(item, 1);
+ if (!optSSParams) {
+ LOG(ERROR) << "Error in sending in getSharedSecretParameters.";
+ return keymint::km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR);
+ }
+ *params = std::move(optSSParams.value());
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus
+JavacardSharedSecret::computeSharedSecret(const std::vector<SharedSecretParameters>& params,
+ std::vector<uint8_t>* secret) {
+
+ auto error = card_->sendEarlyBootEndedEvent(false);
+ if (error != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in sending earlyBoot event javacard.";
+ return keymint::km_utils::kmError2ScopedAStatus(error);
+ }
+ error = card_->initializeJavacard();
+ if (error != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in initializing javacard.";
+ return keymint::km_utils::kmError2ScopedAStatus(error);
+ }
+ cppbor::Array request;
+ cbor_.addSharedSecretParameters(request, params);
+ auto [item, err] = card_->sendRequest(Instruction::INS_COMPUTE_SHARED_SECRET_CMD, request);
+ if (err != KM_ERROR_OK) {
+ LOG(ERROR) << "Error in sending in computeSharedSecret.";
+ return keymint::km_utils::kmError2ScopedAStatus(err);
+ }
+ auto optSecret = cbor_.getByteArrayVec(item, 1);
+ if (!optSecret) {
+ LOG(ERROR) << "Error in decoding the response in computeSharedSecret.";
+ return keymint::km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR);
+ }
+ *secret = std::move(optSecret.value());
+ return ScopedAStatus::ok();
+}
+
+} // namespace aidl::android::hardware::security::sharedsecret
diff --git a/ready_se/google/keymint/KM200/HAL/JavacardSharedSecret.h b/ready_se/google/keymint/KM200/HAL/JavacardSharedSecret.h
new file mode 100644
index 0000000..340853a
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/JavacardSharedSecret.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include <aidl/android/hardware/security/sharedsecret/BnSharedSecret.h>
+#include <aidl/android/hardware/security/sharedsecret/SharedSecretParameters.h>
+
+#include "CborConverter.h"
+#include "JavacardSecureElement.h"
+
+namespace aidl::android::hardware::security::sharedsecret {
+using ::keymint::javacard::CborConverter;
+using ::keymint::javacard::JavacardSecureElement;
+using ndk::ScopedAStatus;
+using std::shared_ptr;
+using std::vector;
+
+class JavacardSharedSecret : public BnSharedSecret {
+ public:
+ explicit JavacardSharedSecret(shared_ptr<JavacardSecureElement> card) : card_(card) {}
+ virtual ~JavacardSharedSecret() {}
+
+ ScopedAStatus getSharedSecretParameters(SharedSecretParameters* params) override;
+
+ ScopedAStatus computeSharedSecret(const std::vector<SharedSecretParameters>& params,
+ std::vector<uint8_t>* secret) override;
+
+ private:
+ shared_ptr<JavacardSecureElement> card_;
+ CborConverter cbor_;
+};
+
+} // namespace aidl::android::hardware::security::sharedsecret
diff --git a/ready_se/google/keymint/KM200/HAL/LICENSE b/ready_se/google/keymint/KM200/HAL/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/ready_se/google/keymint/KM200/HAL/METADATA b/ready_se/google/keymint/KM200/HAL/METADATA
new file mode 100644
index 0000000..d97975c
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/METADATA
@@ -0,0 +1,3 @@
+third_party {
+ license_type: NOTICE
+}
diff --git a/ready_se/google/keymint/KM200/HAL/OWNERS b/ready_se/google/keymint/KM200/HAL/OWNERS
new file mode 100644
index 0000000..0bd972b
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/OWNERS
@@ -0,0 +1,3 @@
+pathakc@google.com
+subrahmanyaman@google.com
+avinashh@google.com
diff --git a/ready_se/google/keymint/KM200/HAL/OmapiTransport.cpp b/ready_se/google/keymint/KM200/HAL/OmapiTransport.cpp
new file mode 100644
index 0000000..3fd5e43
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/OmapiTransport.cpp
@@ -0,0 +1,276 @@
+/*
+ **
+ ** 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 "OmapiTransport.h"
+
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <vector>
+
+#include <aidl/android/hardware/security/keymint/ErrorCode.h>
+#include <android-base/logging.h>
+
+namespace keymint::javacard {
+using ::aidl::android::hardware::security::keymint::ErrorCode;
+
+constexpr uint8_t KEYMINT_APPLET_AID[] = {0xA0, 0x00, 0x00, 0x00, 0x62, 0x03,
+ 0x02, 0x0C, 0x01, 0x01, 0x01};
+std::string const ESE_READER_PREFIX = "eSE";
+constexpr const char omapiServiceName[] = "android.se.omapi.ISecureElementService/default";
+
+class SEListener : public ::aidl::android::se::omapi::BnSecureElementListener {};
+
+keymaster_error_t OmapiTransport::initialize() {
+
+ LOG(DEBUG) << "Initialize the secure element connection";
+
+ // Get OMAPI vendor stable service handler
+ ::ndk::SpAIBinder ks2Binder(AServiceManager_checkService(omapiServiceName));
+ omapiSeService = aidl::android::se::omapi::ISecureElementService::fromBinder(ks2Binder);
+
+ if (omapiSeService == nullptr) {
+ LOG(ERROR) << "Failed to start omapiSeService null";
+ return static_cast<keymaster_error_t>(ErrorCode::HARDWARE_NOT_YET_AVAILABLE);
+ }
+
+ int size = sizeof(KEYMINT_APPLET_AID) / sizeof(KEYMINT_APPLET_AID[0]);
+ // reset readers, clear readers if already existing
+ if (mVSReaders.size() > 0) {
+ closeConnection();
+ }
+
+ std::vector<std::string> readers = {};
+ // Get available readers
+ auto status = omapiSeService->getReaders(&readers);
+ if (!status.isOk()) {
+ LOG(ERROR) << "getReaders failed to get available readers: " << status.getMessage();
+ return static_cast<keymaster_error_t>(ErrorCode::HARDWARE_TYPE_UNAVAILABLE);
+ }
+
+ // Get SE readers handlers
+ for (auto readerName : readers) {
+ std::shared_ptr<::aidl::android::se::omapi::ISecureElementReader> reader;
+ status = omapiSeService->getReader(readerName, &reader);
+ if (!status.isOk()) {
+ LOG(ERROR) << "getReader for " << readerName.c_str()
+ << " Failed: " << status.getMessage();
+ return static_cast<keymaster_error_t>(ErrorCode::HARDWARE_TYPE_UNAVAILABLE);
+ }
+ mVSReaders[readerName] = reader;
+ }
+
+ // Find eSE reader, as of now assumption is only eSE available on device
+ LOG(DEBUG) << "Finding eSE reader";
+ eSEReader = nullptr;
+ if (mVSReaders.size() > 0) {
+ for (const auto& [name, reader] : mVSReaders) {
+ if (name.find(ESE_READER_PREFIX, 0) != std::string::npos) {
+ LOG(DEBUG) << "eSE reader found: " << name;
+ eSEReader = reader;
+ break;
+ }
+ }
+ }
+
+ if (eSEReader == nullptr) {
+ LOG(ERROR) << "secure element reader " << ESE_READER_PREFIX << " not found";
+ return static_cast<keymaster_error_t>(ErrorCode::HARDWARE_TYPE_UNAVAILABLE);
+ }
+
+ bool isSecureElementPresent = false;
+ auto res = eSEReader->isSecureElementPresent(&isSecureElementPresent);
+ if (!res.isOk()) {
+ eSEReader = nullptr;
+ LOG(ERROR) << "isSecureElementPresent error: " << res.getMessage();
+ return static_cast<keymaster_error_t>(ErrorCode::HARDWARE_TYPE_UNAVAILABLE);
+ }
+ if (!isSecureElementPresent) {
+ LOG(ERROR) << "secure element not found";
+ eSEReader = nullptr;
+ return static_cast<keymaster_error_t>(ErrorCode::HARDWARE_TYPE_UNAVAILABLE);
+ }
+
+ status = eSEReader->openSession(&session);
+ if (!status.isOk()) {
+ LOG(ERROR) << "openSession error: " << status.getMessage();
+ return KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
+ }
+ if (session == nullptr) {
+ LOG(ERROR) << "Could not open session null";
+ return KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
+ }
+
+ std::vector<uint8_t> aid(KEYMINT_APPLET_AID, KEYMINT_APPLET_AID + size);
+ auto mSEListener = ndk::SharedRefBase::make<SEListener>();
+ status = session->openLogicalChannel(aid, 0x00, mSEListener, &channel);
+ if (!status.isOk()) {
+ LOG(ERROR) << "openLogicalChannel error: " << status.getMessage();
+ return KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
+ }
+ if (channel == nullptr) {
+ LOG(ERROR) << "Could not open channel null";
+ return KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
+ }
+
+ return KM_ERROR_OK;
+}
+
+bool OmapiTransport::internalTransmitApdu(
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementReader> reader,
+ std::vector<uint8_t> apdu, std::vector<uint8_t>& transmitResponse) {
+
+ LOG(DEBUG) << "internalTransmitApdu: trasmitting data to secure element";
+ if (reader == nullptr) {
+ LOG(ERROR) << "eSE reader is null";
+ return false;
+ }
+
+ bool result = true;
+ auto res = ndk::ScopedAStatus::ok();
+ if (session != nullptr) {
+ res = session->isClosed(&result);
+ if (!res.isOk()) {
+ LOG(ERROR) << "isClosed error: " << res.getMessage();
+ return KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
+ }
+ }
+ if (result) {
+ res = reader->openSession(&session);
+ if (!res.isOk()) {
+ LOG(ERROR) << "openSession error: " << res.getMessage();
+ return false;
+ }
+ if (session == nullptr) {
+ LOG(ERROR) << "Could not open session null";
+ return false;
+ }
+ }
+
+ result = true;
+ if (channel != nullptr) {
+ res = channel->isClosed(&result);
+ if (!res.isOk()) {
+ LOG(ERROR) << "isClosed error: " << res.getMessage();
+ return KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
+ }
+ }
+
+ int size = sizeof(KEYMINT_APPLET_AID) / sizeof(KEYMINT_APPLET_AID[0]);
+ std::vector<uint8_t> aid(KEYMINT_APPLET_AID, KEYMINT_APPLET_AID + size);
+ if (result) {
+ auto mSEListener = ndk::SharedRefBase::make<SEListener>();
+ res = session->openLogicalChannel(aid, 0x00, mSEListener, &channel);
+ if (!res.isOk()) {
+ LOG(ERROR) << "openLogicalChannel error: " << res.getMessage();
+ return false;
+ }
+ if (channel == nullptr) {
+ LOG(ERROR) << "Could not open channel null";
+ return false;
+ }
+ }
+
+ std::vector<uint8_t> selectResponse = {};
+ res = channel->getSelectResponse(&selectResponse);
+ if (!res.isOk()) {
+ LOG(ERROR) << "getSelectResponse error: " << res.getMessage();
+ return false;
+ }
+
+ if ((selectResponse.size() < 2) ||
+ ((selectResponse[selectResponse.size() - 1] & 0xFF) != 0x00) ||
+ ((selectResponse[selectResponse.size() - 2] & 0xFF) != 0x90)) {
+ LOG(ERROR) << "Failed to select the Applet.";
+ return false;
+ }
+
+ res = channel->transmit(apdu, &transmitResponse);
+
+ LOG(INFO) << "STATUS OF TRNSMIT: " << res.getExceptionCode()
+ << " Message: " << res.getMessage();
+ if (!res.isOk()) {
+ LOG(ERROR) << "transmit error: " << res.getMessage();
+ return false;
+ }
+
+ return true;
+}
+
+keymaster_error_t OmapiTransport::openConnection() {
+
+ // if already conection setup done, no need to initialise it again.
+ if (isConnected()) {
+ return KM_ERROR_OK;
+ }
+ return initialize();
+}
+
+keymaster_error_t OmapiTransport::sendData(const vector<uint8_t>& inData, vector<uint8_t>& output) {
+
+ if (!isConnected()) {
+ // Try to initialize connection to eSE
+ LOG(INFO) << "Failed to send data, try to initialize connection SE connection";
+ auto res = initialize();
+ if (res != KM_ERROR_OK) {
+ LOG(ERROR) << "Failed to send data, initialization not completed";
+ closeConnection();
+ return res;
+ }
+ }
+
+ if (eSEReader != nullptr) {
+ LOG(DEBUG) << "Sending apdu data to secure element: " << ESE_READER_PREFIX;
+ if (internalTransmitApdu(eSEReader, inData, output)) {
+ return KM_ERROR_OK;
+ } else {
+ return KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
+ }
+ } else {
+ LOG(ERROR) << "secure element reader " << ESE_READER_PREFIX << " not found";
+ return KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
+ }
+}
+
+keymaster_error_t OmapiTransport::closeConnection() {
+ LOG(DEBUG) << "Closing all connections";
+ if (omapiSeService != nullptr) {
+ if (mVSReaders.size() > 0) {
+ for (const auto& [name, reader] : mVSReaders) {
+ reader->closeSessions();
+ }
+ mVSReaders.clear();
+ }
+ }
+ if (channel != nullptr) channel->close();
+ if (session != nullptr) session->close();
+ return KM_ERROR_OK;
+}
+
+bool OmapiTransport::isConnected() {
+ // Check already initialization completed or not
+ if (omapiSeService != nullptr && eSEReader != nullptr) {
+ LOG(DEBUG) << "Connection initialization already completed";
+ return true;
+ }
+
+ LOG(DEBUG) << "Connection initialization not completed";
+ return false;
+}
+
+} // namespace keymint::javacard
diff --git a/ready_se/google/keymint/KM200/HAL/OmapiTransport.h b/ready_se/google/keymint/KM200/HAL/OmapiTransport.h
new file mode 100644
index 0000000..a199bbb
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/OmapiTransport.h
@@ -0,0 +1,65 @@
+#pragma once
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include <aidl/android/se/omapi/BnSecureElementListener.h>
+#include <aidl/android/se/omapi/ISecureElementChannel.h>
+#include <aidl/android/se/omapi/ISecureElementListener.h>
+#include <aidl/android/se/omapi/ISecureElementReader.h>
+#include <aidl/android/se/omapi/ISecureElementService.h>
+#include <aidl/android/se/omapi/ISecureElementSession.h>
+
+#include <android/binder_manager.h>
+
+#include "ITransport.h"
+
+namespace keymint::javacard {
+using std::vector;
+
+/**
+ * OmapiTransport is derived from ITransport. This class gets the OMAPI service binder instance and
+ * uses IPC to communicate with OMAPI service. OMAPI inturn communicates with hardware via
+ * ISecureElement.
+ */
+class OmapiTransport : public ITransport {
+
+ public:
+ OmapiTransport()
+ : omapiSeService(nullptr), eSEReader(nullptr), session(nullptr), channel(nullptr),
+ mVSReaders({}) {}
+ /**
+ * Gets the binder instance of ISEService, gets te reader corresponding to secure element,
+ * establishes a session and opens a basic channel.
+ */
+ keymaster_error_t openConnection() override;
+ /**
+ * Transmists the data over the opened basic channel and receives the data back.
+ */
+ keymaster_error_t sendData(const vector<uint8_t>& inData, vector<uint8_t>& output) override;
+
+ /**
+ * Closes the connection.
+ */
+ keymaster_error_t closeConnection() override;
+ /**
+ * Returns the state of the connection status. Returns true if the connection is active, false
+ * if connection is broken.
+ */
+ bool isConnected() override;
+
+ private:
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementService> omapiSeService;
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementReader> eSEReader;
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementSession> session;
+ std::shared_ptr<aidl::android::se::omapi::ISecureElementChannel> channel;
+ std::map<std::string, std::shared_ptr<aidl::android::se::omapi::ISecureElementReader>>
+ mVSReaders;
+ keymaster_error_t initialize();
+ bool
+ internalTransmitApdu(std::shared_ptr<aidl::android::se::omapi::ISecureElementReader> reader,
+ std::vector<uint8_t> apdu, std::vector<uint8_t>& transmitResponse);
+};
+
+} // namespace keymint::javacard
diff --git a/ready_se/google/keymint/KM200/HAL/SocketTransport.cpp b/ready_se/google/keymint/KM200/HAL/SocketTransport.cpp
new file mode 100644
index 0000000..a3595fe
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/SocketTransport.cpp
@@ -0,0 +1,144 @@
+/*
+ **
+ ** 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 "SocketTransport.h"
+
+#include <arpa/inet.h>
+#include <errno.h>
+
+#include <memory>
+#include <vector>
+
+#include <aidl/android/hardware/security/keymint/ErrorCode.h>
+#include <android-base/logging.h>
+#include <sys/socket.h>
+
+#include "ITransport.h"
+
+#define PORT 8080
+#define IPADDR "192.168.9.112"
+#define MAX_RECV_BUFFER_SIZE 2500
+
+namespace keymint::javacard {
+using ::aidl::android::hardware::security::keymint::ErrorCode;
+using std::shared_ptr;
+using std::vector;
+
+keymaster_error_t SocketTransport::openConnection() {
+ struct sockaddr_in serv_addr;
+ if ((mSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ LOG(ERROR) << "Socket creation failed"
+ << " Error: " << strerror(errno);
+ return static_cast<keymaster_error_t>(ErrorCode::HARDWARE_TYPE_UNAVAILABLE);
+ }
+
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_port = htons(PORT);
+
+ // Convert IPv4 and IPv6 addresses from text to binary form
+ if (inet_pton(AF_INET, IPADDR, &serv_addr.sin_addr) <= 0) {
+ LOG(ERROR) << "Invalid address/ Address not supported.";
+ return static_cast<keymaster_error_t>(ErrorCode::HARDWARE_TYPE_UNAVAILABLE);
+ }
+
+ if (connect(mSocket, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
+ close(mSocket);
+ LOG(ERROR) << "Connection failed. Error: " << strerror(errno);
+ return KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
+ }
+ socketStatus = true;
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t SocketTransport::sendData(const vector<uint8_t>& inData,
+ vector<uint8_t>& output) {
+ int count = 1;
+ while (!socketStatus && count++ < 5) {
+ sleep(1);
+ LOG(ERROR) << "Trying to open socket connection... count: " << count;
+ openConnection();
+ }
+
+ if (count >= 5) {
+ LOG(ERROR) << "Failed to open socket connection";
+ return KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
+ }
+ // Prepend the input length to the inputData before sending.
+ vector<uint8_t> inDataPrependedLength;
+ inDataPrependedLength.push_back(static_cast<uint8_t>(inData.size() >> 8));
+ inDataPrependedLength.push_back(static_cast<uint8_t>(inData.size() & 0xFF));
+ inDataPrependedLength.insert(inDataPrependedLength.end(), inData.begin(), inData.end());
+
+ if (0 >
+ send(mSocket, inDataPrependedLength.data(), inDataPrependedLength.size(), MSG_NOSIGNAL)) {
+ static int connectionResetCnt = 0; /* To avoid loop */
+ if ((ECONNRESET == errno || EPIPE == errno) && connectionResetCnt == 0) {
+ // Connection reset. Try open socket and then sendData.
+ socketStatus = false;
+ connectionResetCnt++;
+ return sendData(inData, output);
+ }
+ LOG(ERROR) << "Failed to send data over socket err: " << errno;
+ connectionResetCnt = 0;
+ return KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
+ }
+
+ if (!readData(output)) {
+ return KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
+ }
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t SocketTransport::closeConnection() {
+ close(mSocket);
+ socketStatus = false;
+ return KM_ERROR_OK;
+}
+
+bool SocketTransport::isConnected() {
+ return socketStatus;
+}
+
+bool SocketTransport::readData(vector<uint8_t>& output) {
+ uint8_t buffer[MAX_RECV_BUFFER_SIZE];
+ ssize_t expectedResponseLen = 0;
+ ssize_t totalBytesRead = 0;
+ // The first 2 bytes in the response contains the expected response length.
+ do {
+ size_t i = 0;
+ ssize_t numBytes = read(mSocket, buffer, MAX_RECV_BUFFER_SIZE);
+ if (0 > numBytes) {
+ LOG(ERROR) << "Failed to read data from socket.";
+ return false;
+ }
+ totalBytesRead += numBytes;
+ if (expectedResponseLen == 0) {
+ // First two bytes in the response contains the expected response length.
+ expectedResponseLen |= static_cast<ssize_t>(buffer[1] & 0xFF);
+ expectedResponseLen |= static_cast<ssize_t>((buffer[0] << 8) & 0xFF00);
+ // 2 bytes for storing the length.
+ expectedResponseLen += 2;
+ i = 2;
+ }
+ for (; i < numBytes; i++) {
+ output.push_back(buffer[i]);
+ }
+ } while (totalBytesRead < expectedResponseLen);
+
+ return true;
+}
+
+} // namespace keymint::javacard
diff --git a/ready_se/google/keymint/KM200/HAL/SocketTransport.h b/ready_se/google/keymint/KM200/HAL/SocketTransport.h
new file mode 100644
index 0000000..73725d0
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/SocketTransport.h
@@ -0,0 +1,55 @@
+/*
+ **
+ ** 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 <memory>
+#include <vector>
+
+#include "ITransport.h"
+
+namespace keymint::javacard {
+using std::shared_ptr;
+using std::vector;
+
+class SocketTransport : public ITransport {
+
+ public:
+ SocketTransport() : mSocket(-1), socketStatus(false) {}
+ /**
+ * Creates a socket instance and connects to the provided server IP and port.
+ */
+ keymaster_error_t openConnection() override;
+ /**
+ * Sends data over socket and receives data back.
+ */
+ keymaster_error_t sendData(const vector<uint8_t>& inData, vector<uint8_t>& output) override;
+ /**
+ * Closes the connection.
+ */
+ keymaster_error_t closeConnection() override;
+ /**
+ * Returns the state of the connection status. Returns true if the connection is active,
+ * false if connection is broken.
+ */
+ bool isConnected() override;
+
+ private:
+ bool readData(vector<uint8_t>& output);
+ int mSocket;
+ bool socketStatus;
+};
+} // namespace keymint::javacard
diff --git a/ready_se/google/keymint/KM200/HAL/android.hardware.hardware_keystore.jc-strongbox-keymint.xml b/ready_se/google/keymint/KM200/HAL/android.hardware.hardware_keystore.jc-strongbox-keymint.xml
new file mode 100644
index 0000000..c6ca188
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/android.hardware.hardware_keystore.jc-strongbox-keymint.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<!-- Feature for devices with Keymaster in StrongBox. -->
+<permissions>
+ <feature name="android.hardware.strongbox_keystore" version="200"/>
+ <feature name="android.hardware.keystore.app_attest_key" />
+</permissions>
diff --git a/ready_se/google/keymint/KM200/HAL/android.hardware.security.keymint-service.strongbox.rc b/ready_se/google/keymint/KM200/HAL/android.hardware.security.keymint-service.strongbox.rc
new file mode 100644
index 0000000..7bb96f0
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/android.hardware.security.keymint-service.strongbox.rc
@@ -0,0 +1,3 @@
+service vendor.keymint-strongbox /vendor/bin/hw/android.hardware.security.keymint-service.strongbox
+ class early_hal
+ user jc_strongbox
diff --git a/ready_se/google/keymint/KM200/HAL/android.hardware.security.keymint-service.strongbox.xml b/ready_se/google/keymint/KM200/HAL/android.hardware.security.keymint-service.strongbox.xml
new file mode 100644
index 0000000..0631f12
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/android.hardware.security.keymint-service.strongbox.xml
@@ -0,0 +1,10 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.security.keymint</name>
+ <fqname>IKeyMintDevice/strongbox</fqname>
+ </hal>
+ <hal format="aidl">
+ <name>android.hardware.security.keymint</name>
+ <fqname>IRemotelyProvisionedComponent/strongbox</fqname>
+ </hal>
+</manifest>
diff --git a/ready_se/google/keymint/KM200/HAL/android.hardware.security.sharedsecret-service.strongbox.xml b/ready_se/google/keymint/KM200/HAL/android.hardware.security.sharedsecret-service.strongbox.xml
new file mode 100644
index 0000000..5492100
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/android.hardware.security.sharedsecret-service.strongbox.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.security.sharedsecret</name>
+ <fqname>ISharedSecret/strongbox</fqname>
+ </hal>
+</manifest>
diff --git a/ready_se/google/keymint/KM200/HAL/keymint_utils.cpp b/ready_se/google/keymint/KM200/HAL/keymint_utils.cpp
new file mode 100644
index 0000000..f613eda
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/keymint_utils.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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 "keymint_utils.h"
+
+#include <regex.h>
+
+#include <android-base/properties.h>
+
+namespace keymint::javacard {
+
+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 kVendorPatchlevelProp[] = "ro.vendor.build.security_patch";
+constexpr char kPatchlevelRegex[] = "^([0-9]{4})-([0-9]{2})-([0-9]{2})$";
+constexpr size_t kYearMatch = 1;
+constexpr size_t kMonthMatch = 2;
+constexpr size_t kDayMatch = 3;
+constexpr size_t kPatchlevelMatchCount = kDayMatch + 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;
+}
+
+uint32_t getOsVersion(const char* version_str) {
+ regex_t regex;
+ if (regcomp(&regex, kPlatformVersionRegex, REG_EXTENDED)) {
+ return 0;
+ }
+
+ regmatch_t matches[kPlatformVersionMatchCount];
+ int not_match =
+ regexec(&regex, version_str, kPlatformVersionMatchCount, matches, 0 /* flags */);
+ regfree(&regex);
+ 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;
+}
+
+enum class PatchlevelOutput { kYearMonthDay, kYearMonth };
+
+uint32_t getPatchlevel(const char* patchlevel_str, PatchlevelOutput detail) {
+ regex_t regex;
+ if (regcomp(&regex, kPatchlevelRegex, REG_EXTENDED) != 0) {
+ return 0;
+ }
+
+ regmatch_t matches[kPatchlevelMatchCount];
+ int not_match = regexec(&regex, patchlevel_str, kPatchlevelMatchCount, matches, 0 /* flags */);
+ regfree(&regex);
+ 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;
+ }
+
+ switch (detail) {
+ case PatchlevelOutput::kYearMonthDay: {
+ uint32_t day = match_to_uint32(patchlevel_str, matches[kDayMatch]);
+ if (day < 1 || day > 31) {
+ return 0;
+ }
+ return year * 10000 + month * 100 + day;
+ }
+ case PatchlevelOutput::kYearMonth:
+ return year * 100 + month;
+ }
+}
+
+} // anonymous namespace
+
+uint32_t getOsVersion() {
+ std::string version = wait_and_get_property(kPlatformVersionProp);
+ return getOsVersion(version.c_str());
+}
+
+uint32_t getOsPatchlevel() {
+ std::string patchlevel = wait_and_get_property(kPlatformPatchlevelProp);
+ return getPatchlevel(patchlevel.c_str(), PatchlevelOutput::kYearMonth);
+}
+
+uint32_t getVendorPatchlevel() {
+ std::string patchlevel = wait_and_get_property(kVendorPatchlevelProp);
+ return getPatchlevel(patchlevel.c_str(), PatchlevelOutput::kYearMonthDay);
+}
+
+} // namespace keymint::javacard
diff --git a/ready_se/google/keymint/KM200/HAL/keymint_utils.h b/ready_se/google/keymint/KM200/HAL/keymint_utils.h
new file mode 100644
index 0000000..65cda63
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/keymint_utils.h
@@ -0,0 +1,47 @@
+/*
+ * 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 <string>
+#include <vector>
+
+// #include <aidl/android/hardware/security/keymint/HardwareAuthToken.h>
+
+// namespace aidl::android::hardware::security::keymint {
+namespace keymint::javacard {
+
+using std::vector;
+
+inline static std::vector<uint8_t> blob2vector(const uint8_t* data, const size_t length) {
+ std::vector<uint8_t> result(data, data + length);
+ return result;
+}
+
+inline static std::vector<uint8_t> blob2vector(const std::string& value) {
+ vector<uint8_t> result(reinterpret_cast<const uint8_t*>(value.data()),
+ reinterpret_cast<const uint8_t*>(value.data()) + value.size());
+ return result;
+}
+
+// HardwareAuthToken vector2AuthToken(const vector<uint8_t>& buffer);
+// vector<uint8_t> authToken2vector(const HardwareAuthToken& token);
+
+uint32_t getOsVersion();
+uint32_t getOsPatchlevel();
+uint32_t getVendorPatchlevel();
+
+} // namespace keymint::javacard
diff --git a/ready_se/google/keymint/KM200/HAL/service.cpp b/ready_se/google/keymint/KM200/HAL/service.cpp
new file mode 100644
index 0000000..e83ee3d
--- /dev/null
+++ b/ready_se/google/keymint/KM200/HAL/service.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "javacard.strongbox-service"
+
+#include <aidl/android/hardware/security/keymint/SecurityLevel.h>
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include "JavacardKeyMintDevice.h"
+#include "JavacardRemotelyProvisionedComponentDevice.h"
+#include "JavacardSecureElement.h"
+#include "JavacardSharedSecret.h"
+#include "OmapiTransport.h"
+#include "SocketTransport.h"
+#include "keymint_utils.h"
+
+using aidl::android::hardware::security::keymint::JavacardKeyMintDevice;
+using aidl::android::hardware::security::keymint::JavacardRemotelyProvisionedComponentDevice;
+using aidl::android::hardware::security::keymint::SecurityLevel;
+using aidl::android::hardware::security::sharedsecret::JavacardSharedSecret;
+using keymint::javacard::getOsPatchlevel;
+using keymint::javacard::getOsVersion;
+using keymint::javacard::getVendorPatchlevel;
+using keymint::javacard::ITransport;
+using keymint::javacard::JavacardSecureElement;
+using keymint::javacard::OmapiTransport;
+using keymint::javacard::SocketTransport;
+
+#define PROP_BUILD_QEMU "ro.kernel.qemu"
+#define PROP_BUILD_FINGERPRINT "ro.build.fingerprint"
+// Cuttlefish build fingerprint substring.
+#define CUTTLEFISH_FINGERPRINT_SS "aosp_cf_"
+
+template <typename T, class... Args> std::shared_ptr<T> addService(Args&&... args) {
+ std::shared_ptr<T> ser = ndk::SharedRefBase::make<T>(std::forward<Args>(args)...);
+ auto instanceName = std::string(T::descriptor) + "/strongbox";
+ LOG(INFO) << "adding javacard strongbox service instance: " << instanceName;
+ binder_status_t status =
+ AServiceManager_addService(ser->asBinder().get(), instanceName.c_str());
+ CHECK(status == STATUS_OK);
+ return ser;
+}
+
+std::shared_ptr<ITransport> getTransportInstance() {
+ bool isEmulator = false;
+ // Check if the current build is for emulator or device.
+ isEmulator = android::base::GetBoolProperty(PROP_BUILD_QEMU, false);
+ if (!isEmulator) {
+ std::string fingerprint = android::base::GetProperty(PROP_BUILD_FINGERPRINT, "");
+ if (!fingerprint.empty()) {
+ if (fingerprint.find(CUTTLEFISH_FINGERPRINT_SS, 0) != std::string::npos) {
+ isEmulator = true;
+ }
+ }
+ }
+
+ if (!isEmulator) {
+ return std::make_shared<OmapiTransport>();
+ } else {
+ return std::make_shared<SocketTransport>();
+ }
+}
+
+int main() {
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+ // Javacard Secure Element
+ std::shared_ptr<JavacardSecureElement> card = std::make_shared<JavacardSecureElement>(
+ getTransportInstance(), getOsVersion(), getOsPatchlevel(), getVendorPatchlevel());
+ // Add Keymint Service
+ addService<JavacardKeyMintDevice>(card);
+ // Add Shared Secret Service
+ addService<JavacardSharedSecret>(card);
+ // Add Remotely Provisioned Component Service
+ addService<JavacardRemotelyProvisionedComponentDevice>(card);
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reach
+}