Merge "Use -Werror in hardware/interfaces/automotive/vehicle/2.0"
diff --git a/Android.bp b/Android.bp
index 978559a..5cb85b4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,7 +1,3 @@
-subdirs = [
- "*"
-]
-
hidl_package_root {
name: "android.hardware",
path: "hardware/interfaces",
diff --git a/audio/2.0/default/StreamIn.cpp b/audio/2.0/default/StreamIn.cpp
index c074f3c..61d5d8e 100644
--- a/audio/2.0/default/StreamIn.cpp
+++ b/audio/2.0/default/StreamIn.cpp
@@ -415,7 +415,7 @@
// spam the log in this case.
static const std::vector<int> ignoredErrors{ENOSYS};
Result retval(Result::NOT_SUPPORTED);
- if (stream->get_capture_position != NULL) return retval;
+ if (stream->get_capture_position == NULL) return retval;
int64_t halFrames, halTime;
retval = Stream::analyzeStatus("get_capture_position",
stream->get_capture_position(stream, &halFrames, &halTime),
diff --git a/audio/Android.bp b/audio/Android.bp
deleted file mode 100644
index f4a5846..0000000
--- a/audio/Android.bp
+++ /dev/null
@@ -1,11 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "2.0",
- "2.0/vts/functional",
- "common/2.0",
- "common/2.0/default",
- "common/test/utility",
- "effect/2.0",
- "effect/2.0/default",
- "effect/2.0/vts/functional",
-]
diff --git a/automotive/Android.bp b/automotive/Android.bp
deleted file mode 100644
index 8cde817..0000000
--- a/automotive/Android.bp
+++ /dev/null
@@ -1,9 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "evs/1.0",
- "evs/1.0/default",
- "evs/1.0/vts/functional",
- "vehicle/2.0",
- "vehicle/2.0/default",
- "vehicle/2.0/default/impl/vhal_v2_0/proto",
-]
diff --git a/biometrics/Android.bp b/biometrics/Android.bp
deleted file mode 100644
index 19a1062..0000000
--- a/biometrics/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "fingerprint/2.1",
- "fingerprint/2.1/default",
- "fingerprint/2.1/vts/functional",
-]
diff --git a/biometrics/fingerprint/2.1/default/Android.bp b/biometrics/fingerprint/2.1/default/Android.bp
index e1d2cf7..b12ce61 100644
--- a/biometrics/fingerprint/2.1/default/Android.bp
+++ b/biometrics/fingerprint/2.1/default/Android.bp
@@ -1,5 +1,6 @@
cc_binary {
name: "android.hardware.biometrics.fingerprint@2.1-service",
+ defaults: ["hidl_defaults"],
init_rc: ["android.hardware.biometrics.fingerprint@2.1-service.rc"],
vendor: true,
relative_install_path: "hw",
diff --git a/biometrics/fingerprint/2.1/default/service.cpp b/biometrics/fingerprint/2.1/default/service.cpp
index 1697c07..edfaac4 100644
--- a/biometrics/fingerprint/2.1/default/service.cpp
+++ b/biometrics/fingerprint/2.1/default/service.cpp
@@ -35,7 +35,9 @@
configureRpcThreadpool(1, true /*callerWillJoin*/);
if (bio != nullptr) {
- bio->registerAsService();
+ if (::android::OK != bio->registerAsService()) {
+ return 1;
+ }
} else {
ALOGE("Can't create instance of BiometricsFingerprint, nullptr");
}
diff --git a/bluetooth/Android.bp b/bluetooth/Android.bp
deleted file mode 100644
index ed19a37..0000000
--- a/bluetooth/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "1.0/default",
- "1.0/vts/functional",
-]
diff --git a/boot/Android.bp b/boot/Android.bp
deleted file mode 100644
index ed19a37..0000000
--- a/boot/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "1.0/default",
- "1.0/vts/functional",
-]
diff --git a/broadcastradio/1.1/vts/functional/Android.bp b/broadcastradio/1.1/vts/functional/Android.bp
index 3d4fe05..c016c16 100644
--- a/broadcastradio/1.1/vts/functional/Android.bp
+++ b/broadcastradio/1.1/vts/functional/Android.bp
@@ -21,6 +21,7 @@
static_libs: [
"android.hardware.broadcastradio@1.0",
"android.hardware.broadcastradio@1.1",
+ "android.hardware.broadcastradio@1.2", // common-utils-lib dependency
"android.hardware.broadcastradio@common-utils-lib",
"android.hardware.broadcastradio@vts-utils-lib",
"libgmock",
diff --git a/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp b/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
index a46378e..bb490c9 100644
--- a/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
+++ b/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
@@ -525,6 +525,98 @@
ASSERT_FALSE(forced);
}
+static void verifyIdentifier(const ProgramIdentifier& id) {
+ EXPECT_NE(id.type, 0u);
+ auto val = id.value;
+
+ switch (static_cast<IdentifierType>(id.type)) {
+ case IdentifierType::AMFM_FREQUENCY:
+ case IdentifierType::DAB_FREQUENCY:
+ case IdentifierType::DRMO_FREQUENCY:
+ EXPECT_GT(val, 100u) << "Expected f > 100kHz";
+ EXPECT_LT(val, 10000000u) << "Expected f < 10GHz";
+ break;
+ case IdentifierType::RDS_PI:
+ EXPECT_GT(val, 0u);
+ EXPECT_LE(val, 0xFFFFu) << "Expected 16bit id";
+ break;
+ case IdentifierType::HD_STATION_ID_EXT: {
+ auto stationId = val & 0xFFFFFFFF; // 32bit
+ val >>= 32;
+ auto subchannel = val & 0xF; // 4bit
+ val >>= 4;
+ auto freq = val & 0x3FFFF; // 18bit
+ EXPECT_GT(stationId, 0u);
+ EXPECT_LT(subchannel, 8u) << "Expected ch < 8";
+ EXPECT_GT(freq, 100u) << "Expected f > 100kHz";
+ EXPECT_LT(freq, 10000000u) << "Expected f < 10GHz";
+ break;
+ }
+ case IdentifierType::HD_SUBCHANNEL:
+ EXPECT_LT(val, 8u) << "Expected ch < 8";
+ break;
+ case IdentifierType::DAB_SIDECC: {
+ auto sid = val & 0xFFFF; // 16bit
+ val >>= 16;
+ auto ecc = val & 0xFF; // 8bit
+ EXPECT_NE(sid, 0u);
+ EXPECT_GE(ecc, 0xA0u) << "Invalid ECC, see ETSI TS 101 756 V2.1.1";
+ EXPECT_LE(ecc, 0xF6u) << "Invalid ECC, see ETSI TS 101 756 V2.1.1";
+ break;
+ }
+ case IdentifierType::DAB_ENSEMBLE:
+ EXPECT_GT(val, 0u);
+ EXPECT_LE(val, 0xFFFFu) << "Expected 16bit id";
+ break;
+ case IdentifierType::DAB_SCID:
+ EXPECT_GT(val, 0xFu) << "Expected 12bit SCId (not 4bit SCIdS)";
+ EXPECT_LE(val, 0xFFFu) << "Expected 12bit id";
+ break;
+ case IdentifierType::DRMO_SERVICE_ID:
+ EXPECT_GT(val, 0u);
+ EXPECT_LE(val, 0xFFFFFFu) << "Expected 24bit id";
+ break;
+ case IdentifierType::DRMO_MODULATION:
+ EXPECT_GE(val, static_cast<uint32_t>(Modulation::AM));
+ EXPECT_LE(val, static_cast<uint32_t>(Modulation::FM));
+ break;
+ case IdentifierType::SXM_SERVICE_ID:
+ EXPECT_GT(val, 0u);
+ EXPECT_LE(val, 0xFFFFFFFFu) << "Expected 32bit id";
+ break;
+ case IdentifierType::SXM_CHANNEL:
+ EXPECT_LT(val, 1000u);
+ break;
+ case IdentifierType::VENDOR_PRIMARY_START:
+ case IdentifierType::VENDOR_PRIMARY_END:
+ // skip
+ break;
+ }
+}
+
+/**
+ * Test ProgramIdentifier format.
+ *
+ * Verifies that:
+ * - values of ProgramIdentifier match their definitions at IdentifierType.
+ */
+TEST_P(BroadcastRadioHalTest, VerifyIdentifiersFormat) {
+ if (skipped) return;
+ ASSERT_TRUE(openTuner());
+
+ do {
+ auto getCb = [&](const hidl_vec<ProgramInfo>& list) {
+ for (auto&& program : list) {
+ verifyIdentifier(program.selector.primaryId);
+ for (auto&& id : program.selector.secondaryIds) {
+ verifyIdentifier(id);
+ }
+ }
+ };
+ getProgramList(getCb);
+ } while (nextBand());
+}
+
INSTANTIATE_TEST_CASE_P(BroadcastRadioHalTestCases, BroadcastRadioHalTest,
::testing::Values(Class::AM_FM, Class::SAT, Class::DT));
diff --git a/broadcastradio/1.2/default/Tuner.cpp b/broadcastradio/1.2/default/Tuner.cpp
index 70418cf..6209dc1 100644
--- a/broadcastradio/1.2/default/Tuner.cpp
+++ b/broadcastradio/1.2/default/Tuner.cpp
@@ -35,13 +35,13 @@
using V1_0::BandConfig;
using V1_0::Class;
using V1_0::Direction;
-using V1_1::IdentifierType;
using V1_1::ProgramInfo;
using V1_1::ProgramInfoFlags;
using V1_1::ProgramListResult;
using V1_1::ProgramSelector;
using V1_1::ProgramType;
using V1_1::VendorKeyValue;
+using V1_2::IdentifierType;
using utils::HalRevision;
using std::chrono::milliseconds;
@@ -282,7 +282,7 @@
return Result::INVALID_ARGUMENTS;
}
} else if (programType == ProgramType::DAB) {
- if (!utils::hasId(sel, IdentifierType::DAB_SIDECC)) return Result::INVALID_ARGUMENTS;
+ if (!utils::hasId(sel, IdentifierType::DAB_SID_EXT)) return Result::INVALID_ARGUMENTS;
} else if (programType == ProgramType::DRMO) {
if (!utils::hasId(sel, IdentifierType::DRMO_SERVICE_ID)) return Result::INVALID_ARGUMENTS;
} else if (programType == ProgramType::SXM) {
diff --git a/broadcastradio/1.2/default/VirtualProgram.cpp b/broadcastradio/1.2/default/VirtualProgram.cpp
index 95879e3..3284bd1 100644
--- a/broadcastradio/1.2/default/VirtualProgram.cpp
+++ b/broadcastradio/1.2/default/VirtualProgram.cpp
@@ -30,9 +30,9 @@
using V1_0::MetaData;
using V1_0::MetadataKey;
using V1_0::MetadataType;
-using V1_1::IdentifierType;
using V1_1::ProgramInfo;
using V1_1::VendorKeyValue;
+using V1_2::IdentifierType;
using utils::HalRevision;
static MetaData createDemoBitmap(MetadataKey key, HalRevision halRev) {
diff --git a/broadcastradio/1.2/types.hal b/broadcastradio/1.2/types.hal
index 5edb097..7301e13 100644
--- a/broadcastradio/1.2/types.hal
+++ b/broadcastradio/1.2/types.hal
@@ -16,8 +16,35 @@
package android.hardware.broadcastradio@1.2;
+import @1.1::IdentifierType;
import @1.1::Result;
import @1.1::VendorKeyValue;
typedef @1.1::Result Result;
typedef @1.1::VendorKeyValue VendorKeyValue;
+
+enum IdentifierType : @1.1::IdentifierType {
+ /**
+ * 28bit compound primary identifier for DAB.
+ *
+ * Consists of (from the LSB):
+ * - 16bit: SId;
+ * - 8bit: ECC code;
+ * - 4bit: SCIdS (optional).
+ *
+ * SCIdS (Service Component Identifier within the Service) value
+ * of 0 represents the main service, while 1 and above represents
+ * secondary services.
+ *
+ * The remaining bits should be set to zeros when writing on the chip side
+ * and ignored when read.
+ *
+ * This identifier deprecates DAB_SIDECC and makes new primary identifier
+ * for DAB. If the hal implementation detects 1.2 client (by casting
+ * V1_0::ITunerCallback to V1_2::ITunerCallback), it must use DAB_SID_EXT
+ * as a primary identifier for DAB program type. If the hal client detects
+ * either 1.1 or 1.2 HAL, it must convert those identifiers to the
+ * correct version.
+ */
+ DAB_SID_EXT = SXM_CHANNEL + 1,
+};
diff --git a/broadcastradio/1.2/vts/functional/VtsHalBroadcastradioV1_2TargetTest.cpp b/broadcastradio/1.2/vts/functional/VtsHalBroadcastradioV1_2TargetTest.cpp
index f075945..f3552a8 100644
--- a/broadcastradio/1.2/vts/functional/VtsHalBroadcastradioV1_2TargetTest.cpp
+++ b/broadcastradio/1.2/vts/functional/VtsHalBroadcastradioV1_2TargetTest.cpp
@@ -295,6 +295,9 @@
ASSERT_EQ(0u, halResults.size());
}
+// TODO(b/69860743): implement VerifyIdentifiersFormat test when
+// the new program list fetching mechanism is implemented
+
INSTANTIATE_TEST_CASE_P(BroadcastRadioHalTestCases, BroadcastRadioHalTest,
::testing::Values(Class::AM_FM, Class::SAT, Class::DT));
diff --git a/broadcastradio/Android.bp b/broadcastradio/Android.bp
deleted file mode 100644
index 68cc99f..0000000
--- a/broadcastradio/Android.bp
+++ /dev/null
@@ -1,14 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "1.0/default",
- "1.0/vts/functional",
- "1.1",
- "1.1/vts/functional",
- "1.2",
- "1.2/default",
- "1.2/vts/functional",
- "common/tests",
- "common/utils",
- "common/vts/utils",
-]
diff --git a/broadcastradio/common/utils/Android.bp b/broadcastradio/common/utils/Android.bp
index d8bd125..d29d05c 100644
--- a/broadcastradio/common/utils/Android.bp
+++ b/broadcastradio/common/utils/Android.bp
@@ -29,6 +29,6 @@
],
export_include_dirs: ["include"],
shared_libs: [
- "android.hardware.broadcastradio@1.1",
+ "android.hardware.broadcastradio@1.2",
],
}
diff --git a/broadcastradio/common/utils/Utils.cpp b/broadcastradio/common/utils/Utils.cpp
index bdaf8e8..22a6970 100644
--- a/broadcastradio/common/utils/Utils.cpp
+++ b/broadcastradio/common/utils/Utils.cpp
@@ -26,10 +26,10 @@
namespace utils {
using V1_0::Band;
-using V1_1::IdentifierType;
using V1_1::ProgramIdentifier;
using V1_1::ProgramSelector;
using V1_1::ProgramType;
+using V1_2::IdentifierType;
static bool isCompatibleProgramType(const uint32_t ia, const uint32_t ib) {
auto a = static_cast<ProgramType>(ia);
@@ -88,7 +88,7 @@
return haveEqualIds(a, b, IdentifierType::AMFM_FREQUENCY);
case ProgramType::DAB:
- return haveEqualIds(a, b, IdentifierType::DAB_SIDECC);
+ return haveEqualIds(a, b, IdentifierType::DAB_SID_EXT);
case ProgramType::DRMO:
return haveEqualIds(a, b, IdentifierType::DRMO_SERVICE_ID);
case ProgramType::SXM:
@@ -126,23 +126,50 @@
return band == Band::FM || band == Band::FM_HD;
}
-bool hasId(const ProgramSelector& sel, const IdentifierType type) {
+static bool maybeGetId(const ProgramSelector& sel, const IdentifierType type, uint64_t* val) {
auto itype = static_cast<uint32_t>(type);
- if (sel.primaryId.type == itype) return true;
- // not optimal, but we don't care in default impl
- for (auto&& id : sel.secondaryIds) {
- if (id.type == itype) return true;
+ auto itypeAlt = itype;
+ if (type == IdentifierType::DAB_SIDECC) {
+ itypeAlt = static_cast<uint32_t>(IdentifierType::DAB_SID_EXT);
}
- return false;
+ if (type == IdentifierType::DAB_SID_EXT) {
+ itypeAlt = static_cast<uint32_t>(IdentifierType::DAB_SIDECC);
+ }
+
+ if (sel.primaryId.type == itype || sel.primaryId.type == itypeAlt) {
+ if (val) *val = sel.primaryId.value;
+ return true;
+ }
+
+ // not optimal, but we don't care in default impl
+ bool gotAlt = false;
+ for (auto&& id : sel.secondaryIds) {
+ if (id.type == itype) {
+ if (val) *val = id.value;
+ return true;
+ }
+ // alternative identifier is a backup, we prefer original value
+ if (id.type == itypeAlt) {
+ if (val) *val = id.value;
+ gotAlt = true;
+ continue;
+ }
+ }
+
+ return gotAlt;
+}
+
+bool hasId(const ProgramSelector& sel, const IdentifierType type) {
+ return maybeGetId(sel, type, nullptr);
}
uint64_t getId(const ProgramSelector& sel, const IdentifierType type) {
- auto itype = static_cast<uint32_t>(type);
- if (sel.primaryId.type == itype) return sel.primaryId.value;
- // not optimal, but we don't care in default impl
- for (auto&& id : sel.secondaryIds) {
- if (id.type == itype) return id.value;
+ uint64_t val;
+
+ if (maybeGetId(sel, type, &val)) {
+ return val;
}
+
ALOGW("Identifier %s not found", toString(type).c_str());
return 0;
}
diff --git a/broadcastradio/common/utils/include/broadcastradio-utils/Utils.h b/broadcastradio/common/utils/include/broadcastradio-utils/Utils.h
index b07ce79..9cdc629 100644
--- a/broadcastradio/common/utils/include/broadcastradio-utils/Utils.h
+++ b/broadcastradio/common/utils/include/broadcastradio-utils/Utils.h
@@ -16,7 +16,7 @@
#ifndef ANDROID_HARDWARE_BROADCASTRADIO_COMMON_UTILS_H
#define ANDROID_HARDWARE_BROADCASTRADIO_COMMON_UTILS_H
-#include <android/hardware/broadcastradio/1.1/types.h>
+#include <android/hardware/broadcastradio/1.2/types.h>
#include <chrono>
#include <queue>
#include <thread>
@@ -50,21 +50,21 @@
bool isAm(const V1_0::Band band);
bool isFm(const V1_0::Band band);
-bool hasId(const V1_1::ProgramSelector& sel, const V1_1::IdentifierType type);
+bool hasId(const V1_1::ProgramSelector& sel, const V1_2::IdentifierType type);
/**
* Returns ID (either primary or secondary) for a given program selector.
*
* If the selector does not contain given type, returns 0 and emits a warning.
*/
-uint64_t getId(const V1_1::ProgramSelector& sel, const V1_1::IdentifierType type);
+uint64_t getId(const V1_1::ProgramSelector& sel, const V1_2::IdentifierType type);
/**
* Returns ID (either primary or secondary) for a given program selector.
*
* If the selector does not contain given type, returns default value.
*/
-uint64_t getId(const V1_1::ProgramSelector& sel, const V1_1::IdentifierType type, uint64_t defval);
+uint64_t getId(const V1_1::ProgramSelector& sel, const V1_2::IdentifierType type, uint64_t defval);
V1_1::ProgramSelector make_selector(V1_0::Band band, uint32_t channel, uint32_t subChannel = 0);
diff --git a/camera/Android.bp b/camera/Android.bp
deleted file mode 100644
index 0240751..0000000
--- a/camera/Android.bp
+++ /dev/null
@@ -1,15 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "common/1.0",
- "common/1.0/default",
- "device/1.0",
- "device/1.0/default",
- "device/3.2",
- "device/3.2/default",
- "device/3.3",
- "device/3.3/default",
- "metadata/3.2",
- "provider/2.4",
- "provider/2.4/default",
- "provider/2.4/vts/functional",
-]
diff --git a/cas/Android.bp b/cas/Android.bp
deleted file mode 100644
index 36bd607..0000000
--- a/cas/Android.bp
+++ /dev/null
@@ -1,7 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "1.0/default",
- "1.0/vts/functional",
- "native/1.0",
-]
diff --git a/configstore/Android.bp b/configstore/Android.bp
deleted file mode 100644
index 4a783c3..0000000
--- a/configstore/Android.bp
+++ /dev/null
@@ -1,8 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "1.0/vts/functional",
- "1.1",
- "1.1/vts/functional",
- "utils",
-]
diff --git a/contexthub/Android.bp b/contexthub/Android.bp
deleted file mode 100644
index ed19a37..0000000
--- a/contexthub/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "1.0/default",
- "1.0/vts/functional",
-]
diff --git a/drm/Android.bp b/drm/Android.bp
deleted file mode 100644
index ed19a37..0000000
--- a/drm/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "1.0/default",
- "1.0/vts/functional",
-]
diff --git a/dumpstate/Android.bp b/dumpstate/Android.bp
deleted file mode 100644
index ed19a37..0000000
--- a/dumpstate/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "1.0/default",
- "1.0/vts/functional",
-]
diff --git a/gatekeeper/Android.bp b/gatekeeper/Android.bp
deleted file mode 100644
index ed19a37..0000000
--- a/gatekeeper/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "1.0/default",
- "1.0/vts/functional",
-]
diff --git a/gnss/1.1/Android.bp b/gnss/1.1/Android.bp
new file mode 100644
index 0000000..09f65a4
--- /dev/null
+++ b/gnss/1.1/Android.bp
@@ -0,0 +1,19 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.gnss@1.1",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "IGnss.hal",
+ "IGnssCallback.hal",
+ ],
+ interfaces: [
+ "android.hardware.gnss@1.0",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
+
diff --git a/gnss/1.1/IGnss.hal b/gnss/1.1/IGnss.hal
new file mode 100644
index 0000000..f26d47c
--- /dev/null
+++ b/gnss/1.1/IGnss.hal
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss@1.1;
+
+import @1.0::IGnss;
+
+import IGnssCallback;
+
+/** Represents the standard GNSS (Global Navigation Satellite System) interface. */
+interface IGnss extends @1.0::IGnss {
+ /**
+ * Opens the interface and provides the callback routines
+ * to the implementation of this interface.
+ *
+ * @param callback Callback interface for IGnss.
+ *
+ * @return success Returns true on success.
+ */
+ setCallback_1_1(IGnssCallback callback) generates (bool success);
+};
\ No newline at end of file
diff --git a/gnss/1.1/IGnssCallback.hal b/gnss/1.1/IGnssCallback.hal
new file mode 100644
index 0000000..7a2849e
--- /dev/null
+++ b/gnss/1.1/IGnssCallback.hal
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss@1.1;
+
+import @1.0::IGnssCallback;
+
+/**
+ * The interface is required for the HAL to communicate certain information
+ * like status and location info back to the platform, the platform implements
+ * the interfaces and passes a handle to the HAL.
+ */
+interface IGnssCallback extends @1.0::IGnssCallback {
+ /**
+ * Callback to inform framework of the GNSS HAL implementation model & version name.
+ *
+ * This is a user-visible string that identifies the model and version of the GNSS HAL.
+ * For example "ABC Co., Baseband Part 1234, RF Part 567, Software version 3.14.159"
+ *
+ * This must be called in response to IGnss::setCallback
+ *
+ * @param name String providing the name of the GNSS HAL implementation
+ */
+ gnssNameCb(string name);
+};
\ No newline at end of file
diff --git a/gnss/1.1/vts/OWNERS b/gnss/1.1/vts/OWNERS
new file mode 100644
index 0000000..56648ad
--- /dev/null
+++ b/gnss/1.1/vts/OWNERS
@@ -0,0 +1,6 @@
+wyattriley@google.com
+gomo@google.com
+smalkos@google.com
+
+# VTS team
+yim@google.com
diff --git a/gnss/1.1/vts/functional/Android.bp b/gnss/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000..67ef486
--- /dev/null
+++ b/gnss/1.1/vts/functional/Android.bp
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsHalGnssV1_1TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "gnss_hal_test.cpp",
+ "gnss_hal_test_cases.cpp",
+ "VtsHalGnssV1_1TargetTest.cpp",
+ ],
+ static_libs: [
+ "android.hardware.gnss@1.0",
+ "android.hardware.gnss@1.1",
+ ],
+}
diff --git a/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp b/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp
new file mode 100644
index 0000000..9b805e4
--- /dev/null
+++ b/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsHalHidlTargetTestBase.h>
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
+}
\ No newline at end of file
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.cpp b/gnss/1.1/vts/functional/gnss_hal_test.cpp
new file mode 100644
index 0000000..40fd71b
--- /dev/null
+++ b/gnss/1.1/vts/functional/gnss_hal_test.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VtsHalGnssV1_1TargetTest"
+#include <log/log.h>
+
+#include <gnss_hal_test.h>
+
+#include <chrono>
+
+// Implementations for the main test class for GNSS HAL
+GnssHalTest::GnssHalTest() : info_called_count_(0), name_called_count_(0), notify_count_(0) {}
+
+void GnssHalTest::SetUp() {
+ gnss_hal_ = ::testing::VtsHalHidlTargetTestBase::getService<IGnss>();
+ ASSERT_NE(gnss_hal_, nullptr);
+}
+
+void GnssHalTest::TearDown() {
+ if (gnss_hal_ != nullptr) {
+ gnss_hal_->cleanup();
+ }
+ if (notify_count_ > 0) {
+ ALOGW("%d unprocessed callbacks discarded", notify_count_);
+ }
+}
+
+void GnssHalTest::notify() {
+ std::unique_lock<std::mutex> lock(mtx_);
+ notify_count_++;
+ cv_.notify_one();
+}
+
+std::cv_status GnssHalTest::wait(int timeoutSeconds) {
+ std::unique_lock<std::mutex> lock(mtx_);
+
+ auto status = std::cv_status::no_timeout;
+ while (notify_count_ == 0) {
+ status = cv_.wait_for(lock, std::chrono::seconds(timeoutSeconds));
+ if (status == std::cv_status::timeout) return status;
+ }
+ notify_count_--;
+ return status;
+}
+
+// Actual (test) callback handlers
+Return<void> GnssHalTest::GnssCallback::gnssSetSystemInfoCb(
+ const IGnssCallback::GnssSystemInfo& info) {
+ ALOGI("Info received, year %d", info.yearOfHw);
+ parent_.info_called_count_++;
+ parent_.last_info_ = info;
+ parent_.notify();
+ return Void();
+}
+
+// Actual (test) callback handlers
+Return<void> GnssHalTest::GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) {
+ ALOGI("Name received: %s", name.c_str());
+ parent_.name_called_count_++;
+ parent_.last_name_ = name;
+ parent_.notify();
+ return Void();
+}
\ No newline at end of file
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.h b/gnss/1.1/vts/functional/gnss_hal_test.h
new file mode 100644
index 0000000..05cb4ab
--- /dev/null
+++ b/gnss/1.1/vts/functional/gnss_hal_test.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GNSS_HAL_TEST_H_
+#define GNSS_HAL_TEST_H_
+
+#include <android/hardware/gnss/1.1/IGnss.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include <condition_variable>
+#include <mutex>
+
+using android::hardware::Return;
+using android::hardware::Void;
+
+using android::hardware::gnss::V1_0::GnssLocation;
+
+using android::hardware::gnss::V1_1::IGnss;
+using android::hardware::gnss::V1_1::IGnssCallback;
+
+using android::sp;
+
+// The main test class for GNSS HAL.
+class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ GnssHalTest();
+
+ virtual void SetUp() override;
+
+ virtual void TearDown() override;
+
+ /* Used as a mechanism to inform the test that a callback has occurred */
+ void notify();
+
+ /* Test code calls this function to wait for a callback */
+ std::cv_status wait(int timeoutSeconds);
+
+ /* Callback class for data & Event. */
+ class GnssCallback : public IGnssCallback {
+ public:
+ GnssHalTest& parent_;
+
+ GnssCallback(GnssHalTest& parent) : parent_(parent){};
+
+ virtual ~GnssCallback() = default;
+
+ // Dummy callback handlers
+ Return<void> gnssStatusCb(const IGnssCallback::GnssStatusValue /* status */) override {
+ return Void();
+ }
+ Return<void> gnssSvStatusCb(const IGnssCallback::GnssSvStatus& /* svStatus */) override {
+ return Void();
+ }
+ Return<void> gnssNmeaCb(int64_t /* timestamp */,
+ const android::hardware::hidl_string& /* nmea */) override {
+ return Void();
+ }
+ Return<void> gnssAcquireWakelockCb() override { return Void(); }
+ Return<void> gnssReleaseWakelockCb() override { return Void(); }
+ Return<void> gnssRequestTimeCb() override { return Void(); }
+ Return<void> gnssLocationCb(const GnssLocation& /* location */) override { return Void(); }
+ Return<void> gnssSetCapabilitesCb(uint32_t /* capabilities */) override { return Void(); }
+ // Actual (test) callback handlers
+ Return<void> gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) override;
+ Return<void> gnssNameCb(const android::hardware::hidl_string& name) override;
+ };
+
+ sp<IGnss> gnss_hal_; // GNSS HAL to call into
+ sp<IGnssCallback> gnss_cb_; // Primary callback interface
+
+ /* Count of calls to set the following items, and the latest item (used by
+ * test.)
+ */
+ int info_called_count_;
+ IGnssCallback::GnssSystemInfo last_info_;
+
+ int name_called_count_;
+ android::hardware::hidl_string last_name_;
+
+ private:
+ std::mutex mtx_;
+ std::condition_variable cv_;
+ int notify_count_;
+};
+
+#endif // GNSS_HAL_TEST_H_
diff --git a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
new file mode 100644
index 0000000..075940c
--- /dev/null
+++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gnss_hal_test.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#define TIMEOUT_SEC 2 // for basic commands/responses
+
+/*
+ * SetupTeardownCreateCleanup:
+ * Requests the gnss HAL then calls cleanup
+ *
+ * Empty test fixture to verify basic Setup & Teardown
+ */
+TEST_F(GnssHalTest, SetupTeardownCreateCleanup) {}
+
+/*
+ * SetCallbackResponses:
+ * Sets up the callback, awaits the info & name
+ */
+TEST_F(GnssHalTest, SetCallbackResponses) {
+ gnss_cb_ = new GnssCallback(*this);
+ ASSERT_NE(gnss_cb_, nullptr);
+
+ auto result = gnss_hal_->setCallback_1_1(gnss_cb_);
+ if (!result.isOk()) {
+ ALOGE("result of failed setCallback %s", result.description().c_str());
+ }
+
+ ASSERT_TRUE(result.isOk());
+ ASSERT_TRUE(result);
+
+ /*
+ * Both name and systemInfo callbacks should trigger
+ */
+ EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC));
+ EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC));
+
+ EXPECT_EQ(info_called_count_, 1);
+ EXPECT_EQ(name_called_count_, 1);
+}
\ No newline at end of file
diff --git a/gnss/Android.bp b/gnss/Android.bp
deleted file mode 100644
index ed19a37..0000000
--- a/gnss/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "1.0/default",
- "1.0/vts/functional",
-]
diff --git a/graphics/Android.bp b/graphics/Android.bp
deleted file mode 100644
index 9fa9241..0000000
--- a/graphics/Android.bp
+++ /dev/null
@@ -1,15 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "allocator/2.0",
- "allocator/2.0/default",
- "bufferqueue/1.0",
- "common/1.0",
- "composer/2.1",
- "composer/2.1/default",
- "composer/2.1/vts/functional",
- "mapper/2.0",
- "mapper/2.0/default",
- "mapper/2.0/vts/functional",
- "mapper/2.1",
- "mapper/2.1/vts/functional",
-]
diff --git a/health/Android.bp b/health/Android.bp
deleted file mode 100644
index ca89713..0000000
--- a/health/Android.bp
+++ /dev/null
@@ -1,9 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "1.0/default",
- "1.0/default/libhealthd",
- "1.0/vts/functional",
- "2.0",
- "2.0/vts/functional",
-]
diff --git a/ir/Android.bp b/ir/Android.bp
deleted file mode 100644
index ed19a37..0000000
--- a/ir/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "1.0/default",
- "1.0/vts/functional",
-]
diff --git a/keymaster/4.0/Android.bp b/keymaster/4.0/Android.bp
new file mode 100644
index 0000000..2d4e7bf
--- /dev/null
+++ b/keymaster/4.0/Android.bp
@@ -0,0 +1,28 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.keymaster@4.0",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IKeymaster.hal",
+ ],
+ interfaces: [
+ "android.hardware.keymaster@3.0",
+ "android.hidl.base@1.0",
+ ],
+ types: [
+ "HardwareAuthToken",
+ "HardwareAuthTokenMacMethod",
+ "KeyCharacteristics",
+ "KeyParameter",
+ "KeyPurpose",
+ "Tag",
+ "TagType",
+ ],
+ gen_java: false,
+}
+
diff --git a/keymaster/4.0/IKeymaster.hal b/keymaster/4.0/IKeymaster.hal
new file mode 100644
index 0000000..b841832
--- /dev/null
+++ b/keymaster/4.0/IKeymaster.hal
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.keymaster@4.0;
+
+import android.hardware.keymaster@3.0::ErrorCode;
+import android.hardware.keymaster@3.0::KeyFormat;
+
+/**
+ * Keymaster device definition. For thorough documentation see the implementer's reference, at
+ * https://source.android.com/security/keystore/implementer-ref.html
+ */
+interface IKeymaster {
+
+ /**
+ * Returns information about the underlying keymaster hardware.
+ *
+ * @return isSecure Indicates whether this keymaster implementation is in some sort of secure
+ * hardware.
+ *
+ * @return keymasterName is the name of the keymaster implementation.
+ *
+ * @return keymasterAuthorName is the name of the author of the keymaster implementation
+ * (organization name, not individual).
+ */
+ getHardwareInfo() generates (bool isSecure, string keymasterName, string keymasterAuthorName);
+
+ /**
+ * Adds entropy to the RNG used by keymaster. Entropy added through this method must not be the
+ * only source of entropy used. The keymaster implementation must securely mix entropy provided
+ * through this method with internally-generated entropy.
+ *
+ * @param data Bytes to be mixed into the RNG.
+ *
+ * @return error See the ErrorCode enum in types.hal.
+ */
+ addRngEntropy(vec<uint8_t> data) generates (ErrorCode error);
+
+ /**
+ * Generates a key, or key pair, returning a key blob and a description of the key.
+ *
+ * @param keyParams Key generation parameters are defined as keymaster tag/value pairs, provided
+ * in params. See Tag in types.hal for the full list.
+ *
+ * @return error See the ErrorCode enum in types.hal.
+ *
+ * @return keyBlob Opaque, encrypted descriptor of the generated key. A recommended
+ * implementation strategy is to include an encrypted copy of the key material, wrapped
+ * in a key unavailable outside secure hardware.
+ *
+ * @return keyCharacteristics Description of the generated key. See KeyCharacteristis in
+ * types.hal.
+ */
+ generateKey(vec<KeyParameter> keyParams)
+ generates (ErrorCode error, vec<uint8_t> keyBlob, KeyCharacteristics keyCharacteristics);
+
+ /**
+ * Imports a key, or key pair, returning a key blob and/or a description of the key.
+ *
+ * @param keyParams Key generation parameters are defined as keymaster tag/value pairs, provided
+ * in params. See Tag for the full list.
+ *
+ * @param keyFormat The format of the key material to import.
+ *
+ * @pram keyData The key material to import, in the format specifed in keyFormat.
+ *
+ * @return error See the ErrorCode enum.
+ *
+ * @return keyBlob Opaque, encrypted descriptor of the generated key, which will generally
+ * contain a copy of the key material, wrapped in a key unavailable outside secure
+ * hardware.
+ *
+ * @return keyCharacteristics Decription of the generated key.
+ */
+ importKey(vec<KeyParameter> keyParams, KeyFormat keyFormat, vec<uint8_t> keyData)
+ generates (ErrorCode error, vec<uint8_t> keyBlob, KeyCharacteristics keyCharacteristics);
+
+ /**
+ * Returns the characteristics of the specified key, if the keyBlob is valid (implementations
+ * must fully validate the integrity of the key).
+ *
+ * @param keyBlob The opaque descriptor returned by generateKey() or importKey();
+ *
+ * @param clientId An opaque byte string identifying the client. This value must match the
+ * Tag::APPLICATION_ID data provided during key generation/import. Without the correct
+ * value, it must be computationally infeasible for the secure hardware to obtain the key
+ * material.
+ *
+ * @param appData An opaque byte string provided by the application. This value must match the
+ * Tag::APPLICATION_DATA data provided during key generation/import. Without the correct
+ * value, it must be computationally infeasible for the secure hardware to obtain the key
+ * material.
+ *
+ * @return error See the ErrorCode enum in types.hal.
+ *
+ * @return keyCharacteristics Decription of the generated key. See KeyCharacteristis in
+ * types.hal.
+ */
+ getKeyCharacteristics(vec<uint8_t> keyBlob, vec<uint8_t> clientId, vec<uint8_t> appData)
+ generates (ErrorCode error, KeyCharacteristics keyCharacteristics);
+
+ /**
+ * Exports a public key, returning the key in the specified format.
+ *
+ * @parm keyFormat The format used for export. See KeyFormat in types.hal.
+ *
+ * @param keyBlob The opaque descriptor returned by generateKey() or importKey(). The
+ * referenced key must be asymmetric.
+ *
+ * @param clientId An opaque byte string identifying the client. This value must match the
+ * Tag::APPLICATION_ID data provided during key generation/import. Without the correct
+ * value, it must be computationally infeasible for the secure hardware to obtain the key
+ * material.
+ *
+ * @param appData An opaque byte string provided by the application. This value must match the
+ * Tag::APPLICATION_DATA data provided during key generation/import. Without the correct
+ * value, it must be computationally infeasible for the secure hardware to obtain the key
+ * material.
+ *
+ * @return error See the ErrorCode enum in types.hal.
+ *
+ * @return keyMaterial The public key material in PKCS#8 format.
+ */
+ exportKey(KeyFormat keyFormat, vec<uint8_t> keyBlob, vec<uint8_t> clientId,
+ vec<uint8_t> appData) generates (ErrorCode error, vec<uint8_t> keyMaterial);
+
+ /**
+ * Generates a signed X.509 certificate chain attesting to the presence of keyToAttest in
+ * keymaster. The certificate must contain an extension with OID 1.3.6.1.4.1.11129.2.1.17 and
+ * value defined in:
+ *
+ * https://developer.android.com/training/articles/security-key-attestation.html.
+ *
+ * @param keyToAttest The opaque descriptor returned by generateKey() or importKey(). The
+ * referenced key must be asymmetric.
+ *
+ * @param attestParams Parameters for the attestation, notably Tag::ATTESTATION_CHALLENGE.
+ *
+ * @return error See the ErrorCode enum in types.hal.
+ *
+ * @return certChain The attestation certificate, and additional certificates back to the root
+ * attestation certificate, which clients will need to check against a known-good value.
+ */
+ attestKey(vec<uint8_t> keyToAttest, vec<KeyParameter> attestParams)
+ generates (ErrorCode error, vec<vec<uint8_t>> certChain);
+
+ /**
+ * Upgrades an old key blob. Keys can become "old" in two ways: Keymaster can be upgraded to a
+ * new version with an incompatible key blob format, or the system can be updated to invalidate
+ * the OS version and/or patch level. In either case, attempts to use an old key blob with
+ * getKeyCharacteristics(), exportKey(), attestKey() or begin() must result in keymaster
+ * returning ErrorCode::KEY_REQUIRES_UPGRADE. The caller must use this method to upgrade the
+ * key blob.
+ *
+ * @param keyBlobToUpgrade The opaque descriptor returned by generateKey() or importKey();
+ *
+ * @param upgradeParams A parameter list containing any parameters needed to complete the
+ * upgrade, including Tag::APPLICATION_ID and Tag::APPLICATION_DATA.
+ *
+ * @return error See the ErrorCode enum.
+ *
+ * @return upgradedKeyBlob A new key blob that references the same key as keyBlobToUpgrade, but
+ * is in the new format, or has the new version data.
+ */
+ upgradeKey(vec<uint8_t> keyBlobToUpgrade, vec<KeyParameter> upgradeParams)
+ generates (ErrorCode error, vec<uint8_t> upgradedKeyBlob);
+
+ /**
+ * Deletes the key, or key pair, associated with the key blob. Calling this function on a key
+ * with Tag::ROLLBACK_RESISTANCE in its hardware-enforced authorization list must render the key
+ * permanently unusable. Keys without Tag::ROLLBACK_RESISTANCE may or may not be rendered
+ * unusable.
+ *
+ * @param keyBlob The opaque descriptor returned by generateKey() or importKey();
+ *
+ * @return error See the ErrorCode enum.
+ */
+ deleteKey(vec<uint8_t> keyBlob) generates (ErrorCode error);
+
+ /**
+ * Deletes all keys in the hardware keystore. Used when keystore is reset completely. After
+ * this function is called all keys with Tag::ROLLBACK_RESISTANCE in their hardware-enforced
+ * authorization lists must be rendered permanently unusable. Keys without
+ * Tag::ROLLBACK_RESISTANCE may or may not be rendered unusable.
+ *
+ * @return error See the ErrorCode enum.
+ */
+ deleteAllKeys() generates (ErrorCode error);
+
+ /**
+ * Destroys knowledge of the device's ids. This prevents all device id attestation in the
+ * future. The destruction must be permanent so that not even a factory reset will restore the
+ * device ids.
+ *
+ * Device id attestation may be provided only if this method is fully implemented, allowing the
+ * user to permanently disable device id attestation. If this cannot be guaranteed, the device
+ * must never attest any device ids.
+ *
+ * This is a NOP if device id attestation is not supported.
+ *
+ * @return error See the ErrorCode enum.
+ */
+ destroyAttestationIds() generates (ErrorCode error);
+
+ /**
+ * Begins a cryptographic operation using the specified key. If all is well, begin() must
+ * return ErrorCode::OK and create an operation handle which must be passed to subsequent calls
+ * to update(), finish() or abort().
+ *
+ * It is critical that each call to begin() be paired with a subsequent call to finish() or
+ * abort(), to allow the keymaster implementation to clean up any internal operation state. The
+ * caller's failure to do this may leak internal state space or other internal resources and may
+ * eventually cause begin() to return ErrorCode::TOO_MANY_OPERATIONS when it runs out of space
+ * for operations. Any result other than ErrorCode::OK from begin(), update() or finish()
+ * implicitly aborts the operation, in which case abort() need not be called (and must return
+ * ErrorCode::INVALID_OPERATION_HANDLE if called).
+ *
+ * @param purpose The purpose of the operation, one of KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT,
+ * KeyPurpose::SIGN or KeyPurpose::VERIFY. Note that for AEAD modes, encryption and
+ * decryption imply signing and verification, respectively, but must be specified as
+ * KeyPurpose::ENCRYPT and KeyPurpose::DECRYPT.
+ *
+ * @param keyBlob The opaque key descriptor returned by generateKey() or importKey(). The key
+ * must have a purpose compatible with purpose and all of its usage requirements must be
+ * satisfied, or begin() must return an appropriate error code.
+ *
+ * @param inParams Additional parameters for the operation. If Tag::APPLICATION_ID or
+ * Tag::APPLICATION_DATA were provided during generation, they must be provided here, or
+ * the operation must fail with ErrorCode::INVALID_KEY_BLOB. For operations that require
+ * a nonce or IV, on keys that were generated with Tag::CALLER_NONCE, inParams may
+ * contain a tag Tag::NONCE. If Tag::NONCE is provided for a key without
+ * Tag:CALLER_NONCE, ErrorCode::CALLER_NONCE_PROHIBITED must be returned.
+ *
+ * @param authToken Authentication token. Callers that provide no token must set all numeric
+ * fields to zero and the MAC must be an empty vector.
+ *
+ * @return error See the ErrorCode enum in types.hal.
+ *
+ * @return outParams Output parameters. Used to return additional data from the operation
+ * initialization, notably to return the IV or nonce from operations that generate an IV
+ * or nonce.
+ *
+ * @return operationHandle The newly-created operation handle which must be passed to update(),
+ * finish() or abort().
+ */
+ begin(KeyPurpose purpose, vec<uint8_t> keyBlob, vec<KeyParameter> inParams,
+ HardwareAuthToken authToken)
+ generates (ErrorCode error, vec<KeyParameter> outParams, OperationHandle operationHandle);
+
+ /**
+ * Provides data to, and possibly receives output from, an ongoing cryptographic operation begun
+ * with begin().
+ *
+ * If operationHandle is invalid, update() must return ErrorCode::INVALID_OPERATION_HANDLE.
+ *
+ * update() may not consume all of the data provided in the data buffer. update() must return
+ * the amount consumed in inputConsumed. The caller may provide the unconsumed data in a
+ * subsequent call.
+ *
+ * @param operationHandle The operation handle returned by begin().
+ *
+ * @param inParams Additional parameters for the operation. For AEAD modes, this is used to
+ * specify Tag::ADDITIONAL_DATA. Note that additional data may be provided in multiple
+ * calls to update(), but only until input data has been provided.
+ *
+ * @param input Data to be processed. Note that update() may or may not consume all of the data
+ * provided. See inputConsumed.
+ *
+ * @param authToken Authentication token. Callers that provide no token must set all numeric
+ * fields to zero and the MAC must be an empty vector.
+ *
+ * @return error See the ErrorCode enum in types.hal.
+ *
+ * @return inputConsumed Amount of data that was consumed by update(). If this is less than the
+ * amount provided, the caller may provide the remainder in a subsequent call to
+ * update() or finish(). Every call to update must consume at least one byte, and
+ * implementations should consume as much data as reasonably possible for each call.
+ *
+ * @return outParams Output parameters, used to return additional data from the operation.
+ *
+ * @return output The output data, if any.
+ */
+ update(OperationHandle operationHandle, vec<KeyParameter> inParams, vec<uint8_t> input,
+ HardwareAuthToken authToken)
+ generates (ErrorCode error, uint32_t inputConsumed, vec<KeyParameter> outParams,
+ vec<uint8_t> output);
+
+ /**
+ * Finalizes a cryptographic operation begun with begin() and invalidates operationHandle.
+ *
+ * @param operationHandle The operation handle returned by begin(). This handle must be invalid
+ * when finish() returns.
+ *
+ * @param inParams Additional parameters for the operation. For AEAD modes, this is used to
+ * specify Tag::ADDITIONAL_DATA, but only if no input data was provided to update().
+ *
+ * @param input Data to be processed, per the parameters established in the call to begin().
+ * finish() must consume all provided data or return ErrorCode::INVALID_INPUT_LENGTH.
+ *
+ * @param signature The signature to be verified if the purpose specified in the begin() call
+ * was KeyPurpose::VERIFY.
+ *
+ * @param authToken Authentication token. Callers that provide no token must set all numeric
+ * fields to zero and the MAC must be an empty vector.
+ *
+ * @return error See the ErrorCode enum in types.hal.
+ *
+ * @return outParams Any output parameters generated by finish().
+ *
+ * @return output The output data, if any.
+ */
+ finish(OperationHandle operationHandle, vec<KeyParameter> inParams, vec<uint8_t> input,
+ vec<uint8_t> signature, HardwareAuthToken authToken)
+ generates (ErrorCode error, vec<KeyParameter> outParams, vec<uint8_t> output);
+
+ /**
+ * Aborts a cryptographic operation begun with begin(), freeing all internal resources and
+ * invalidating operationHandle.
+ *
+ * @param operationHandle The operation handle returned by begin(). This handle must be
+ * invalid when abort() returns.
+ *
+ * @return error See the ErrorCode enum in types.hal.
+ */
+ abort(OperationHandle operationHandle) generates (ErrorCode error);
+};
diff --git a/keymaster/4.0/default/Android.bp b/keymaster/4.0/default/Android.bp
new file mode 100644
index 0000000..0cede50
--- /dev/null
+++ b/keymaster/4.0/default/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_binary {
+ name: "android.hardware.keymaster@4.0-service",
+ defaults: ["hidl_defaults"],
+ relative_install_path: "hw",
+ vendor: true,
+ init_rc: ["android.hardware.keymaster@4.0-service.rc"],
+ srcs: ["service.cpp"],
+
+ shared_libs: [
+ "android.hardware.keymaster@4.0",
+ "libbase",
+ "libcutils",
+ "libhardware",
+ "libhidlbase",
+ "libhidltransport",
+ "libkeymaster4",
+ "liblog",
+ "libutils",
+ ],
+
+}
diff --git a/keymaster/4.0/default/OWNERS b/keymaster/4.0/default/OWNERS
new file mode 100644
index 0000000..335660d
--- /dev/null
+++ b/keymaster/4.0/default/OWNERS
@@ -0,0 +1,2 @@
+jdanis@google.com
+swillden@google.com
diff --git a/keymaster/4.0/default/android.hardware.keymaster@4.0-service.rc b/keymaster/4.0/default/android.hardware.keymaster@4.0-service.rc
new file mode 100644
index 0000000..2ce439e
--- /dev/null
+++ b/keymaster/4.0/default/android.hardware.keymaster@4.0-service.rc
@@ -0,0 +1,4 @@
+service vendor.keymaster-4-0 /vendor/bin/hw/android.hardware.keymaster@4.0-service
+ class early_hal
+ user system
+ group system drmrpc
diff --git a/keymaster/4.0/default/service.cpp b/keymaster/4.0/default/service.cpp
new file mode 100644
index 0000000..adb27e1
--- /dev/null
+++ b/keymaster/4.0/default/service.cpp
@@ -0,0 +1,33 @@
+/*
+**
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <android-base/logging.h>
+#include <android/hardware/keymaster/4.0/IKeymaster.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include <AndroidKeymaster4.h>
+
+int main() {
+ auto keymaster = ::keymaster::V4_0::ng::CreateKeymaster();
+ auto status = keymaster->registerAsService();
+ if (status != android::OK) {
+ LOG(FATAL) << "Could not register service for Keymaster 4.0 (" << status << ")";
+ }
+
+ android::hardware::joinRpcThreadpool();
+ return -1; // Should never get here.
+}
diff --git a/keymaster/4.0/support/Android.bp b/keymaster/4.0/support/Android.bp
new file mode 100644
index 0000000..31acfca
--- /dev/null
+++ b/keymaster/4.0/support/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library {
+ name: "libkeymaster4support",
+ vendor_available: true,
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+ srcs: [
+ "attestation_record.cpp",
+ "authorization_set.cpp",
+ "key_param_output.cpp",
+ ],
+ export_include_dirs: ["include"],
+ shared_libs: [
+ "android.hardware.keymaster@3.0",
+ "android.hardware.keymaster@4.0",
+ "libcrypto",
+ "libhidlbase",
+ ]
+}
diff --git a/keymaster/4.0/support/OWNERS b/keymaster/4.0/support/OWNERS
new file mode 100644
index 0000000..335660d
--- /dev/null
+++ b/keymaster/4.0/support/OWNERS
@@ -0,0 +1,2 @@
+jdanis@google.com
+swillden@google.com
diff --git a/keymaster/4.0/support/attestation_record.cpp b/keymaster/4.0/support/attestation_record.cpp
new file mode 100644
index 0000000..8f37d9c
--- /dev/null
+++ b/keymaster/4.0/support/attestation_record.cpp
@@ -0,0 +1,289 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <keymasterV4_0/attestation_record.h>
+
+#include <assert.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#include <keymasterV4_0/authorization_set.h>
+#include <keymasterV4_0/openssl_utils.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+
+struct stack_st_ASN1_TYPE_Delete {
+ void operator()(stack_st_ASN1_TYPE* p) { sk_ASN1_TYPE_free(p); }
+};
+
+struct ASN1_STRING_Delete {
+ void operator()(ASN1_STRING* p) { ASN1_STRING_free(p); }
+};
+
+struct ASN1_TYPE_Delete {
+ void operator()(ASN1_TYPE* p) { ASN1_TYPE_free(p); }
+};
+
+#define ASN1_INTEGER_SET STACK_OF(ASN1_INTEGER)
+
+typedef struct km_root_of_trust {
+ ASN1_OCTET_STRING* verified_boot_key;
+ ASN1_BOOLEAN* device_locked;
+ ASN1_ENUMERATED* verified_boot_state;
+} KM_ROOT_OF_TRUST;
+
+ASN1_SEQUENCE(KM_ROOT_OF_TRUST) = {
+ ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_key, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(KM_ROOT_OF_TRUST, device_locked, ASN1_BOOLEAN),
+ ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_state, ASN1_ENUMERATED),
+} ASN1_SEQUENCE_END(KM_ROOT_OF_TRUST);
+IMPLEMENT_ASN1_FUNCTIONS(KM_ROOT_OF_TRUST);
+
+typedef struct km_auth_list {
+ ASN1_INTEGER_SET* purpose;
+ ASN1_INTEGER* algorithm;
+ ASN1_INTEGER* key_size;
+ ASN1_INTEGER_SET* digest;
+ ASN1_INTEGER_SET* padding;
+ ASN1_INTEGER* ec_curve;
+ ASN1_INTEGER* rsa_public_exponent;
+ ASN1_INTEGER* active_date_time;
+ ASN1_INTEGER* origination_expire_date_time;
+ ASN1_INTEGER* usage_expire_date_time;
+ ASN1_NULL* no_auth_required;
+ ASN1_INTEGER* user_auth_type;
+ ASN1_INTEGER* auth_timeout;
+ ASN1_NULL* allow_while_on_body;
+ ASN1_NULL* all_applications;
+ ASN1_OCTET_STRING* application_id;
+ ASN1_INTEGER* creation_date_time;
+ ASN1_INTEGER* origin;
+ ASN1_NULL* rollback_resistant;
+ KM_ROOT_OF_TRUST* root_of_trust;
+ ASN1_INTEGER* os_version;
+ ASN1_INTEGER* os_patchlevel;
+ ASN1_OCTET_STRING* attestation_application_id;
+} KM_AUTH_LIST;
+
+ASN1_SEQUENCE(KM_AUTH_LIST) = {
+ ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.maskedTag()),
+ ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.maskedTag()),
+ ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER,
+ TAG_RSA_PUBLIC_EXPONENT.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER,
+ TAG_ORIGINATION_EXPIRE_DATETIME.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER,
+ TAG_USAGE_EXPIRE_DATETIME.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, allow_while_on_body, ASN1_NULL, TAG_ALLOW_WHILE_ON_BODY.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, application_id, ASN1_OCTET_STRING, TAG_APPLICATION_ID.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER, TAG_CREATION_DATETIME.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistant, ASN1_NULL, TAG_ROLLBACK_RESISTANCE.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.maskedTag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, attestation_application_id, ASN1_OCTET_STRING,
+ TAG_ATTESTATION_APPLICATION_ID.maskedTag()),
+} ASN1_SEQUENCE_END(KM_AUTH_LIST);
+IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST);
+
+typedef struct km_key_description {
+ ASN1_INTEGER* attestation_version;
+ ASN1_ENUMERATED* attestation_security_level;
+ ASN1_INTEGER* keymaster_version;
+ ASN1_ENUMERATED* keymaster_security_level;
+ ASN1_OCTET_STRING* attestation_challenge;
+ KM_AUTH_LIST* software_enforced;
+ KM_AUTH_LIST* tee_enforced;
+ ASN1_INTEGER* unique_id;
+} KM_KEY_DESCRIPTION;
+
+ASN1_SEQUENCE(KM_KEY_DESCRIPTION) = {
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_version, ASN1_INTEGER),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_security_level, ASN1_ENUMERATED),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_version, ASN1_INTEGER),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_security_level, ASN1_ENUMERATED),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_challenge, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, unique_id, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, software_enforced, KM_AUTH_LIST),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, tee_enforced, KM_AUTH_LIST),
+} ASN1_SEQUENCE_END(KM_KEY_DESCRIPTION);
+IMPLEMENT_ASN1_FUNCTIONS(KM_KEY_DESCRIPTION);
+
+template <Tag tag>
+void copyAuthTag(const stack_st_ASN1_INTEGER* stack, TypedTag<TagType::ENUM_REP, tag> ttag,
+ AuthorizationSet* auth_list) {
+ typedef typename TypedTag2ValueType<decltype(ttag)>::type ValueT;
+ for (size_t i = 0; i < sk_ASN1_INTEGER_num(stack); ++i) {
+ auth_list->push_back(
+ ttag, static_cast<ValueT>(ASN1_INTEGER_get(sk_ASN1_INTEGER_value(stack, i))));
+ }
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::ENUM, tag> ttag,
+ AuthorizationSet* auth_list) {
+ typedef typename TypedTag2ValueType<decltype(ttag)>::type ValueT;
+ if (!asn1_int) return;
+ auth_list->push_back(ttag, static_cast<ValueT>(ASN1_INTEGER_get(asn1_int)));
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::UINT, tag> ttag,
+ AuthorizationSet* auth_list) {
+ if (!asn1_int) return;
+ auth_list->push_back(ttag, ASN1_INTEGER_get(asn1_int));
+}
+
+BIGNUM* construct_uint_max() {
+ BIGNUM* value = BN_new();
+ BIGNUM_Ptr one(BN_new());
+ BN_one(one.get());
+ BN_lshift(value, one.get(), 32);
+ return value;
+}
+
+uint64_t BignumToUint64(BIGNUM* num) {
+ static_assert((sizeof(BN_ULONG) == sizeof(uint32_t)) || (sizeof(BN_ULONG) == sizeof(uint64_t)),
+ "This implementation only supports 32 and 64-bit BN_ULONG");
+ if (sizeof(BN_ULONG) == sizeof(uint32_t)) {
+ BIGNUM_Ptr uint_max(construct_uint_max());
+ BIGNUM_Ptr hi(BN_new()), lo(BN_new());
+ BN_CTX_Ptr ctx(BN_CTX_new());
+ BN_div(hi.get(), lo.get(), num, uint_max.get(), ctx.get());
+ return static_cast<uint64_t>(BN_get_word(hi.get())) << 32 | BN_get_word(lo.get());
+ } else if (sizeof(BN_ULONG) == sizeof(uint64_t)) {
+ return BN_get_word(num);
+ } else {
+ return 0;
+ }
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::ULONG, tag> ttag,
+ AuthorizationSet* auth_list) {
+ if (!asn1_int) return;
+ BIGNUM_Ptr num(ASN1_INTEGER_to_BN(asn1_int, nullptr));
+ auth_list->push_back(ttag, BignumToUint64(num.get()));
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::DATE, tag> ttag,
+ AuthorizationSet* auth_list) {
+ if (!asn1_int) return;
+ BIGNUM_Ptr num(ASN1_INTEGER_to_BN(asn1_int, nullptr));
+ auth_list->push_back(ttag, BignumToUint64(num.get()));
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_NULL* asn1_null, TypedTag<TagType::BOOL, tag> ttag,
+ AuthorizationSet* auth_list) {
+ if (!asn1_null) return;
+ auth_list->push_back(ttag);
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_OCTET_STRING* asn1_string, TypedTag<TagType::BYTES, tag> ttag,
+ AuthorizationSet* auth_list) {
+ if (!asn1_string) return;
+ hidl_vec<uint8_t> buf;
+ buf.setToExternal(asn1_string->data, asn1_string->length);
+ auth_list->push_back(ttag, buf);
+}
+
+// Extract the values from the specified ASN.1 record and place them in auth_list.
+static ErrorCode extract_auth_list(const KM_AUTH_LIST* record, AuthorizationSet* auth_list) {
+ if (!record) return ErrorCode::OK;
+
+ copyAuthTag(record->active_date_time, TAG_ACTIVE_DATETIME, auth_list);
+ copyAuthTag(record->algorithm, TAG_ALGORITHM, auth_list);
+ copyAuthTag(record->application_id, TAG_APPLICATION_ID, auth_list);
+ copyAuthTag(record->auth_timeout, TAG_AUTH_TIMEOUT, auth_list);
+ copyAuthTag(record->creation_date_time, TAG_CREATION_DATETIME, auth_list);
+ copyAuthTag(record->digest, TAG_DIGEST, auth_list);
+ copyAuthTag(record->ec_curve, TAG_EC_CURVE, auth_list);
+ copyAuthTag(record->key_size, TAG_KEY_SIZE, auth_list);
+ copyAuthTag(record->no_auth_required, TAG_NO_AUTH_REQUIRED, auth_list);
+ copyAuthTag(record->origin, TAG_ORIGIN, auth_list);
+ copyAuthTag(record->origination_expire_date_time, TAG_ORIGINATION_EXPIRE_DATETIME, auth_list);
+ copyAuthTag(record->os_patchlevel, TAG_OS_PATCHLEVEL, auth_list);
+ copyAuthTag(record->os_version, TAG_OS_VERSION, auth_list);
+ copyAuthTag(record->padding, TAG_PADDING, auth_list);
+ copyAuthTag(record->purpose, TAG_PURPOSE, auth_list);
+ copyAuthTag(record->rollback_resistant, TAG_ROLLBACK_RESISTANCE, auth_list);
+ copyAuthTag(record->rsa_public_exponent, TAG_RSA_PUBLIC_EXPONENT, auth_list);
+ copyAuthTag(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list);
+ copyAuthTag(record->user_auth_type, TAG_USER_AUTH_TYPE, auth_list);
+ copyAuthTag(record->attestation_application_id, TAG_ATTESTATION_APPLICATION_ID, auth_list);
+
+ return ErrorCode::OK;
+}
+
+MAKE_OPENSSL_PTR_TYPE(KM_KEY_DESCRIPTION)
+
+// Parse the DER-encoded attestation record, placing the results in keymaster_version,
+// attestation_challenge, software_enforced, tee_enforced and unique_id.
+ErrorCode parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
+ uint32_t* attestation_version, //
+ SecurityLevel* attestation_security_level,
+ uint32_t* keymaster_version,
+ SecurityLevel* keymaster_security_level,
+ hidl_vec<uint8_t>* attestation_challenge,
+ AuthorizationSet* software_enforced,
+ AuthorizationSet* tee_enforced, //
+ hidl_vec<uint8_t>* unique_id) {
+ const uint8_t* p = asn1_key_desc;
+ KM_KEY_DESCRIPTION_Ptr record(d2i_KM_KEY_DESCRIPTION(nullptr, &p, asn1_key_desc_len));
+ if (!record.get()) return ErrorCode::UNKNOWN_ERROR;
+
+ *attestation_version = ASN1_INTEGER_get(record->attestation_version);
+ *attestation_security_level =
+ static_cast<SecurityLevel>(ASN1_ENUMERATED_get(record->attestation_security_level));
+ *keymaster_version = ASN1_INTEGER_get(record->keymaster_version);
+ *keymaster_security_level =
+ static_cast<SecurityLevel>(ASN1_ENUMERATED_get(record->keymaster_security_level));
+
+ auto& chall = record->attestation_challenge;
+ attestation_challenge->resize(chall->length);
+ memcpy(attestation_challenge->data(), chall->data, chall->length);
+ auto& uid = record->unique_id;
+ unique_id->resize(uid->length);
+ memcpy(unique_id->data(), uid->data, uid->length);
+
+ ErrorCode error = extract_auth_list(record->software_enforced, software_enforced);
+ if (error != ErrorCode::OK) return error;
+
+ return extract_auth_list(record->tee_enforced, tee_enforced);
+}
+
+} // namespace V4_0
+} // namespace keymaster
+} // namespace hardware
+} // namespace android
diff --git a/keymaster/4.0/support/authorization_set.cpp b/keymaster/4.0/support/authorization_set.cpp
new file mode 100644
index 0000000..de3e270
--- /dev/null
+++ b/keymaster/4.0/support/authorization_set.cpp
@@ -0,0 +1,515 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <keymasterV4_0/authorization_set.h>
+
+#include <assert.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+
+inline bool keyParamLess(const KeyParameter& a, const KeyParameter& b) {
+ if (a.tag != b.tag) return a.tag < b.tag;
+ int retval;
+ switch (typeFromTag(a.tag)) {
+ case TagType::INVALID:
+ case TagType::BOOL:
+ return false;
+ case TagType::ENUM:
+ case TagType::ENUM_REP:
+ case TagType::UINT:
+ case TagType::UINT_REP:
+ return a.f.integer < b.f.integer;
+ case TagType::ULONG:
+ case TagType::ULONG_REP:
+ return a.f.longInteger < b.f.longInteger;
+ case TagType::DATE:
+ return a.f.dateTime < b.f.dateTime;
+ case TagType::BIGNUM:
+ case TagType::BYTES:
+ // Handle the empty cases.
+ if (a.blob.size() == 0) return b.blob.size() != 0;
+ if (b.blob.size() == 0) return false;
+
+ retval = memcmp(&a.blob[0], &b.blob[0], std::min(a.blob.size(), b.blob.size()));
+ // if one is the prefix of the other the longer wins
+ if (retval == 0) return a.blob.size() < b.blob.size();
+ // Otherwise a is less if a is less.
+ else
+ return retval < 0;
+ }
+ return false;
+}
+
+inline bool keyParamEqual(const KeyParameter& a, const KeyParameter& b) {
+ if (a.tag != b.tag) return false;
+
+ switch (typeFromTag(a.tag)) {
+ case TagType::INVALID:
+ case TagType::BOOL:
+ return true;
+ case TagType::ENUM:
+ case TagType::ENUM_REP:
+ case TagType::UINT:
+ case TagType::UINT_REP:
+ return a.f.integer == b.f.integer;
+ case TagType::ULONG:
+ case TagType::ULONG_REP:
+ return a.f.longInteger == b.f.longInteger;
+ case TagType::DATE:
+ return a.f.dateTime == b.f.dateTime;
+ case TagType::BIGNUM:
+ case TagType::BYTES:
+ if (a.blob.size() != b.blob.size()) return false;
+ return a.blob.size() == 0 || memcmp(&a.blob[0], &b.blob[0], a.blob.size()) == 0;
+ }
+ return false;
+}
+
+void AuthorizationSet::Sort() {
+ std::sort(data_.begin(), data_.end(), keyParamLess);
+}
+
+void AuthorizationSet::Deduplicate() {
+ if (data_.empty()) return;
+
+ Sort();
+ std::vector<KeyParameter> result;
+
+ auto curr = data_.begin();
+ auto prev = curr++;
+ for (; curr != data_.end(); ++prev, ++curr) {
+ if (prev->tag == Tag::INVALID) continue;
+
+ if (!keyParamEqual(*prev, *curr)) {
+ result.emplace_back(std::move(*prev));
+ }
+ }
+ result.emplace_back(std::move(*prev));
+
+ std::swap(data_, result);
+}
+
+void AuthorizationSet::Union(const AuthorizationSet& other) {
+ data_.insert(data_.end(), other.data_.begin(), other.data_.end());
+ Deduplicate();
+}
+
+void AuthorizationSet::Subtract(const AuthorizationSet& other) {
+ Deduplicate();
+
+ auto i = other.begin();
+ while (i != other.end()) {
+ int pos = -1;
+ do {
+ pos = find(i->tag, pos);
+ if (pos != -1 && keyParamEqual(*i, data_[pos])) {
+ data_.erase(data_.begin() + pos);
+ break;
+ }
+ } while (pos != -1);
+ ++i;
+ }
+}
+
+KeyParameter& AuthorizationSet::operator[](int at) {
+ return data_[at];
+}
+
+const KeyParameter& AuthorizationSet::operator[](int at) const {
+ return data_[at];
+}
+
+void AuthorizationSet::Clear() {
+ data_.clear();
+}
+
+size_t AuthorizationSet::GetTagCount(Tag tag) const {
+ size_t count = 0;
+ for (int pos = -1; (pos = find(tag, pos)) != -1;) ++count;
+ return count;
+}
+
+int AuthorizationSet::find(Tag tag, int begin) const {
+ auto iter = data_.begin() + (1 + begin);
+
+ while (iter != data_.end() && iter->tag != tag) ++iter;
+
+ if (iter != data_.end()) return iter - data_.begin();
+ return -1;
+}
+
+bool AuthorizationSet::erase(int index) {
+ auto pos = data_.begin() + index;
+ if (pos != data_.end()) {
+ data_.erase(pos);
+ return true;
+ }
+ return false;
+}
+
+NullOr<const KeyParameter&> AuthorizationSet::GetEntry(Tag tag) const {
+ int pos = find(tag);
+ if (pos == -1) return {};
+ return data_[pos];
+}
+
+/**
+ * Persistent format is:
+ * | 32 bit indirect_size |
+ * --------------------------------
+ * | indirect_size bytes of data | this is where the blob data is stored
+ * --------------------------------
+ * | 32 bit element_count | number of entries
+ * | 32 bit elements_size | total bytes used by entries (entries have variable length)
+ * --------------------------------
+ * | elementes_size bytes of data | where the elements are stored
+ */
+
+/**
+ * Persistent format of blobs and bignums:
+ * | 32 bit tag |
+ * | 32 bit blob_length |
+ * | 32 bit indirect_offset |
+ */
+
+struct OutStreams {
+ std::ostream& indirect;
+ std::ostream& elements;
+};
+
+OutStreams& serializeParamValue(OutStreams& out, const hidl_vec<uint8_t>& blob) {
+ uint32_t buffer;
+
+ // write blob_length
+ auto blob_length = blob.size();
+ if (blob_length > std::numeric_limits<uint32_t>::max()) {
+ out.elements.setstate(std::ios_base::badbit);
+ return out;
+ }
+ buffer = blob_length;
+ out.elements.write(reinterpret_cast<const char*>(&buffer), sizeof(uint32_t));
+
+ // write indirect_offset
+ auto offset = out.indirect.tellp();
+ if (offset < 0 || offset > std::numeric_limits<uint32_t>::max() ||
+ uint32_t(offset) + uint32_t(blob_length) < uint32_t(offset)) { // overflow check
+ out.elements.setstate(std::ios_base::badbit);
+ return out;
+ }
+ buffer = offset;
+ out.elements.write(reinterpret_cast<const char*>(&buffer), sizeof(uint32_t));
+
+ // write blob to indirect stream
+ if (blob_length) out.indirect.write(reinterpret_cast<const char*>(&blob[0]), blob_length);
+
+ return out;
+}
+
+template <typename T>
+OutStreams& serializeParamValue(OutStreams& out, const T& value) {
+ out.elements.write(reinterpret_cast<const char*>(&value), sizeof(T));
+ return out;
+}
+
+OutStreams& serialize(TAG_INVALID_t&&, OutStreams& out, const KeyParameter&) {
+ // skip invalid entries.
+ return out;
+}
+template <typename T>
+OutStreams& serialize(T ttag, OutStreams& out, const KeyParameter& param) {
+ out.elements.write(reinterpret_cast<const char*>(¶m.tag), sizeof(int32_t));
+ return serializeParamValue(out, accessTagValue(ttag, param));
+}
+
+template <typename... T>
+struct choose_serializer;
+template <typename... Tags>
+struct choose_serializer<MetaList<Tags...>> {
+ static OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
+ return choose_serializer<Tags...>::serialize(out, param);
+ }
+};
+
+template <>
+struct choose_serializer<> {
+ static OutStreams& serialize(OutStreams& out, const KeyParameter&) { return out; }
+};
+
+template <TagType tag_type, Tag tag, typename... Tail>
+struct choose_serializer<TypedTag<tag_type, tag>, Tail...> {
+ static OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
+ if (param.tag == tag) {
+ return V4_0::serialize(TypedTag<tag_type, tag>(), out, param);
+ } else {
+ return choose_serializer<Tail...>::serialize(out, param);
+ }
+ }
+};
+
+OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
+ return choose_serializer<all_tags_t>::serialize(out, param);
+}
+
+std::ostream& serialize(std::ostream& out, const std::vector<KeyParameter>& params) {
+ std::stringstream indirect;
+ std::stringstream elements;
+ OutStreams streams = {indirect, elements};
+ for (const auto& param : params) {
+ serialize(streams, param);
+ }
+ if (indirect.bad() || elements.bad()) {
+ out.setstate(std::ios_base::badbit);
+ return out;
+ }
+ auto pos = indirect.tellp();
+ if (pos < 0 || pos > std::numeric_limits<uint32_t>::max()) {
+ out.setstate(std::ios_base::badbit);
+ return out;
+ }
+ uint32_t indirect_size = pos;
+ pos = elements.tellp();
+ if (pos < 0 || pos > std::numeric_limits<uint32_t>::max()) {
+ out.setstate(std::ios_base::badbit);
+ return out;
+ }
+ uint32_t elements_size = pos;
+ uint32_t element_count = params.size();
+
+ out.write(reinterpret_cast<const char*>(&indirect_size), sizeof(uint32_t));
+
+ pos = out.tellp();
+ if (indirect_size) out << indirect.rdbuf();
+ assert(out.tellp() - pos == indirect_size);
+
+ out.write(reinterpret_cast<const char*>(&element_count), sizeof(uint32_t));
+ out.write(reinterpret_cast<const char*>(&elements_size), sizeof(uint32_t));
+
+ pos = out.tellp();
+ if (elements_size) out << elements.rdbuf();
+ assert(out.tellp() - pos == elements_size);
+
+ return out;
+}
+
+struct InStreams {
+ std::istream& indirect;
+ std::istream& elements;
+};
+
+InStreams& deserializeParamValue(InStreams& in, hidl_vec<uint8_t>* blob) {
+ uint32_t blob_length = 0;
+ uint32_t offset = 0;
+ in.elements.read(reinterpret_cast<char*>(&blob_length), sizeof(uint32_t));
+ blob->resize(blob_length);
+ in.elements.read(reinterpret_cast<char*>(&offset), sizeof(uint32_t));
+ in.indirect.seekg(offset);
+ in.indirect.read(reinterpret_cast<char*>(&(*blob)[0]), blob->size());
+ return in;
+}
+
+template <typename T>
+InStreams& deserializeParamValue(InStreams& in, T* value) {
+ in.elements.read(reinterpret_cast<char*>(value), sizeof(T));
+ return in;
+}
+
+InStreams& deserialize(TAG_INVALID_t&&, InStreams& in, KeyParameter*) {
+ // there should be no invalid KeyParamaters but if handle them as zero sized.
+ return in;
+}
+
+template <typename T>
+InStreams& deserialize(T&& ttag, InStreams& in, KeyParameter* param) {
+ return deserializeParamValue(in, &accessTagValue(ttag, *param));
+}
+
+template <typename... T>
+struct choose_deserializer;
+template <typename... Tags>
+struct choose_deserializer<MetaList<Tags...>> {
+ static InStreams& deserialize(InStreams& in, KeyParameter* param) {
+ return choose_deserializer<Tags...>::deserialize(in, param);
+ }
+};
+template <>
+struct choose_deserializer<> {
+ static InStreams& deserialize(InStreams& in, KeyParameter*) {
+ // encountered an unknown tag -> fail parsing
+ in.elements.setstate(std::ios_base::badbit);
+ return in;
+ }
+};
+template <TagType tag_type, Tag tag, typename... Tail>
+struct choose_deserializer<TypedTag<tag_type, tag>, Tail...> {
+ static InStreams& deserialize(InStreams& in, KeyParameter* param) {
+ if (param->tag == tag) {
+ return V4_0::deserialize(TypedTag<tag_type, tag>(), in, param);
+ } else {
+ return choose_deserializer<Tail...>::deserialize(in, param);
+ }
+ }
+};
+
+InStreams& deserialize(InStreams& in, KeyParameter* param) {
+ in.elements.read(reinterpret_cast<char*>(¶m->tag), sizeof(Tag));
+ return choose_deserializer<all_tags_t>::deserialize(in, param);
+}
+
+std::istream& deserialize(std::istream& in, std::vector<KeyParameter>* params) {
+ uint32_t indirect_size = 0;
+ in.read(reinterpret_cast<char*>(&indirect_size), sizeof(uint32_t));
+ std::string indirect_buffer(indirect_size, '\0');
+ if (indirect_buffer.size() != indirect_size) {
+ in.setstate(std::ios_base::badbit);
+ return in;
+ }
+ in.read(&indirect_buffer[0], indirect_buffer.size());
+
+ uint32_t element_count = 0;
+ in.read(reinterpret_cast<char*>(&element_count), sizeof(uint32_t));
+ uint32_t elements_size = 0;
+ in.read(reinterpret_cast<char*>(&elements_size), sizeof(uint32_t));
+
+ std::string elements_buffer(elements_size, '\0');
+ if (elements_buffer.size() != elements_size) {
+ in.setstate(std::ios_base::badbit);
+ return in;
+ }
+ in.read(&elements_buffer[0], elements_buffer.size());
+
+ if (in.bad()) return in;
+
+ // TODO write one-shot stream buffer to avoid copying here
+ std::stringstream indirect(indirect_buffer);
+ std::stringstream elements(elements_buffer);
+ InStreams streams = {indirect, elements};
+
+ params->resize(element_count);
+
+ for (uint32_t i = 0; i < element_count; ++i) {
+ deserialize(streams, &(*params)[i]);
+ }
+ return in;
+}
+
+void AuthorizationSet::Serialize(std::ostream* out) const {
+ serialize(*out, data_);
+}
+
+void AuthorizationSet::Deserialize(std::istream* in) {
+ deserialize(*in, &data_);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::RsaKey(uint32_t key_size,
+ uint64_t public_exponent) {
+ Authorization(TAG_ALGORITHM, Algorithm::RSA);
+ Authorization(TAG_KEY_SIZE, key_size);
+ Authorization(TAG_RSA_PUBLIC_EXPONENT, public_exponent);
+ return *this;
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaKey(uint32_t key_size) {
+ Authorization(TAG_ALGORITHM, Algorithm::EC);
+ Authorization(TAG_KEY_SIZE, key_size);
+ return *this;
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaKey(EcCurve curve) {
+ Authorization(TAG_ALGORITHM, Algorithm::EC);
+ Authorization(TAG_EC_CURVE, curve);
+ return *this;
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::AesKey(uint32_t key_size) {
+ Authorization(TAG_ALGORITHM, Algorithm::AES);
+ return Authorization(TAG_KEY_SIZE, key_size);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::HmacKey(uint32_t key_size) {
+ Authorization(TAG_ALGORITHM, Algorithm::HMAC);
+ Authorization(TAG_KEY_SIZE, key_size);
+ return SigningKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::RsaSigningKey(uint32_t key_size,
+ uint64_t public_exponent) {
+ RsaKey(key_size, public_exponent);
+ return SigningKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::RsaEncryptionKey(uint32_t key_size,
+ uint64_t public_exponent) {
+ RsaKey(key_size, public_exponent);
+ return EncryptionKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaSigningKey(uint32_t key_size) {
+ EcdsaKey(key_size);
+ return SigningKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaSigningKey(EcCurve curve) {
+ EcdsaKey(curve);
+ return SigningKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::AesEncryptionKey(uint32_t key_size) {
+ AesKey(key_size);
+ return EncryptionKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::SigningKey() {
+ Authorization(TAG_PURPOSE, KeyPurpose::SIGN);
+ return Authorization(TAG_PURPOSE, KeyPurpose::VERIFY);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::EncryptionKey() {
+ Authorization(TAG_PURPOSE, KeyPurpose::ENCRYPT);
+ return Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::NoDigestOrPadding() {
+ Authorization(TAG_DIGEST, Digest::NONE);
+ return Authorization(TAG_PADDING, PaddingMode::NONE);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::EcbMode() {
+ return Authorization(TAG_BLOCK_MODE, BlockMode::ECB);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::BlockMode(
+ std::initializer_list<V4_0::BlockMode> blockModes) {
+ for (auto mode : blockModes) {
+ push_back(TAG_BLOCK_MODE, mode);
+ }
+ return *this;
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::Digest(
+ std::initializer_list<V4_0::Digest> digests) {
+ for (auto digest : digests) {
+ push_back(TAG_DIGEST, digest);
+ }
+ return *this;
+}
+
+} // namespace V4_0
+} // namespace keymaster
+} // namespace hardware
+} // namespace android
diff --git a/keymaster/4.0/support/include/keymasterV4_0/attestation_record.h b/keymaster/4.0/support/include/keymasterV4_0/attestation_record.h
new file mode 100644
index 0000000..c993d6b
--- /dev/null
+++ b/keymaster/4.0/support/include/keymasterV4_0/attestation_record.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMASTER_40_VTS_FUNCTIONAL_ATTESTATION_RECORD_H_
+#define HARDWARE_INTERFACES_KEYMASTER_40_VTS_FUNCTIONAL_ATTESTATION_RECORD_H_
+
+#include <android/hardware/keymaster/4.0/IKeymaster.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+
+using V3_0::ErrorCode;
+using V3_0::SecurityLevel;
+
+class AuthorizationSet;
+
+/**
+ * The OID for Android attestation records. For the curious, it breaks down as follows:
+ *
+ * 1 = ISO
+ * 3 = org
+ * 6 = DoD (Huh? OIDs are weird.)
+ * 1 = IANA
+ * 4 = Private
+ * 1 = Enterprises
+ * 11129 = Google
+ * 2 = Google security
+ * 1 = certificate extension
+ * 17 = Android attestation extension.
+ */
+static const char kAttestionRecordOid[] = "1.3.6.1.4.1.11129.2.1.17";
+
+ErrorCode parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
+ uint32_t* attestation_version, //
+ SecurityLevel* attestation_security_level,
+ uint32_t* keymaster_version,
+ SecurityLevel* keymaster_security_level,
+ hidl_vec<uint8_t>* attestation_challenge,
+ AuthorizationSet* software_enforced,
+ AuthorizationSet* tee_enforced, //
+ hidl_vec<uint8_t>* unique_id);
+} // namespace V4_0
+} // namespace keymaster
+} // namespace hardware
+} // namespace android
+
+#endif // HARDWARE_INTERFACES_KEYMASTER_40_VTS_FUNCTIONAL_ATTESTATION_RECORD_H_
diff --git a/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h b/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h
new file mode 100644
index 0000000..f67f192
--- /dev/null
+++ b/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h
@@ -0,0 +1,300 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SYSTEM_SECURITY_KEYSTORE_KM4_AUTHORIZATION_SET_H_
+#define SYSTEM_SECURITY_KEYSTORE_KM4_AUTHORIZATION_SET_H_
+
+#include <vector>
+
+#include <keymasterV4_0/keymaster_tags.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+
+class AuthorizationSetBuilder;
+
+/**
+ * An ordered collection of KeyParameters. It provides memory ownership and some convenient
+ * functionality for sorting, deduplicating, joining, and subtracting sets of KeyParameters.
+ * For serialization, wrap the backing store of this structure in a hidl_vec<KeyParameter>.
+ */
+class AuthorizationSet {
+ public:
+ typedef KeyParameter value_type;
+
+ /**
+ * Construct an empty, dynamically-allocated, growable AuthorizationSet.
+ */
+ AuthorizationSet(){};
+
+ // Copy constructor.
+ AuthorizationSet(const AuthorizationSet& other) : data_(other.data_) {}
+
+ // Move constructor.
+ AuthorizationSet(AuthorizationSet&& other) : data_(std::move(other.data_)) {}
+
+ // Constructor from hidl_vec<KeyParameter>
+ AuthorizationSet(const hidl_vec<KeyParameter>& other) { *this = other; }
+
+ // Copy assignment.
+ AuthorizationSet& operator=(const AuthorizationSet& other) {
+ data_ = other.data_;
+ return *this;
+ }
+
+ // Move assignment.
+ AuthorizationSet& operator=(AuthorizationSet&& other) {
+ data_ = std::move(other.data_);
+ return *this;
+ }
+
+ AuthorizationSet& operator=(const hidl_vec<KeyParameter>& other) {
+ if (other.size() > 0) {
+ data_.resize(other.size());
+ for (size_t i = 0; i < data_.size(); ++i) {
+ /* This makes a deep copy even of embedded blobs.
+ * See assignment operator/copy constructor of hidl_vec.*/
+ data_[i] = other[i];
+ }
+ }
+ return *this;
+ }
+
+ /**
+ * Clear existing authorization set data
+ */
+ void Clear();
+
+ ~AuthorizationSet() = default;
+
+ /**
+ * Returns the size of the set.
+ */
+ size_t size() const { return data_.size(); }
+
+ /**
+ * Returns true if the set is empty.
+ */
+ bool empty() const { return size() == 0; }
+
+ /**
+ * Returns the data in the set, directly. Be careful with this.
+ */
+ const KeyParameter* data() const { return data_.data(); }
+
+ /**
+ * Sorts the set
+ */
+ void Sort();
+
+ /**
+ * Sorts the set and removes duplicates (inadvertently duplicating tags is easy to do with the
+ * AuthorizationSetBuilder).
+ */
+ void Deduplicate();
+
+ /**
+ * Adds all elements from \p set that are not already present in this AuthorizationSet. As a
+ * side-effect, if \p set is not null this AuthorizationSet will end up sorted.
+ */
+ void Union(const AuthorizationSet& set);
+
+ /**
+ * Removes all elements in \p set from this AuthorizationSet.
+ */
+ void Subtract(const AuthorizationSet& set);
+
+ /**
+ * Returns the offset of the next entry that matches \p tag, starting from the element after \p
+ * begin. If not found, returns -1.
+ */
+ int find(Tag tag, int begin = -1) const;
+
+ /**
+ * Removes the entry at the specified index. Returns true if successful, false if the index was
+ * out of bounds.
+ */
+ bool erase(int index);
+
+ /**
+ * Returns iterator (pointer) to beginning of elems array, to enable STL-style iteration
+ */
+ std::vector<KeyParameter>::const_iterator begin() const { return data_.begin(); }
+
+ /**
+ * Returns iterator (pointer) one past end of elems array, to enable STL-style iteration
+ */
+ std::vector<KeyParameter>::const_iterator end() const { return data_.end(); }
+
+ /**
+ * Returns the nth element of the set.
+ * Like for std::vector::operator[] there is no range check performed. Use of out of range
+ * indices is undefined.
+ */
+ KeyParameter& operator[](int n);
+
+ /**
+ * Returns the nth element of the set.
+ * Like for std::vector::operator[] there is no range check performed. Use of out of range
+ * indices is undefined.
+ */
+ const KeyParameter& operator[](int n) const;
+
+ /**
+ * Returns true if the set contains at least one instance of \p tag
+ */
+ bool Contains(Tag tag) const { return find(tag) != -1; }
+
+ template <TagType tag_type, Tag tag, typename ValueT>
+ bool Contains(TypedTag<tag_type, tag> ttag, const ValueT& value) const {
+ for (const auto& param : data_) {
+ auto entry = authorizationValue(ttag, param);
+ if (entry.isOk() && static_cast<ValueT>(entry.value()) == value) return true;
+ }
+ return false;
+ }
+ /**
+ * Returns the number of \p tag entries.
+ */
+ size_t GetTagCount(Tag tag) const;
+
+ template <typename T>
+ inline NullOr<const typename TypedTag2ValueType<T>::type&> GetTagValue(T tag) const {
+ auto entry = GetEntry(tag);
+ if (entry.isOk()) return authorizationValue(tag, entry.value());
+ return {};
+ }
+
+ void push_back(const KeyParameter& param) { data_.push_back(param); }
+ void push_back(KeyParameter&& param) { data_.push_back(std::move(param)); }
+ void push_back(const AuthorizationSet& set) {
+ for (auto& entry : set) {
+ push_back(entry);
+ }
+ }
+ void push_back(AuthorizationSet&& set) {
+ std::move(set.begin(), set.end(), std::back_inserter(*this));
+ }
+
+ /**
+ * Append the tag and enumerated value to the set.
+ * "val" may be exactly one parameter unless a boolean parameter is added.
+ * In this case "val" is omitted. This condition is checked at compile time by Authorization()
+ */
+ template <typename TypedTagT, typename... Value>
+ void push_back(TypedTagT tag, Value&&... val) {
+ push_back(Authorization(tag, std::forward<Value>(val)...));
+ }
+
+ template <typename Iterator>
+ void append(Iterator begin, Iterator end) {
+ while (begin != end) {
+ push_back(*begin);
+ ++begin;
+ }
+ }
+
+ hidl_vec<KeyParameter> hidl_data() const {
+ hidl_vec<KeyParameter> result;
+ result.setToExternal(const_cast<KeyParameter*>(data()), size());
+ return result;
+ }
+
+ void Serialize(std::ostream* out) const;
+ void Deserialize(std::istream* in);
+
+ private:
+ NullOr<const KeyParameter&> GetEntry(Tag tag) const;
+
+ std::vector<KeyParameter> data_;
+};
+
+class AuthorizationSetBuilder : public AuthorizationSet {
+ public:
+ template <typename TagType, typename... ValueType>
+ AuthorizationSetBuilder& Authorization(TagType ttag, ValueType&&... value) {
+ push_back(ttag, std::forward<ValueType>(value)...);
+ return *this;
+ }
+
+ template <Tag tag>
+ AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, const uint8_t* data,
+ size_t data_length) {
+ hidl_vec<uint8_t> new_blob;
+ new_blob.setToExternal(const_cast<uint8_t*>(data), data_length);
+ push_back(ttag, std::move(new_blob));
+ return *this;
+ }
+
+ template <Tag tag>
+ AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, const char* data,
+ size_t data_length) {
+ return Authorization(ttag, reinterpret_cast<const uint8_t*>(data), data_length);
+ }
+
+ AuthorizationSetBuilder& Authorizations(const AuthorizationSet& set) {
+ for (const auto& entry : set) {
+ push_back(entry);
+ }
+ return *this;
+ }
+
+ AuthorizationSetBuilder& RsaKey(uint32_t key_size, uint64_t public_exponent);
+ AuthorizationSetBuilder& EcdsaKey(uint32_t key_size);
+ AuthorizationSetBuilder& EcdsaKey(EcCurve curve);
+ AuthorizationSetBuilder& AesKey(uint32_t key_size);
+ AuthorizationSetBuilder& HmacKey(uint32_t key_size);
+
+ AuthorizationSetBuilder& RsaSigningKey(uint32_t key_size, uint64_t public_exponent);
+ AuthorizationSetBuilder& RsaEncryptionKey(uint32_t key_size, uint64_t public_exponent);
+ AuthorizationSetBuilder& EcdsaSigningKey(uint32_t key_size);
+ AuthorizationSetBuilder& EcdsaSigningKey(EcCurve curve);
+ AuthorizationSetBuilder& AesEncryptionKey(uint32_t key_size);
+
+ AuthorizationSetBuilder& SigningKey();
+ AuthorizationSetBuilder& EncryptionKey();
+ AuthorizationSetBuilder& NoDigestOrPadding();
+ AuthorizationSetBuilder& EcbMode();
+
+ AuthorizationSetBuilder& BlockMode(std::initializer_list<BlockMode> blockModes);
+ AuthorizationSetBuilder& Digest(std::initializer_list<Digest> digests);
+
+ template <typename... T>
+ AuthorizationSetBuilder& BlockMode(T&&... a) {
+ return BlockMode({std::forward<T>(a)...});
+ }
+ template <typename... T>
+ AuthorizationSetBuilder& Digest(T&&... a) {
+ return Digest({std::forward<T>(a)...});
+ }
+ template <typename... T>
+ AuthorizationSetBuilder& Padding(T&&... a) {
+ return Padding({std::forward<T>(a)...});
+ }
+
+ AuthorizationSetBuilder& Padding(PaddingMode padding) {
+ return Authorization(TAG_PADDING, padding);
+ }
+};
+
+} // namespace V4_0
+} // namespace keymaster
+} // namespace hardware
+} // namespace android
+
+#endif // SYSTEM_SECURITY_KEYSTORE_KM4_AUTHORIZATION_SET_H_
diff --git a/keymaster/4.0/support/include/keymasterV4_0/key_param_output.h b/keymaster/4.0/support/include/keymasterV4_0/key_param_output.h
new file mode 100644
index 0000000..04ba3a4
--- /dev/null
+++ b/keymaster/4.0/support/include/keymasterV4_0/key_param_output.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+
+#include <android/hardware/keymaster/4.0/types.h>
+
+#include "keymaster_tags.h"
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+
+namespace V3_0 {
+
+inline ::std::ostream& operator<<(::std::ostream& os, Algorithm value) {
+ return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, BlockMode value) {
+ return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, Digest value) {
+ return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, EcCurve value) {
+ return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, ErrorCode value) {
+ return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, PaddingMode value) {
+ return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, KeyOrigin value) {
+ return os << toString(value);
+}
+
+} // namespace V3_0
+
+namespace V4_0 {
+
+template <typename ValueT>
+::std::ostream& operator<<(::std::ostream& os, const NullOr<ValueT>& value) {
+ if (!value.isOk()) {
+ os << "(value not present)";
+ } else {
+ os << value.value();
+ }
+ return os;
+}
+
+::std::ostream& operator<<(::std::ostream& os, const hidl_vec<KeyParameter>& set);
+::std::ostream& operator<<(::std::ostream& os, const KeyParameter& value);
+
+inline ::std::ostream& operator<<(::std::ostream& os, const KeyCharacteristics& value) {
+ return os << "SW: " << value.softwareEnforced << ::std::endl
+ << "HW: " << value.hardwareEnforced << ::std::endl;
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, KeyPurpose value) {
+ return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, Tag tag) {
+ return os << toString(tag);
+}
+
+} // namespace V4_0
+} // namespace keymaster
+} // namespace hardware
+} // namespace android
diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
new file mode 100644
index 0000000..7e3b008
--- /dev/null
+++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
@@ -0,0 +1,346 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SYSTEM_SECURITY_KEYSTORE_KEYMASTER_TAGS_H_
+#define SYSTEM_SECURITY_KEYSTORE_KEYMASTER_TAGS_H_
+
+/**
+ * This header contains various definitions that make working with keymaster tags safer and easier.
+ *
+ * It makes use of a fair amount of template metaprogramming. The metaprogramming serves the purpose
+ * of making it impossible to make certain classes of mistakes when operating on keymaster
+ * authorizations. For example, it's an error to create a KeyParameter with tag == Tag::PURPOSE
+ * and then to assign Algorithm::RSA to algorithm element of its union. But because the user
+ * must choose the union field, there could be a mismatch which the compiler has now way to
+ * diagnose.
+ *
+ * The machinery in this header solves these problems by describing which union field corresponds
+ * to which Tag. Central to this mechanism is the template TypedTag. It has zero size and binds a
+ * numeric Tag to a type that the compiler understands. By means of the macro DECLARE_TYPED_TAG,
+ * we declare types for each of the tags defined in hardware/interfaces/keymaster/4.0/types.hal.
+ *
+ * The macro DECLARE_TYPED_TAG(name) generates a typename TAG_name_t and a zero sized instance
+ * TAG_name. Once these typed tags have been declared we define metafunctions mapping the each tag
+ * to its value c++ type and the correct union element of KeyParameter. This is done by means of
+ * the macros MAKE_TAG_*VALUE_ACCESSOR, which generates TypedTag2ValueType, a metafunction mapping
+ * a typed tag to the corresponding c++ type, and access function, accessTagValue returning a
+ * reference to the correct element of KeyParameter.
+ * E.g.:
+ * given "KeyParameter param;" then "accessTagValue(TAG_PURPOSE, param)"
+ * yields a reference to param.f.purpose
+ * If used in an assignment the compiler can now check the compatibility of the assigned value.
+ *
+ * For convenience we also provide the constructor like function Authorization().
+ * Authorization takes a typed tag and a value and checks at compile time whether the value given
+ * is suitable for the given tag. At runtime it creates a new KeyParameter initialized with the
+ * given tag and value and returns it by value.
+ *
+ * The second convenience function, authorizationValue, allows access to the KeyParameter value in
+ * a safe way. It takes a typed tag and a KeyParameter and returns a reference to the value wrapped
+ * by NullOr. NullOr has out-of-band information about whether it is save to access the wrapped
+ * reference.
+ * E.g.:
+ * auto param = Authorization(TAG_ALGORITM, Algorithm::RSA);
+ * auto value1 = authorizationValue(TAG_PURPOSE, param);
+ * auto value2 = authorizationValue(TAG_ALGORITM, param);
+ * value1.isOk() yields false, but value2.isOk() yields true, thus value2.value() is save to access.
+ */
+
+#include <android/hardware/keymaster/4.0/IKeymaster.h>
+
+#include <type_traits>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+
+using ::android::hardware::keymaster::V3_0::Algorithm;
+using ::android::hardware::keymaster::V3_0::BlockMode;
+using ::android::hardware::keymaster::V3_0::Digest;
+using ::android::hardware::keymaster::V3_0::EcCurve;
+using ::android::hardware::keymaster::V3_0::KeyFormat;
+using ::android::hardware::keymaster::V3_0::KeyOrigin;
+using ::android::hardware::keymaster::V3_0::PaddingMode;
+using ::android::hardware::keymaster::V3_0::TagType;
+
+// The following create the numeric values that KM_TAG_PADDING and KM_TAG_DIGEST used to have. We
+// need these old values to be able to support old keys that use them.
+static const int32_t KM_TAG_DIGEST_OLD = static_cast<int32_t>(TagType::ENUM) | 5;
+static const int32_t KM_TAG_PADDING_OLD = static_cast<int32_t>(TagType::ENUM) | 7;
+
+constexpr TagType typeFromTag(Tag tag) {
+ return static_cast<TagType>(static_cast<uint32_t>(tag) & static_cast<uint32_t>(0xf0000000));
+}
+
+/**
+ * TypedTag is a templatized version of Tag, which provides compile-time checking of
+ * keymaster tag types. Instances are convertible to Tag, so they can be used wherever
+ * Tag is expected, and because they encode the tag type it's possible to create
+ * function overloads that only operate on tags with a particular type.
+ */
+template <TagType tag_type, Tag tag>
+struct TypedTag {
+ inline TypedTag() {
+ // Ensure that it's impossible to create a TypedTag instance whose 'tag' doesn't have type
+ // 'tag_type'. Attempting to instantiate a tag with the wrong type will result in a compile
+ // error (no match for template specialization StaticAssert<false>), with no run-time cost.
+ static_assert(typeFromTag(tag) == tag_type, "mismatch between tag and tag_type");
+ }
+ operator Tag() const { return tag; }
+ int32_t maskedTag() { return tag & 0x0FFFFFFF; }
+};
+
+template <Tag tag>
+struct Tag2TypedTag {
+ typedef TypedTag<typeFromTag(tag), tag> type;
+};
+
+#define DECLARE_TYPED_TAG(name) \
+ typedef typename Tag2TypedTag<Tag::name>::type TAG_##name##_t; \
+ static TAG_##name##_t TAG_##name;
+
+DECLARE_TYPED_TAG(INVALID);
+DECLARE_TYPED_TAG(KEY_SIZE);
+DECLARE_TYPED_TAG(MAC_LENGTH);
+DECLARE_TYPED_TAG(CALLER_NONCE);
+DECLARE_TYPED_TAG(MIN_MAC_LENGTH);
+DECLARE_TYPED_TAG(RSA_PUBLIC_EXPONENT);
+DECLARE_TYPED_TAG(INCLUDE_UNIQUE_ID);
+DECLARE_TYPED_TAG(ACTIVE_DATETIME);
+DECLARE_TYPED_TAG(ORIGINATION_EXPIRE_DATETIME);
+DECLARE_TYPED_TAG(USAGE_EXPIRE_DATETIME);
+DECLARE_TYPED_TAG(MIN_SECONDS_BETWEEN_OPS);
+DECLARE_TYPED_TAG(MAX_USES_PER_BOOT);
+DECLARE_TYPED_TAG(USER_SECURE_ID);
+DECLARE_TYPED_TAG(NO_AUTH_REQUIRED);
+DECLARE_TYPED_TAG(AUTH_TIMEOUT);
+DECLARE_TYPED_TAG(ALLOW_WHILE_ON_BODY);
+DECLARE_TYPED_TAG(APPLICATION_ID);
+DECLARE_TYPED_TAG(APPLICATION_DATA);
+DECLARE_TYPED_TAG(CREATION_DATETIME);
+DECLARE_TYPED_TAG(ROLLBACK_RESISTANCE);
+DECLARE_TYPED_TAG(ROOT_OF_TRUST);
+DECLARE_TYPED_TAG(ASSOCIATED_DATA);
+DECLARE_TYPED_TAG(NONCE);
+DECLARE_TYPED_TAG(BOOTLOADER_ONLY);
+DECLARE_TYPED_TAG(OS_VERSION);
+DECLARE_TYPED_TAG(OS_PATCHLEVEL);
+DECLARE_TYPED_TAG(UNIQUE_ID);
+DECLARE_TYPED_TAG(ATTESTATION_CHALLENGE);
+DECLARE_TYPED_TAG(ATTESTATION_APPLICATION_ID);
+DECLARE_TYPED_TAG(RESET_SINCE_ID_ROTATION);
+
+DECLARE_TYPED_TAG(PURPOSE);
+DECLARE_TYPED_TAG(ALGORITHM);
+DECLARE_TYPED_TAG(BLOCK_MODE);
+DECLARE_TYPED_TAG(DIGEST);
+DECLARE_TYPED_TAG(PADDING);
+DECLARE_TYPED_TAG(BLOB_USAGE_REQUIREMENTS);
+DECLARE_TYPED_TAG(ORIGIN);
+DECLARE_TYPED_TAG(USER_AUTH_TYPE);
+DECLARE_TYPED_TAG(EC_CURVE);
+
+template <typename... Elems>
+struct MetaList {};
+
+using all_tags_t = MetaList<
+ TAG_INVALID_t, TAG_KEY_SIZE_t, TAG_MAC_LENGTH_t, TAG_CALLER_NONCE_t, TAG_MIN_MAC_LENGTH_t,
+ TAG_RSA_PUBLIC_EXPONENT_t, TAG_INCLUDE_UNIQUE_ID_t, TAG_ACTIVE_DATETIME_t,
+ TAG_ORIGINATION_EXPIRE_DATETIME_t, TAG_USAGE_EXPIRE_DATETIME_t, TAG_MIN_SECONDS_BETWEEN_OPS_t,
+ TAG_MAX_USES_PER_BOOT_t, TAG_USER_SECURE_ID_t, TAG_NO_AUTH_REQUIRED_t, TAG_AUTH_TIMEOUT_t,
+ TAG_ALLOW_WHILE_ON_BODY_t, TAG_APPLICATION_ID_t, TAG_APPLICATION_DATA_t,
+ TAG_CREATION_DATETIME_t, TAG_ROLLBACK_RESISTANCE_t, TAG_ROOT_OF_TRUST_t, TAG_ASSOCIATED_DATA_t,
+ TAG_NONCE_t, TAG_BOOTLOADER_ONLY_t, TAG_OS_VERSION_t, TAG_OS_PATCHLEVEL_t, TAG_UNIQUE_ID_t,
+ TAG_ATTESTATION_CHALLENGE_t, TAG_ATTESTATION_APPLICATION_ID_t, TAG_RESET_SINCE_ID_ROTATION_t,
+ TAG_PURPOSE_t, TAG_ALGORITHM_t, TAG_BLOCK_MODE_t, TAG_DIGEST_t, TAG_PADDING_t,
+ TAG_BLOB_USAGE_REQUIREMENTS_t, TAG_ORIGIN_t, TAG_USER_AUTH_TYPE_t, TAG_EC_CURVE_t>;
+
+template <typename TypedTagType>
+struct TypedTag2ValueType;
+
+#define MAKE_TAG_VALUE_ACCESSOR(tag_type, field_name) \
+ template <Tag tag> \
+ struct TypedTag2ValueType<TypedTag<tag_type, tag>> { \
+ typedef decltype(static_cast<KeyParameter*>(nullptr)->field_name) type; \
+ }; \
+ template <Tag tag> \
+ inline auto accessTagValue(TypedTag<tag_type, tag>, const KeyParameter& param) \
+ ->const decltype(param.field_name)& { \
+ return param.field_name; \
+ } \
+ template <Tag tag> \
+ inline auto accessTagValue(TypedTag<tag_type, tag>, KeyParameter& param) \
+ ->decltype(param.field_name)& { \
+ return param.field_name; \
+ }
+
+MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG, f.longInteger)
+MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG_REP, f.longInteger)
+MAKE_TAG_VALUE_ACCESSOR(TagType::DATE, f.dateTime)
+MAKE_TAG_VALUE_ACCESSOR(TagType::UINT, f.integer)
+MAKE_TAG_VALUE_ACCESSOR(TagType::UINT_REP, f.integer)
+MAKE_TAG_VALUE_ACCESSOR(TagType::BOOL, f.boolValue)
+MAKE_TAG_VALUE_ACCESSOR(TagType::BYTES, blob)
+MAKE_TAG_VALUE_ACCESSOR(TagType::BIGNUM, blob)
+
+#define MAKE_TAG_ENUM_VALUE_ACCESSOR(typed_tag, field_name) \
+ template <> \
+ struct TypedTag2ValueType<decltype(typed_tag)> { \
+ typedef decltype(static_cast<KeyParameter*>(nullptr)->field_name) type; \
+ }; \
+ inline auto accessTagValue(decltype(typed_tag), const KeyParameter& param) \
+ ->const decltype(param.field_name)& { \
+ return param.field_name; \
+ } \
+ inline auto accessTagValue(decltype(typed_tag), KeyParameter& param) \
+ ->decltype(param.field_name)& { \
+ return param.field_name; \
+ }
+
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ALGORITHM, f.algorithm)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_BLOB_USAGE_REQUIREMENTS, f.keyBlobUsageRequirements)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_BLOCK_MODE, f.blockMode)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_DIGEST, f.digest)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_EC_CURVE, f.ecCurve)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ORIGIN, f.origin)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PADDING, f.paddingMode)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PURPOSE, f.purpose)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_USER_AUTH_TYPE, f.hardwareAuthenticatorType)
+
+template <TagType tag_type, Tag tag, typename ValueT>
+inline KeyParameter makeKeyParameter(TypedTag<tag_type, tag> ttag, ValueT&& value) {
+ KeyParameter param;
+ param.tag = tag;
+ param.f.longInteger = 0;
+ accessTagValue(ttag, param) = std::forward<ValueT>(value);
+ return param;
+}
+
+// the boolean case
+template <Tag tag>
+inline KeyParameter makeKeyParameter(TypedTag<TagType::BOOL, tag>) {
+ KeyParameter param;
+ param.tag = tag;
+ param.f.boolValue = true;
+ return param;
+}
+
+template <typename... Pack>
+struct FirstOrNoneHelper;
+template <typename First>
+struct FirstOrNoneHelper<First> {
+ typedef First type;
+};
+template <>
+struct FirstOrNoneHelper<> {
+ struct type {};
+};
+
+template <typename... Pack>
+using FirstOrNone = typename FirstOrNoneHelper<Pack...>::type;
+
+template <TagType tag_type, Tag tag, typename... Args>
+inline KeyParameter Authorization(TypedTag<tag_type, tag> ttag, Args&&... args) {
+ static_assert(tag_type != TagType::BOOL || (sizeof...(args) == 0),
+ "TagType::BOOL Authorizations do not take parameters. Presence is truth.");
+ static_assert(tag_type == TagType::BOOL || (sizeof...(args) == 1),
+ "Authorization other then TagType::BOOL take exactly one parameter.");
+ static_assert(
+ tag_type == TagType::BOOL ||
+ std::is_convertible<std::remove_cv_t<std::remove_reference_t<FirstOrNone<Args...>>>,
+ typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type>::value,
+ "Invalid argument type for given tag.");
+
+ return makeKeyParameter(ttag, std::forward<Args>(args)...);
+}
+
+/**
+ * This class wraps a (mostly return) value and stores whether or not the wrapped value is valid out
+ * of band. Note that if the wrapped value is a reference it is unsafe to access the value if
+ * !isOk(). If the wrapped type is a pointer or value and !isOk(), it is still safe to access the
+ * wrapped value. In this case the pointer will be NULL though, and the value will be default
+ * constructed.
+ */
+template <typename ValueT>
+class NullOr {
+ template <typename T>
+ struct reference_initializer {
+ static T&& init() { return *static_cast<std::remove_reference_t<T>*>(nullptr); }
+ };
+ template <typename T>
+ struct pointer_initializer {
+ static T init() { return nullptr; }
+ };
+ template <typename T>
+ struct value_initializer {
+ static T init() { return T(); }
+ };
+ template <typename T>
+ using initializer_t =
+ std::conditional_t<std::is_lvalue_reference<T>::value, reference_initializer<T>,
+ std::conditional_t<std::is_pointer<T>::value, pointer_initializer<T>,
+ value_initializer<T>>>;
+
+ public:
+ NullOr() : value_(initializer_t<ValueT>::init()), null_(true) {}
+ NullOr(ValueT&& value) : value_(std::forward<ValueT>(value)), null_(false) {}
+
+ bool isOk() const { return !null_; }
+
+ const ValueT& value() const & { return value_; }
+ ValueT& value() & { return value_; }
+ ValueT&& value() && { return std::move(value_); }
+
+ private:
+ ValueT value_;
+ bool null_;
+};
+
+template <typename T>
+std::remove_reference_t<T> NullOrOr(T&& v) {
+ if (v.isOk()) return v;
+ return {};
+}
+
+template <typename Head, typename... Tail>
+std::remove_reference_t<Head> NullOrOr(Head&& head, Tail&&... tail) {
+ if (head.isOk()) return head;
+ return NullOrOr(std::forward<Tail>(tail)...);
+}
+
+template <typename Default, typename Wrapped>
+std::remove_reference_t<Wrapped> defaultOr(NullOr<Wrapped>&& optional, Default&& def) {
+ static_assert(std::is_convertible<std::remove_reference_t<Default>,
+ std::remove_reference_t<Wrapped>>::value,
+ "Type of default value must match the type wrapped by NullOr");
+ if (optional.isOk()) return optional.value();
+ return def;
+}
+
+template <TagType tag_type, Tag tag>
+inline NullOr<const typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type&> authorizationValue(
+ TypedTag<tag_type, tag> ttag, const KeyParameter& param) {
+ if (tag != param.tag) return {};
+ return accessTagValue(ttag, param);
+}
+
+} // namespace V4_0
+} // namespace keymaster
+} // namespace hardware
+} // namespace android
+
+#endif // SYSTEM_SECURITY_KEYSTORE_KEYMASTER_TAGS_H_
diff --git a/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h b/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h
new file mode 100644
index 0000000..2d3bcf1
--- /dev/null
+++ b/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+template <typename T, void (*F)(T*)>
+struct UniquePtrDeleter {
+ void operator()(T* p) const { F(p); }
+};
+
+typedef UniquePtrDeleter<EVP_PKEY, EVP_PKEY_free> EVP_PKEY_Delete;
+
+#define MAKE_OPENSSL_PTR_TYPE(type) \
+ typedef std::unique_ptr<type, UniquePtrDeleter<type, type##_free>> type##_Ptr;
+
+MAKE_OPENSSL_PTR_TYPE(ASN1_OBJECT)
+MAKE_OPENSSL_PTR_TYPE(EVP_PKEY)
+MAKE_OPENSSL_PTR_TYPE(RSA)
+MAKE_OPENSSL_PTR_TYPE(X509)
+MAKE_OPENSSL_PTR_TYPE(BN_CTX)
+
+typedef std::unique_ptr<BIGNUM, UniquePtrDeleter<BIGNUM, BN_free>> BIGNUM_Ptr;
+
+inline const EVP_MD* openssl_digest(android::hardware::keymaster::V4_0::Digest digest) {
+ switch (digest) {
+ case android::hardware::keymaster::V4_0::Digest::NONE:
+ return nullptr;
+ case android::hardware::keymaster::V4_0::Digest::MD5:
+ return EVP_md5();
+ case android::hardware::keymaster::V4_0::Digest::SHA1:
+ return EVP_sha1();
+ case android::hardware::keymaster::V4_0::Digest::SHA_2_224:
+ return EVP_sha224();
+ case android::hardware::keymaster::V4_0::Digest::SHA_2_256:
+ return EVP_sha256();
+ case android::hardware::keymaster::V4_0::Digest::SHA_2_384:
+ return EVP_sha384();
+ case android::hardware::keymaster::V4_0::Digest::SHA_2_512:
+ return EVP_sha512();
+ }
+ return nullptr;
+}
diff --git a/keymaster/4.0/support/key_param_output.cpp b/keymaster/4.0/support/key_param_output.cpp
new file mode 100644
index 0000000..e90e2fe
--- /dev/null
+++ b/keymaster/4.0/support/key_param_output.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <keymasterV4_0/key_param_output.h>
+
+#include <keymasterV4_0/keymaster_tags.h>
+
+#include <iomanip>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+
+using ::std::ostream;
+using ::std::endl;
+
+namespace V4_0 {
+
+ostream& operator<<(ostream& os, const hidl_vec<KeyParameter>& set) {
+ if (set.size() == 0) {
+ os << "(Empty)" << endl;
+ } else {
+ os << "\n";
+ for (const auto& elem : set) os << elem << endl;
+ }
+ return os;
+}
+
+ostream& operator<<(ostream& os, const KeyParameter& param) {
+ os << param.tag << ": ";
+ switch (typeFromTag(param.tag)) {
+ case TagType::INVALID:
+ return os << " Invalid";
+ case TagType::UINT_REP:
+ case TagType::UINT:
+ return os << param.f.integer;
+ case TagType::ENUM_REP:
+ case TagType::ENUM:
+ switch (param.tag) {
+ case Tag::ALGORITHM:
+ return os << param.f.algorithm;
+ case Tag::BLOCK_MODE:
+ return os << param.f.blockMode;
+ case Tag::PADDING:
+ return os << param.f.paddingMode;
+ case Tag::DIGEST:
+ return os << param.f.digest;
+ case Tag::EC_CURVE:
+ return os << (int)param.f.ecCurve;
+ case Tag::ORIGIN:
+ return os << param.f.origin;
+ case Tag::BLOB_USAGE_REQUIREMENTS:
+ return os << (int)param.f.keyBlobUsageRequirements;
+ case Tag::PURPOSE:
+ return os << param.f.purpose;
+ default:
+ return os << " UNKNOWN ENUM " << param.f.integer;
+ }
+ case TagType::ULONG_REP:
+ case TagType::ULONG:
+ return os << param.f.longInteger;
+ case TagType::DATE:
+ return os << param.f.dateTime;
+ case TagType::BOOL:
+ return os << "true";
+ case TagType::BIGNUM:
+ os << " Bignum: ";
+ for (size_t i = 0; i < param.blob.size(); ++i) {
+ os << std::hex << ::std::setw(2) << static_cast<int>(param.blob[i]) << ::std::dec;
+ }
+ return os;
+ case TagType::BYTES:
+ os << " Bytes: ";
+ for (size_t i = 0; i < param.blob.size(); ++i) {
+ os << ::std::hex << ::std::setw(2) << static_cast<int>(param.blob[i]) << ::std::dec;
+ }
+ return os;
+ }
+ return os << "UNKNOWN TAG TYPE!";
+}
+
+} // namespace V4_0
+} // namespace keymaster
+} // namespace hardware
+} // namespace android
diff --git a/keymaster/4.0/types.hal b/keymaster/4.0/types.hal
new file mode 100644
index 0000000..b82848b
--- /dev/null
+++ b/keymaster/4.0/types.hal
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.keymaster@4.0;
+
+import android.hardware.keymaster@3.0::Algorithm;
+import android.hardware.keymaster@3.0::BlockMode;
+import android.hardware.keymaster@3.0::Digest;
+import android.hardware.keymaster@3.0::EcCurve;
+import android.hardware.keymaster@3.0::ErrorCode;
+import android.hardware.keymaster@3.0::HardwareAuthenticatorType;
+import android.hardware.keymaster@3.0::KeyBlobUsageRequirements;
+import android.hardware.keymaster@3.0::KeyDerivationFunction;
+import android.hardware.keymaster@3.0::KeyFormat;
+import android.hardware.keymaster@3.0::KeyOrigin;
+import android.hardware.keymaster@3.0::PaddingMode;
+import android.hardware.keymaster@3.0::TagType;
+
+enum Tag : uint32_t {
+ INVALID = TagType:INVALID | 0,
+
+ /**
+ * Tags that must be semantically enforced by hardware and software implementations.
+ */
+
+ /** Crypto parameters */
+ PURPOSE = TagType:ENUM_REP | 1, /* KeyPurpose. */
+ ALGORITHM = TagType:ENUM | 2, /* Algorithm. */
+ KEY_SIZE = TagType:UINT | 3, /* Key size in bits. */
+ BLOCK_MODE = TagType:ENUM_REP | 4, /* BlockMode. */
+ DIGEST = TagType:ENUM_REP | 5, /* Digest. */
+ PADDING = TagType:ENUM_REP | 6, /* PaddingMode. */
+ CALLER_NONCE = TagType:BOOL | 7, /* Allow caller to specify nonce or IV. */
+ MIN_MAC_LENGTH = TagType:UINT | 8, /* Minimum length of MAC or AEAD authentication tag in
+ * bits. */
+ // 9 reserved
+ EC_CURVE = TagType:ENUM | 10, /* EcCurve. */
+
+ /** Algorithm-specific. */
+ RSA_PUBLIC_EXPONENT = TagType:ULONG | 200,
+ // 201 reserved for ECIES
+ INCLUDE_UNIQUE_ID = TagType:BOOL | 202, /* If true, attestation certificates for this key must
+ * contain an application-scoped and time-bounded
+ * device-unique ID.*/
+
+ /** Other hardware-enforced. */
+ BLOB_USAGE_REQUIREMENTS = TagType:ENUM | 301, /* KeyBlobUsageRequirements. */
+ BOOTLOADER_ONLY = TagType:BOOL | 302, /* Usable only by bootloader. */
+ ROLLBACK_RESISTANCE = TagType:BOOL | 303, /* Whether key is rollback-resistant. Specified
+ * in the key description provided to generateKey
+ * or importKey if rollback resistance is desired.
+ * If the implementation cannot provide rollback
+ * resistance, it must return
+ * ROLLBACK_RESISTANCE_UNAVAILABLE. */
+
+ /**
+ * Tags that should be semantically enforced by hardware if possible and will otherwise be
+ * enforced by software (keystore).
+ */
+
+ /** Key validity period */
+ ACTIVE_DATETIME = TagType:DATE | 400, /* Start of validity. */
+ ORIGINATION_EXPIRE_DATETIME = TagType:DATE | 401, /* Date when new "messages" should no longer
+ * be created. */
+ USAGE_EXPIRE_DATETIME = TagType:DATE | 402, /* Date when existing "messages" should no
+ * longer be trusted. */
+ MIN_SECONDS_BETWEEN_OPS = TagType:UINT | 403, /* Minimum elapsed time between
+ * cryptographic operations with the key. */
+ MAX_USES_PER_BOOT = TagType:UINT | 404, /* Number of times the key can be used per
+ * boot. */
+
+ /** User authentication */
+ // 500-501 reserved
+ USER_SECURE_ID = TagType:ULONG_REP | 502, /* Secure ID of authorized user or authenticator(s).
+ * Disallowed if ALL_USERS or NO_AUTH_REQUIRED is
+ * present. */
+ NO_AUTH_REQUIRED = TagType:BOOL | 503, /* If key is usable without authentication. */
+ USER_AUTH_TYPE = TagType:ENUM | 504, /* Bitmask of authenticator types allowed when
+ * USER_SECURE_ID contains a secure user ID, rather
+ * than a secure authenticator ID. Defined in
+ * HardwareAuthenticatorType. */
+ AUTH_TIMEOUT = TagType:UINT | 505, /* Required freshness of user authentication for
+ * private/secret key operations, in seconds. Public
+ * key operations require no authentication. If
+ * absent, authentication is required for every use.
+ * Authentication state is lost when the device is
+ * powered off. */
+ ALLOW_WHILE_ON_BODY = TagType:BOOL | 506, /* Allow key to be used after authentication timeout
+ * if device is still on-body (requires secure
+ * on-body sensor. */
+
+ /** Application access control */
+ APPLICATION_ID = TagType:BYTES | 601, /* Byte string identifying the authorized application. */
+
+ /**
+ * Semantically unenforceable tags, either because they have no specific meaning or because
+ * they're informational only.
+ */
+ APPLICATION_DATA = TagType:BYTES | 700, /* Data provided by authorized application. */
+ CREATION_DATETIME = TagType:DATE | 701, /* Key creation time */
+ ORIGIN = TagType:ENUM | 702, /* keymaster_key_origin_t. */
+ // 703 is unused.
+ ROOT_OF_TRUST = TagType:BYTES | 704, /* Root of trust ID. */
+ OS_VERSION = TagType:UINT | 705, /* Version of system (keymaster2) */
+ OS_PATCHLEVEL = TagType:UINT | 706, /* Patch level of system (keymaster2) */
+ UNIQUE_ID = TagType:BYTES | 707, /* Used to provide unique ID in attestation */
+ ATTESTATION_CHALLENGE = TagType:BYTES | 708, /* Used to provide challenge in attestation */
+ ATTESTATION_APPLICATION_ID = TagType:BYTES | 709, /* Used to identify the set of possible
+ * applications of which one has initiated a
+ * key attestation */
+ ATTESTATION_ID_BRAND = TagType:BYTES | 710, /* Used to provide the device's brand name to be
+ * included in attestation */
+ ATTESTATION_ID_DEVICE = TagType:BYTES | 711, /* Used to provide the device's device name to
+ * be included in attestation */
+ ATTESTATION_ID_PRODUCT = TagType:BYTES | 712, /* Used to provide the device's product name to
+ * be included in attestation */
+ ATTESTATION_ID_SERIAL =
+ TagType:BYTES | 713, /* Used to provide the device's serial number to be
+ * included in attestation */
+ ATTESTATION_ID_IMEI = TagType:BYTES | 714, /* Used to provide the device's IMEI to be included
+ * in attestation */
+ ATTESTATION_ID_MEID = TagType:BYTES | 715, /* Used to provide the device's MEID to be included
+ * in attestation */
+ ATTESTATION_ID_MANUFACTURER =
+ TagType:BYTES | 716, /* Used to provide the device's manufacturer
+ * name to be included in attestation */
+ ATTESTATION_ID_MODEL = TagType:BYTES | 717, /* Used to provide the device's model name to be
+ * included in attestation */
+
+ /** Tags used only to provide data to or receive data from operations */
+ ASSOCIATED_DATA = TagType:BYTES | 1000, /* Used to provide associated data for AEAD modes. */
+ NONCE = TagType:BYTES | 1001, /* Nonce or Initialization Vector */
+ MAC_LENGTH = TagType:UINT | 1003, /* MAC or AEAD authentication tag length in bits. */
+
+ RESET_SINCE_ID_ROTATION = TagType:BOOL | 1004, /* Whether the device has beeen factory reset
+ * since the last unique ID rotation. Used for
+ * key attestation. */
+};
+
+/**
+ * Possible purposes of a key (or pair).
+ */
+enum KeyPurpose : uint32_t {
+ ENCRYPT = 0, /* Usable with RSA, EC and AES keys. */
+ DECRYPT = 1, /* Usable with RSA, EC and AES keys. */
+ SIGN = 2, /* Usable with RSA, EC and HMAC keys. */
+ VERIFY = 3, /* Usable with RSA, EC and HMAC keys. */
+ /* 4 is reserved */
+ WRAP_KEY = 5, /* Usable with wrapping keys. */
+};
+
+struct KeyParameter {
+ /**
+ * Discriminates the uinon/blob field used. The blob cannot be coincided with the union, but
+ * only one of "f" and "blob" is ever used at a time. */
+ Tag tag;
+ union IntegerParams {
+ /** Enum types */
+ Algorithm algorithm;
+ BlockMode blockMode;
+ PaddingMode paddingMode;
+ Digest digest;
+ EcCurve ecCurve;
+ KeyOrigin origin;
+ KeyBlobUsageRequirements keyBlobUsageRequirements;
+ KeyPurpose purpose;
+ KeyDerivationFunction keyDerivationFunction;
+ HardwareAuthenticatorType hardwareAuthenticatorType;
+
+ /** Other types */
+ bool boolValue; // Always true, if a boolean tag is present.
+ uint32_t integer;
+ uint64_t longInteger;
+ uint64_t dateTime;
+ };
+ IntegerParams f; // Hidl does not support anonymous unions, so we have to name it.
+ vec<uint8_t> blob;
+};
+
+struct KeyCharacteristics {
+ vec<KeyParameter> softwareEnforced;
+ vec<KeyParameter> hardwareEnforced;
+};
+
+/**
+ * Data used to prove successful authentication.
+ */
+struct HardwareAuthToken {
+ uint64_t challenge;
+ uint64_t userId; // Secure User ID, not Android user ID.
+ uint64_t authenticatorId; // Secure authenticator ID.
+ HardwareAuthenticatorType authenticatorType;
+ uint64_t timestamp;
+ /**
+ * MACs are computed with a backward-compatible method, used by Keymaster 3.0, Gatekeeper 1.0
+ * and Fingerprint 1.0, as well as pre-treble HALs.
+ *
+ * The MAC is 32 bytes in length and is computed as follows:
+ *
+ * HMAC(H, 0 || challenge || user_id || authenticator_id || authenticator_type || timestamp)
+ *
+ * where ``||'' represents concatenation, the leading zero is a single byte, and all integers
+ * are represented as unsigned values, the full width of the type. The challenge, userId and
+ * authenticatorId values are in machine order, but authenticatorType and timestamp are in
+ * network order. This odd construction is compatible with the hw_auth_token_t structure,
+ */
+ uint8_t[32] mac;
+};
+
+typedef uint64_t OperationHandle;
diff --git a/keymaster/4.0/vts/OWNERS b/keymaster/4.0/vts/OWNERS
new file mode 100644
index 0000000..376c12b
--- /dev/null
+++ b/keymaster/4.0/vts/OWNERS
@@ -0,0 +1,4 @@
+jdanis@google.com
+swillden@google.com
+yim@google.com
+yuexima@google.com
diff --git a/keymaster/4.0/vts/functional/Android.bp b/keymaster/4.0/vts/functional/Android.bp
new file mode 100644
index 0000000..3c3063c
--- /dev/null
+++ b/keymaster/4.0/vts/functional/Android.bp
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsHalKeymasterV4_0TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "keymaster_hidl_hal_test.cpp",
+ ],
+ static_libs: [
+ "android.hardware.keymaster@4.0",
+ "libcrypto",
+ "libkeymaster4support",
+ "libsoftkeymasterdevice",
+ ],
+}
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
new file mode 100644
index 0000000..d26b6b9
--- /dev/null
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -0,0 +1,4096 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "keymaster_hidl_hal_test"
+#include <cutils/log.h>
+
+#include <iostream>
+
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#include <android/hardware/keymaster/4.0/IKeymaster.h>
+#include <android/hardware/keymaster/4.0/types.h>
+#include <cutils/properties.h>
+#include <keymaster/keymaster_configuration.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include <keymasterV4_0/attestation_record.h>
+#include <keymasterV4_0/authorization_set.h>
+#include <keymasterV4_0/key_param_output.h>
+#include <keymasterV4_0/openssl_utils.h>
+
+using ::android::sp;
+
+using ::std::string;
+
+static bool arm_deleteAllKeys = false;
+static bool dump_Attestations = false;
+
+namespace android {
+namespace hardware {
+
+template <typename T>
+bool operator==(const hidl_vec<T>& a, const hidl_vec<T>& b) {
+ if (a.size() != b.size()) {
+ return false;
+ }
+ for (size_t i = 0; i < a.size(); ++i) {
+ if (a[i] != b[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+namespace keymaster {
+namespace V4_0 {
+
+bool operator==(const KeyParameter& a, const KeyParameter& b) {
+ if (a.tag != b.tag) {
+ return false;
+ }
+
+ switch (a.tag) {
+ /* Boolean tags */
+ case Tag::INVALID:
+ case Tag::CALLER_NONCE:
+ case Tag::INCLUDE_UNIQUE_ID:
+ case Tag::BOOTLOADER_ONLY:
+ case Tag::NO_AUTH_REQUIRED:
+ case Tag::ALLOW_WHILE_ON_BODY:
+ case Tag::ROLLBACK_RESISTANCE:
+ case Tag::RESET_SINCE_ID_ROTATION:
+ return true;
+
+ /* Integer tags */
+ case Tag::KEY_SIZE:
+ case Tag::MIN_MAC_LENGTH:
+ case Tag::MIN_SECONDS_BETWEEN_OPS:
+ case Tag::MAX_USES_PER_BOOT:
+ case Tag::OS_VERSION:
+ case Tag::OS_PATCHLEVEL:
+ case Tag::MAC_LENGTH:
+ case Tag::AUTH_TIMEOUT:
+ return a.f.integer == b.f.integer;
+
+ /* Long integer tags */
+ case Tag::RSA_PUBLIC_EXPONENT:
+ case Tag::USER_SECURE_ID:
+ return a.f.longInteger == b.f.longInteger;
+
+ /* Date-time tags */
+ case Tag::ACTIVE_DATETIME:
+ case Tag::ORIGINATION_EXPIRE_DATETIME:
+ case Tag::USAGE_EXPIRE_DATETIME:
+ case Tag::CREATION_DATETIME:
+ return a.f.dateTime == b.f.dateTime;
+
+ /* Bytes tags */
+ case Tag::APPLICATION_ID:
+ case Tag::APPLICATION_DATA:
+ case Tag::ROOT_OF_TRUST:
+ case Tag::UNIQUE_ID:
+ case Tag::ATTESTATION_CHALLENGE:
+ case Tag::ATTESTATION_APPLICATION_ID:
+ case Tag::ATTESTATION_ID_BRAND:
+ case Tag::ATTESTATION_ID_DEVICE:
+ case Tag::ATTESTATION_ID_PRODUCT:
+ case Tag::ATTESTATION_ID_SERIAL:
+ case Tag::ATTESTATION_ID_IMEI:
+ case Tag::ATTESTATION_ID_MEID:
+ case Tag::ATTESTATION_ID_MANUFACTURER:
+ case Tag::ATTESTATION_ID_MODEL:
+ case Tag::ASSOCIATED_DATA:
+ case Tag::NONCE:
+ return a.blob == b.blob;
+
+ /* Enum tags */
+ case Tag::PURPOSE:
+ return a.f.purpose == b.f.purpose;
+ case Tag::ALGORITHM:
+ return a.f.algorithm == b.f.algorithm;
+ case Tag::BLOCK_MODE:
+ return a.f.blockMode == b.f.blockMode;
+ case Tag::DIGEST:
+ return a.f.digest == b.f.digest;
+ case Tag::PADDING:
+ return a.f.paddingMode == b.f.paddingMode;
+ case Tag::EC_CURVE:
+ return a.f.ecCurve == b.f.ecCurve;
+ case Tag::BLOB_USAGE_REQUIREMENTS:
+ return a.f.keyBlobUsageRequirements == b.f.keyBlobUsageRequirements;
+ case Tag::USER_AUTH_TYPE:
+ return a.f.integer == b.f.integer;
+ case Tag::ORIGIN:
+ return a.f.origin == b.f.origin;
+ }
+
+ return false;
+}
+
+bool operator==(const AuthorizationSet& a, const AuthorizationSet& b) {
+ return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
+}
+
+bool operator==(const KeyCharacteristics& a, const KeyCharacteristics& b) {
+ // This isn't very efficient. Oh, well.
+ AuthorizationSet a_sw(a.softwareEnforced);
+ AuthorizationSet b_sw(b.softwareEnforced);
+ AuthorizationSet a_tee(b.hardwareEnforced);
+ AuthorizationSet b_tee(b.hardwareEnforced);
+
+ a_sw.Sort();
+ b_sw.Sort();
+ a_tee.Sort();
+ b_tee.Sort();
+
+ return a_sw == b_sw && a_tee == b_tee;
+}
+
+::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set) {
+ if (set.size() == 0)
+ os << "(Empty)" << ::std::endl;
+ else {
+ os << "\n";
+ for (size_t i = 0; i < set.size(); ++i) os << set[i] << ::std::endl;
+ }
+ return os;
+}
+
+namespace test {
+namespace {
+
+template <TagType tag_type, Tag tag, typename ValueT>
+bool contains(hidl_vec<KeyParameter>& set, TypedTag<tag_type, tag> ttag, ValueT expected_value) {
+ size_t count = std::count_if(set.begin(), set.end(), [&](const KeyParameter& param) {
+ return param.tag == tag && accessTagValue(ttag, param) == expected_value;
+ });
+ return count == 1;
+}
+
+template <TagType tag_type, Tag tag>
+bool contains(hidl_vec<KeyParameter>& set, TypedTag<tag_type, tag>) {
+ size_t count = std::count_if(set.begin(), set.end(),
+ [&](const KeyParameter& param) { return param.tag == tag; });
+ return count > 0;
+}
+
+constexpr char hex_value[256] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // '0'..'9'
+ 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'A'..'F'
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'a'..'f'
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+string hex2str(string a) {
+ string b;
+ size_t num = a.size() / 2;
+ b.resize(num);
+ for (size_t i = 0; i < num; i++) {
+ b[i] = (hex_value[a[i * 2] & 0xFF] << 4) + (hex_value[a[i * 2 + 1] & 0xFF]);
+ }
+ return b;
+}
+
+char nibble2hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+string bin2hex(const hidl_vec<uint8_t>& data) {
+ string retval;
+ retval.reserve(data.size() * 2 + 1);
+ for (uint8_t byte : data) {
+ retval.push_back(nibble2hex[0x0F & (byte >> 4)]);
+ retval.push_back(nibble2hex[0x0F & byte]);
+ }
+ return retval;
+}
+
+string rsa_key = hex2str(
+ "30820275020100300d06092a864886f70d01010105000482025f3082025b"
+ "02010002818100c6095409047d8634812d5a218176e45c41d60a75b13901"
+ "f234226cffe776521c5a77b9e389417b71c0b6a44d13afe4e4a2805d46c9"
+ "da2935adb1ff0c1f24ea06e62b20d776430a4d435157233c6f916783c30e"
+ "310fcbd89b85c2d56771169785ac12bca244abda72bfb19fc44d27c81e1d"
+ "92de284f4061edfd99280745ea6d2502030100010281801be0f04d9cae37"
+ "18691f035338308e91564b55899ffb5084d2460e6630257e05b3ceab0297"
+ "2dfabcd6ce5f6ee2589eb67911ed0fac16e43a444b8c861e544a05933657"
+ "72f8baf6b22fc9e3c5f1024b063ac080a7b2234cf8aee8f6c47bbf4fd3ac"
+ "e7240290bef16c0b3f7f3cdd64ce3ab5912cf6e32f39ab188358afcccd80"
+ "81024100e4b49ef50f765d3b24dde01aceaaf130f2c76670a91a61ae08af"
+ "497b4a82be6dee8fcdd5e3f7ba1cfb1f0c926b88f88c92bfab137fba2285"
+ "227b83c342ff7c55024100ddabb5839c4c7f6bf3d4183231f005b31aa58a"
+ "ffdda5c79e4cce217f6bc930dbe563d480706c24e9ebfcab28a6cdefd324"
+ "b77e1bf7251b709092c24ff501fd91024023d4340eda3445d8cd26c14411"
+ "da6fdca63c1ccd4b80a98ad52b78cc8ad8beb2842c1d280405bc2f6c1bea"
+ "214a1d742ab996b35b63a82a5e470fa88dbf823cdd02401b7b57449ad30d"
+ "1518249a5f56bb98294d4b6ac12ffc86940497a5a5837a6cf946262b4945"
+ "26d328c11e1126380fde04c24f916dec250892db09a6d77cdba351024077"
+ "62cd8f4d050da56bd591adb515d24d7ccd32cca0d05f866d583514bd7324"
+ "d5f33645e8ed8b4a1cb3cc4a1d67987399f2a09f5b3fb68c88d5e5d90ac3"
+ "3492d6");
+
+string ec_256_key = hex2str(
+ "308187020100301306072a8648ce3d020106082a8648ce3d030107046d30"
+ "6b0201010420737c2ecd7b8d1940bf2930aa9b4ed3ff941eed09366bc032"
+ "99986481f3a4d859a14403420004bf85d7720d07c25461683bc648b4778a"
+ "9a14dd8a024e3bdd8c7ddd9ab2b528bbc7aa1b51f14ebbbb0bd0ce21bcc4"
+ "1c6eb00083cf3376d11fd44949e0b2183bfe");
+
+string ec_521_key = hex2str(
+ "3081EE020100301006072A8648CE3D020106052B810400230481D63081D3"
+ "02010104420011458C586DB5DAA92AFAB03F4FE46AA9D9C3CE9A9B7A006A"
+ "8384BEC4C78E8E9D18D7D08B5BCFA0E53C75B064AD51C449BAE0258D54B9"
+ "4B1E885DED08ED4FB25CE9A1818903818600040149EC11C6DF0FA122C6A9"
+ "AFD9754A4FA9513A627CA329E349535A5629875A8ADFBE27DCB932C05198"
+ "6377108D054C28C6F39B6F2C9AF81802F9F326B842FF2E5F3C00AB7635CF"
+ "B36157FC0882D574A10D839C1A0C049DC5E0D775E2EE50671A208431BB45"
+ "E78E70BEFE930DB34818EE4D5C26259F5C6B8E28A652950F9F88D7B4B2C9"
+ "D9");
+
+struct RSA_Delete {
+ void operator()(RSA* p) { RSA_free(p); }
+};
+
+X509* parse_cert_blob(const hidl_vec<uint8_t>& blob) {
+ const uint8_t* p = blob.data();
+ return d2i_X509(nullptr, &p, blob.size());
+}
+
+bool verify_chain(const hidl_vec<hidl_vec<uint8_t>>& chain) {
+ for (size_t i = 0; i < chain.size() - 1; ++i) {
+ X509_Ptr key_cert(parse_cert_blob(chain[i]));
+ X509_Ptr signing_cert;
+ if (i < chain.size() - 1) {
+ signing_cert.reset(parse_cert_blob(chain[i + 1]));
+ } else {
+ signing_cert.reset(parse_cert_blob(chain[i]));
+ }
+ EXPECT_TRUE(!!key_cert.get() && !!signing_cert.get());
+ if (!key_cert.get() || !signing_cert.get()) return false;
+
+ EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get()));
+ EXPECT_TRUE(!!signing_pubkey.get());
+ if (!signing_pubkey.get()) return false;
+
+ EXPECT_EQ(1, X509_verify(key_cert.get(), signing_pubkey.get()))
+ << "Verification of certificate " << i << " failed";
+
+ char* cert_issuer = //
+ X509_NAME_oneline(X509_get_issuer_name(key_cert.get()), nullptr, 0);
+ char* signer_subj =
+ X509_NAME_oneline(X509_get_subject_name(signing_cert.get()), nullptr, 0);
+ EXPECT_STREQ(cert_issuer, signer_subj) << "Cert " << i << " has wrong issuer.";
+ if (i == 0) {
+ char* cert_sub = X509_NAME_oneline(X509_get_subject_name(key_cert.get()), nullptr, 0);
+ EXPECT_STREQ("/CN=Android Keystore Key", cert_sub)
+ << "Cert " << i << " has wrong subject.";
+ free(cert_sub);
+ }
+
+ free(cert_issuer);
+ free(signer_subj);
+
+ if (dump_Attestations) std::cout << bin2hex(chain[i]) << std::endl;
+ }
+
+ return true;
+}
+
+// Extract attestation record from cert. Returned object is still part of cert; don't free it
+// separately.
+ASN1_OCTET_STRING* get_attestation_record(X509* certificate) {
+ ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
+ EXPECT_TRUE(!!oid.get());
+ if (!oid.get()) return nullptr;
+
+ int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
+ EXPECT_NE(-1, location) << "Attestation extension not found in certificate";
+ if (location == -1) return nullptr;
+
+ X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
+ EXPECT_TRUE(!!attest_rec_ext)
+ << "Found attestation extension but couldn't retrieve it? Probably a BoringSSL bug.";
+ if (!attest_rec_ext) return nullptr;
+
+ ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
+ EXPECT_TRUE(!!attest_rec) << "Attestation extension contained no data";
+ return attest_rec;
+}
+
+bool tag_in_list(const KeyParameter& entry) {
+ // Attestations don't contain everything in key authorization lists, so we need to filter
+ // the key lists to produce the lists that we expect to match the attestations.
+ auto tag_list = {
+ Tag::INCLUDE_UNIQUE_ID, Tag::BLOB_USAGE_REQUIREMENTS,
+ Tag::EC_CURVE /* Tag::EC_CURVE will be included by KM2 implementations */,
+ };
+ return std::find(tag_list.begin(), tag_list.end(), entry.tag) != tag_list.end();
+}
+
+AuthorizationSet filter_tags(const AuthorizationSet& set) {
+ AuthorizationSet filtered;
+ std::remove_copy_if(set.begin(), set.end(), std::back_inserter(filtered), tag_in_list);
+ return filtered;
+}
+
+std::string make_string(const uint8_t* data, size_t length) {
+ return std::string(reinterpret_cast<const char*>(data), length);
+}
+
+template <size_t N>
+std::string make_string(const uint8_t (&a)[N]) {
+ return make_string(a, N);
+}
+
+class HidlBuf : public hidl_vec<uint8_t> {
+ typedef hidl_vec<uint8_t> super;
+
+ public:
+ HidlBuf() {}
+ HidlBuf(const super& other) : super(other) {}
+ HidlBuf(super&& other) : super(std::move(other)) {}
+ explicit HidlBuf(const std::string& other) : HidlBuf() { *this = other; }
+
+ HidlBuf& operator=(const super& other) {
+ super::operator=(other);
+ return *this;
+ }
+
+ HidlBuf& operator=(super&& other) {
+ super::operator=(std::move(other));
+ return *this;
+ }
+
+ HidlBuf& operator=(const string& other) {
+ resize(other.size());
+ for (size_t i = 0; i < other.size(); ++i) {
+ (*this)[i] = static_cast<uint8_t>(other[i]);
+ }
+ return *this;
+ }
+
+ string to_string() const { return string(reinterpret_cast<const char*>(data()), size()); }
+};
+
+constexpr uint64_t kOpHandleSentinel = 0xFFFFFFFFFFFFFFFF;
+
+} // namespace
+
+class KeymasterHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static KeymasterHidlEnvironment* Instance() {
+ static KeymasterHidlEnvironment* instance = new KeymasterHidlEnvironment;
+ return instance;
+ }
+
+ void registerTestServices() override { registerTestService<IKeymaster>(); }
+
+ private:
+ KeymasterHidlEnvironment(){};
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(KeymasterHidlEnvironment);
+};
+
+class KeymasterHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ void TearDown() override {
+ if (key_blob_.size()) {
+ CheckedDeleteKey();
+ }
+ AbortIfNeeded();
+ }
+
+ // SetUpTestCase runs only once per test case, not once per test.
+ static void SetUpTestCase() {
+ string service_name = KeymasterHidlEnvironment::Instance()->getServiceName<IKeymaster>();
+ keymaster_ = ::testing::VtsHalHidlTargetTestBase::getService<IKeymaster>(service_name);
+ ASSERT_NE(keymaster_, nullptr);
+
+ ASSERT_TRUE(keymaster_
+ ->getHardwareInfo([&](bool is_secure, const hidl_string& name,
+ const hidl_string& author) {
+ is_secure_ = is_secure;
+ name_ = name;
+ author_ = author;
+ })
+ .isOk());
+
+ os_version_ = ::keymaster::GetOsVersion();
+ os_patch_level_ = ::keymaster::GetOsPatchlevel();
+ }
+
+ static void TearDownTestCase() { keymaster_.clear(); }
+
+ static IKeymaster& keymaster() { return *keymaster_; }
+ static uint32_t os_version() { return os_version_; }
+ static uint32_t os_patch_level() { return os_patch_level_; }
+
+ ErrorCode GenerateKey(const AuthorizationSet& key_desc, HidlBuf* key_blob,
+ KeyCharacteristics* key_characteristics) {
+ EXPECT_NE(key_blob, nullptr) << "Key blob pointer must not be null. Test bug";
+ EXPECT_EQ(0U, key_blob->size()) << "Key blob not empty before generating key. Test bug.";
+ EXPECT_NE(key_characteristics, nullptr)
+ << "Previous characteristics not deleted before generating key. Test bug.";
+
+ ErrorCode error;
+ EXPECT_TRUE(keymaster_
+ ->generateKey(key_desc.hidl_data(),
+ [&](ErrorCode hidl_error, const HidlBuf& hidl_key_blob,
+ const KeyCharacteristics& hidl_key_characteristics) {
+ error = hidl_error;
+ *key_blob = hidl_key_blob;
+ *key_characteristics = hidl_key_characteristics;
+ })
+ .isOk());
+ // On error, blob & characteristics should be empty.
+ if (error != ErrorCode::OK) {
+ EXPECT_EQ(0U, key_blob->size());
+ EXPECT_EQ(0U, (key_characteristics->softwareEnforced.size() +
+ key_characteristics->hardwareEnforced.size()));
+ }
+ return error;
+ }
+
+ ErrorCode GenerateKey(const AuthorizationSet& key_desc) {
+ return GenerateKey(key_desc, &key_blob_, &key_characteristics_);
+ }
+
+ ErrorCode ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
+ const string& key_material, HidlBuf* key_blob,
+ KeyCharacteristics* key_characteristics) {
+ ErrorCode error;
+ EXPECT_TRUE(keymaster_
+ ->importKey(key_desc.hidl_data(), format, HidlBuf(key_material),
+ [&](ErrorCode hidl_error, const HidlBuf& hidl_key_blob,
+ const KeyCharacteristics& hidl_key_characteristics) {
+ error = hidl_error;
+ *key_blob = hidl_key_blob;
+ *key_characteristics = hidl_key_characteristics;
+ })
+ .isOk());
+ // On error, blob & characteristics should be empty.
+ if (error != ErrorCode::OK) {
+ EXPECT_EQ(0U, key_blob->size());
+ EXPECT_EQ(0U, (key_characteristics->softwareEnforced.size() +
+ key_characteristics->hardwareEnforced.size()));
+ }
+ return error;
+ }
+
+ ErrorCode ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
+ const string& key_material) {
+ return ImportKey(key_desc, format, key_material, &key_blob_, &key_characteristics_);
+ }
+
+ ErrorCode ExportKey(KeyFormat format, const HidlBuf& key_blob, const HidlBuf& client_id,
+ const HidlBuf& app_data, HidlBuf* key_material) {
+ ErrorCode error;
+ EXPECT_TRUE(
+ keymaster_
+ ->exportKey(format, key_blob, client_id, app_data,
+ [&](ErrorCode hidl_error_code, const HidlBuf& hidl_key_material) {
+ error = hidl_error_code;
+ *key_material = hidl_key_material;
+ })
+ .isOk());
+ // On error, blob should be empty.
+ if (error != ErrorCode::OK) {
+ EXPECT_EQ(0U, key_material->size());
+ }
+ return error;
+ }
+
+ ErrorCode ExportKey(KeyFormat format, HidlBuf* key_material) {
+ HidlBuf client_id, app_data;
+ return ExportKey(format, key_blob_, client_id, app_data, key_material);
+ }
+
+ ErrorCode DeleteKey(HidlBuf* key_blob, bool keep_key_blob = false) {
+ auto rc = keymaster_->deleteKey(*key_blob);
+ if (!keep_key_blob) *key_blob = HidlBuf();
+ if (!rc.isOk()) return ErrorCode::UNKNOWN_ERROR;
+ return rc;
+ }
+
+ ErrorCode DeleteKey(bool keep_key_blob = false) { return DeleteKey(&key_blob_, keep_key_blob); }
+
+ ErrorCode DeleteAllKeys() {
+ ErrorCode error = keymaster_->deleteAllKeys();
+ return error;
+ }
+
+ void CheckedDeleteKey(HidlBuf* key_blob, bool keep_key_blob = false) {
+ auto rc = DeleteKey(key_blob, keep_key_blob);
+ EXPECT_TRUE(rc == ErrorCode::OK || rc == ErrorCode::UNIMPLEMENTED);
+ }
+
+ void CheckedDeleteKey() { CheckedDeleteKey(&key_blob_); }
+
+ ErrorCode GetCharacteristics(const HidlBuf& key_blob, const HidlBuf& client_id,
+ const HidlBuf& app_data, KeyCharacteristics* key_characteristics) {
+ ErrorCode error = ErrorCode::UNKNOWN_ERROR;
+ EXPECT_TRUE(
+ keymaster_
+ ->getKeyCharacteristics(
+ key_blob, client_id, app_data,
+ [&](ErrorCode hidl_error, const KeyCharacteristics& hidl_key_characteristics) {
+ error = hidl_error, *key_characteristics = hidl_key_characteristics;
+ })
+ .isOk());
+ return error;
+ }
+
+ ErrorCode GetCharacteristics(const HidlBuf& key_blob, KeyCharacteristics* key_characteristics) {
+ HidlBuf client_id, app_data;
+ return GetCharacteristics(key_blob, client_id, app_data, key_characteristics);
+ }
+
+ ErrorCode Begin(KeyPurpose purpose, const HidlBuf& key_blob, const AuthorizationSet& in_params,
+ AuthorizationSet* out_params, OperationHandle* op_handle) {
+ SCOPED_TRACE("Begin");
+ ErrorCode error;
+ OperationHandle saved_handle = *op_handle;
+ EXPECT_TRUE(
+ keymaster_
+ ->begin(purpose, key_blob, in_params.hidl_data(), HardwareAuthToken(),
+ [&](ErrorCode hidl_error, const hidl_vec<KeyParameter>& hidl_out_params,
+ uint64_t hidl_op_handle) {
+ error = hidl_error;
+ *out_params = hidl_out_params;
+ *op_handle = hidl_op_handle;
+ })
+ .isOk());
+ if (error != ErrorCode::OK) {
+ // Some implementations may modify *op_handle on error.
+ *op_handle = saved_handle;
+ }
+ return error;
+ }
+
+ ErrorCode Begin(KeyPurpose purpose, const AuthorizationSet& in_params,
+ AuthorizationSet* out_params) {
+ SCOPED_TRACE("Begin");
+ EXPECT_EQ(kOpHandleSentinel, op_handle_);
+ return Begin(purpose, key_blob_, in_params, out_params, &op_handle_);
+ }
+
+ ErrorCode Begin(KeyPurpose purpose, const AuthorizationSet& in_params) {
+ SCOPED_TRACE("Begin");
+ AuthorizationSet out_params;
+ ErrorCode error = Begin(purpose, in_params, &out_params);
+ EXPECT_TRUE(out_params.empty());
+ return error;
+ }
+
+ ErrorCode Update(OperationHandle op_handle, const AuthorizationSet& in_params,
+ const string& input, AuthorizationSet* out_params, string* output,
+ size_t* input_consumed) {
+ SCOPED_TRACE("Update");
+ ErrorCode error;
+ EXPECT_TRUE(keymaster_
+ ->update(op_handle, in_params.hidl_data(), HidlBuf(input),
+ HardwareAuthToken(),
+ [&](ErrorCode hidl_error, uint32_t hidl_input_consumed,
+ const hidl_vec<KeyParameter>& hidl_out_params,
+ const HidlBuf& hidl_output) {
+ error = hidl_error;
+ out_params->push_back(AuthorizationSet(hidl_out_params));
+ output->append(hidl_output.to_string());
+ *input_consumed = hidl_input_consumed;
+ })
+ .isOk());
+ return error;
+ }
+
+ ErrorCode Update(const string& input, string* out, size_t* input_consumed) {
+ SCOPED_TRACE("Update");
+ AuthorizationSet out_params;
+ ErrorCode error = Update(op_handle_, AuthorizationSet() /* in_params */, input, &out_params,
+ out, input_consumed);
+ EXPECT_TRUE(out_params.empty());
+ return error;
+ }
+
+ ErrorCode Finish(OperationHandle op_handle, const AuthorizationSet& in_params,
+ const string& input, const string& signature, AuthorizationSet* out_params,
+ string* output) {
+ SCOPED_TRACE("Finish");
+ ErrorCode error;
+ EXPECT_TRUE(
+ keymaster_
+ ->finish(op_handle, in_params.hidl_data(), HidlBuf(input), HidlBuf(signature),
+ HardwareAuthToken(),
+ [&](ErrorCode hidl_error, const hidl_vec<KeyParameter>& hidl_out_params,
+ const HidlBuf& hidl_output) {
+ error = hidl_error;
+ *out_params = hidl_out_params;
+ output->append(hidl_output.to_string());
+ })
+ .isOk());
+ op_handle_ = kOpHandleSentinel; // So dtor doesn't Abort().
+ return error;
+ }
+
+ ErrorCode Finish(const string& message, string* output) {
+ SCOPED_TRACE("Finish");
+ AuthorizationSet out_params;
+ string finish_output;
+ ErrorCode error = Finish(op_handle_, AuthorizationSet() /* in_params */, message,
+ "" /* signature */, &out_params, output);
+ if (error != ErrorCode::OK) {
+ return error;
+ }
+ EXPECT_EQ(0U, out_params.size());
+ return error;
+ }
+
+ ErrorCode Finish(const string& message, const string& signature, string* output) {
+ SCOPED_TRACE("Finish");
+ AuthorizationSet out_params;
+ ErrorCode error = Finish(op_handle_, AuthorizationSet() /* in_params */, message, signature,
+ &out_params, output);
+ op_handle_ = kOpHandleSentinel; // So dtor doesn't Abort().
+ if (error != ErrorCode::OK) {
+ return error;
+ }
+ EXPECT_EQ(0U, out_params.size());
+ return error;
+ }
+
+ ErrorCode Abort(OperationHandle op_handle) {
+ SCOPED_TRACE("Abort");
+ auto retval = keymaster_->abort(op_handle);
+ EXPECT_TRUE(retval.isOk());
+ return retval;
+ }
+
+ void AbortIfNeeded() {
+ SCOPED_TRACE("AbortIfNeeded");
+ if (op_handle_ != kOpHandleSentinel) {
+ EXPECT_EQ(ErrorCode::OK, Abort(op_handle_));
+ op_handle_ = kOpHandleSentinel;
+ }
+ }
+
+ ErrorCode AttestKey(const HidlBuf& key_blob, const AuthorizationSet& attest_params,
+ hidl_vec<hidl_vec<uint8_t>>* cert_chain) {
+ SCOPED_TRACE("AttestKey");
+ ErrorCode error;
+ auto rc = keymaster_->attestKey(
+ key_blob, attest_params.hidl_data(),
+ [&](ErrorCode hidl_error, const hidl_vec<hidl_vec<uint8_t>>& hidl_cert_chain) {
+ error = hidl_error;
+ *cert_chain = hidl_cert_chain;
+ });
+
+ EXPECT_TRUE(rc.isOk()) << rc.description();
+ if (!rc.isOk()) return ErrorCode::UNKNOWN_ERROR;
+
+ return error;
+ }
+
+ ErrorCode AttestKey(const AuthorizationSet& attest_params,
+ hidl_vec<hidl_vec<uint8_t>>* cert_chain) {
+ SCOPED_TRACE("AttestKey");
+ return AttestKey(key_blob_, attest_params, cert_chain);
+ }
+
+ string ProcessMessage(const HidlBuf& key_blob, KeyPurpose operation, const string& message,
+ const AuthorizationSet& in_params, AuthorizationSet* out_params) {
+ SCOPED_TRACE("ProcessMessage");
+ AuthorizationSet begin_out_params;
+ EXPECT_EQ(ErrorCode::OK,
+ Begin(operation, key_blob, in_params, &begin_out_params, &op_handle_));
+
+ string unused;
+ AuthorizationSet finish_params;
+ AuthorizationSet finish_out_params;
+ string output;
+ EXPECT_EQ(ErrorCode::OK,
+ Finish(op_handle_, finish_params, message, unused, &finish_out_params, &output));
+ op_handle_ = kOpHandleSentinel;
+
+ out_params->push_back(begin_out_params);
+ out_params->push_back(finish_out_params);
+ return output;
+ }
+
+ string SignMessage(const HidlBuf& key_blob, const string& message,
+ const AuthorizationSet& params) {
+ SCOPED_TRACE("SignMessage");
+ AuthorizationSet out_params;
+ string signature = ProcessMessage(key_blob, KeyPurpose::SIGN, message, params, &out_params);
+ EXPECT_TRUE(out_params.empty());
+ return signature;
+ }
+
+ string SignMessage(const string& message, const AuthorizationSet& params) {
+ SCOPED_TRACE("SignMessage");
+ return SignMessage(key_blob_, message, params);
+ }
+
+ string MacMessage(const string& message, Digest digest, size_t mac_length) {
+ SCOPED_TRACE("MacMessage");
+ return SignMessage(
+ key_blob_, message,
+ AuthorizationSetBuilder().Digest(digest).Authorization(TAG_MAC_LENGTH, mac_length));
+ }
+
+ void CheckHmacTestVector(const string& key, const string& message, Digest digest,
+ const string& expected_mac) {
+ SCOPED_TRACE("CheckHmacTestVector");
+ ASSERT_EQ(ErrorCode::OK,
+ ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .HmacKey(key.size() * 8)
+ .Authorization(TAG_MIN_MAC_LENGTH, expected_mac.size() * 8)
+ .Digest(digest),
+ KeyFormat::RAW, key));
+ string signature = MacMessage(message, digest, expected_mac.size() * 8);
+ EXPECT_EQ(expected_mac, signature)
+ << "Test vector didn't match for key of size " << key.size() << " message of size "
+ << message.size() << " and digest " << digest;
+ CheckedDeleteKey();
+ }
+
+ void CheckAesCtrTestVector(const string& key, const string& nonce, const string& message,
+ const string& expected_ciphertext) {
+ SCOPED_TRACE("CheckAesCtrTestVector");
+ ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(key.size() * 8)
+ .BlockMode(BlockMode::CTR)
+ .Authorization(TAG_CALLER_NONCE)
+ .Padding(PaddingMode::NONE),
+ KeyFormat::RAW, key));
+
+ auto params = AuthorizationSetBuilder()
+ .Authorization(TAG_NONCE, nonce.data(), nonce.size())
+ .BlockMode(BlockMode::CTR)
+ .Padding(PaddingMode::NONE);
+ AuthorizationSet out_params;
+ string ciphertext = EncryptMessage(key_blob_, message, params, &out_params);
+ EXPECT_EQ(expected_ciphertext, ciphertext);
+ }
+
+ void VerifyMessage(const HidlBuf& key_blob, const string& message, const string& signature,
+ const AuthorizationSet& params) {
+ SCOPED_TRACE("VerifyMessage");
+ AuthorizationSet begin_out_params;
+ ASSERT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::VERIFY, key_blob, params, &begin_out_params, &op_handle_));
+
+ string unused;
+ AuthorizationSet finish_params;
+ AuthorizationSet finish_out_params;
+ string output;
+ EXPECT_EQ(ErrorCode::OK, Finish(op_handle_, finish_params, message, signature,
+ &finish_out_params, &output));
+ op_handle_ = kOpHandleSentinel;
+ EXPECT_TRUE(output.empty());
+ }
+
+ void VerifyMessage(const string& message, const string& signature,
+ const AuthorizationSet& params) {
+ SCOPED_TRACE("VerifyMessage");
+ VerifyMessage(key_blob_, message, signature, params);
+ }
+
+ string EncryptMessage(const HidlBuf& key_blob, const string& message,
+ const AuthorizationSet& in_params, AuthorizationSet* out_params) {
+ SCOPED_TRACE("EncryptMessage");
+ return ProcessMessage(key_blob, KeyPurpose::ENCRYPT, message, in_params, out_params);
+ }
+
+ string EncryptMessage(const string& message, const AuthorizationSet& params,
+ AuthorizationSet* out_params) {
+ SCOPED_TRACE("EncryptMessage");
+ return EncryptMessage(key_blob_, message, params, out_params);
+ }
+
+ string EncryptMessage(const string& message, const AuthorizationSet& params) {
+ SCOPED_TRACE("EncryptMessage");
+ AuthorizationSet out_params;
+ string ciphertext = EncryptMessage(message, params, &out_params);
+ EXPECT_TRUE(out_params.empty())
+ << "Output params should be empty. Contained: " << out_params;
+ return ciphertext;
+ }
+
+ string DecryptMessage(const HidlBuf& key_blob, const string& ciphertext,
+ const AuthorizationSet& params) {
+ SCOPED_TRACE("DecryptMessage");
+ AuthorizationSet out_params;
+ string plaintext =
+ ProcessMessage(key_blob, KeyPurpose::DECRYPT, ciphertext, params, &out_params);
+ EXPECT_TRUE(out_params.empty());
+ return plaintext;
+ }
+
+ string DecryptMessage(const string& ciphertext, const AuthorizationSet& params) {
+ SCOPED_TRACE("DecryptMessage");
+ return DecryptMessage(key_blob_, ciphertext, params);
+ }
+
+ std::pair<ErrorCode, HidlBuf> UpgradeKey(const HidlBuf& key_blob) {
+ std::pair<ErrorCode, HidlBuf> retval;
+ keymaster_->upgradeKey(key_blob, hidl_vec<KeyParameter>(),
+ [&](ErrorCode error, const hidl_vec<uint8_t>& upgraded_blob) {
+ retval = std::tie(error, upgraded_blob);
+ });
+ return retval;
+ }
+
+ static bool IsSecure() { return is_secure_; }
+
+ HidlBuf key_blob_;
+ KeyCharacteristics key_characteristics_;
+ OperationHandle op_handle_ = kOpHandleSentinel;
+
+ private:
+ static sp<IKeymaster> keymaster_;
+ static uint32_t os_version_;
+ static uint32_t os_patch_level_;
+
+ static bool is_secure_;
+ static hidl_string name_;
+ static hidl_string author_;
+};
+
+bool verify_attestation_record(const string& challenge, const string& app_id,
+ AuthorizationSet expected_sw_enforced,
+ AuthorizationSet expected_tee_enforced,
+ const hidl_vec<uint8_t>& attestation_cert) {
+ X509_Ptr cert(parse_cert_blob(attestation_cert));
+ EXPECT_TRUE(!!cert.get());
+ if (!cert.get()) return false;
+
+ ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get());
+ EXPECT_TRUE(!!attest_rec);
+ if (!attest_rec) return false;
+
+ AuthorizationSet att_sw_enforced;
+ AuthorizationSet att_tee_enforced;
+ uint32_t att_attestation_version;
+ uint32_t att_keymaster_version;
+ SecurityLevel att_attestation_security_level;
+ SecurityLevel att_keymaster_security_level;
+ HidlBuf att_challenge;
+ HidlBuf att_unique_id;
+ HidlBuf att_app_id;
+ EXPECT_EQ(ErrorCode::OK,
+ parse_attestation_record(attest_rec->data, //
+ attest_rec->length, //
+ &att_attestation_version, //
+ &att_attestation_security_level, //
+ &att_keymaster_version, //
+ &att_keymaster_security_level, //
+ &att_challenge, //
+ &att_sw_enforced, //
+ &att_tee_enforced, //
+ &att_unique_id));
+
+ EXPECT_TRUE(att_attestation_version == 1 || att_attestation_version == 2);
+
+ expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID, HidlBuf(app_id));
+
+ EXPECT_GE(att_keymaster_version, 3U);
+ EXPECT_EQ(KeymasterHidlTest::IsSecure() ? SecurityLevel::TRUSTED_ENVIRONMENT
+ : SecurityLevel::SOFTWARE,
+ att_keymaster_security_level);
+ EXPECT_EQ(KeymasterHidlTest::IsSecure() ? SecurityLevel::TRUSTED_ENVIRONMENT
+ : SecurityLevel::SOFTWARE,
+ att_attestation_security_level);
+
+ EXPECT_EQ(challenge.length(), att_challenge.size());
+ EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data(), challenge.length()));
+
+ att_sw_enforced.Sort();
+ expected_sw_enforced.Sort();
+ EXPECT_EQ(filter_tags(expected_sw_enforced), filter_tags(att_sw_enforced));
+
+ att_tee_enforced.Sort();
+ expected_tee_enforced.Sort();
+ EXPECT_EQ(filter_tags(expected_tee_enforced), filter_tags(att_tee_enforced));
+
+ return true;
+}
+
+sp<IKeymaster> KeymasterHidlTest::keymaster_;
+uint32_t KeymasterHidlTest::os_version_;
+uint32_t KeymasterHidlTest::os_patch_level_;
+bool KeymasterHidlTest::is_secure_;
+hidl_string KeymasterHidlTest::name_;
+hidl_string KeymasterHidlTest::author_;
+
+class NewKeyGenerationTest : public KeymasterHidlTest {
+ protected:
+ void CheckBaseParams(const KeyCharacteristics& keyCharacteristics) {
+ // TODO(swillden): Distinguish which params should be in which auth list.
+
+ AuthorizationSet auths(keyCharacteristics.hardwareEnforced);
+ auths.push_back(AuthorizationSet(keyCharacteristics.softwareEnforced));
+
+ EXPECT_TRUE(auths.Contains(TAG_ORIGIN, KeyOrigin::GENERATED));
+ EXPECT_TRUE(auths.Contains(TAG_PURPOSE, KeyPurpose::SIGN));
+ EXPECT_TRUE(auths.Contains(TAG_PURPOSE, KeyPurpose::VERIFY));
+
+ // Verify that App ID, App data and ROT are NOT included.
+ EXPECT_FALSE(auths.Contains(TAG_ROOT_OF_TRUST));
+ EXPECT_FALSE(auths.Contains(TAG_APPLICATION_ID));
+ EXPECT_FALSE(auths.Contains(TAG_APPLICATION_DATA));
+
+ // Check that some unexpected tags/values are NOT present.
+ EXPECT_FALSE(auths.Contains(TAG_PURPOSE, KeyPurpose::ENCRYPT));
+ EXPECT_FALSE(auths.Contains(TAG_PURPOSE, KeyPurpose::DECRYPT));
+ EXPECT_FALSE(auths.Contains(TAG_AUTH_TIMEOUT, 301U));
+
+ // Now check that unspecified, defaulted tags are correct.
+ EXPECT_TRUE(auths.Contains(TAG_CREATION_DATETIME));
+
+ EXPECT_TRUE(auths.Contains(TAG_OS_VERSION, os_version()))
+ << "OS version is " << os_version() << " key reported "
+ << auths.GetTagValue(TAG_OS_VERSION);
+ EXPECT_TRUE(auths.Contains(TAG_OS_PATCHLEVEL, os_patch_level()))
+ << "OS patch level is " << os_patch_level() << " key reported "
+ << auths.GetTagValue(TAG_OS_PATCHLEVEL);
+ }
+
+ void CheckCharacteristics(const HidlBuf& key_blob,
+ const KeyCharacteristics& key_characteristics) {
+ KeyCharacteristics retrieved_chars;
+ ASSERT_EQ(ErrorCode::OK, GetCharacteristics(key_blob, &retrieved_chars));
+ EXPECT_EQ(key_characteristics, retrieved_chars);
+ }
+};
+
+/*
+ * NewKeyGenerationTest.Rsa
+ *
+ * Verifies that keymaster can generate all required RSA key sizes, and that the resulting keys have
+ * correct characteristics.
+ */
+TEST_F(NewKeyGenerationTest, Rsa) {
+ for (uint32_t key_size : {1024, 2048, 3072, 4096}) {
+ HidlBuf key_blob;
+ KeyCharacteristics key_characteristics;
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(key_size, 3)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE),
+ &key_blob, &key_characteristics));
+
+ ASSERT_GT(key_blob.size(), 0U);
+ CheckBaseParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
+
+ AuthorizationSet crypto_params;
+ if (IsSecure()) {
+ crypto_params = key_characteristics.hardwareEnforced;
+ } else {
+ crypto_params = key_characteristics.softwareEnforced;
+ }
+
+ EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::RSA));
+ EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
+ << "Key size " << key_size << "missing";
+ EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 3U));
+
+ CheckedDeleteKey(&key_blob);
+ }
+}
+
+/*
+ * NewKeyGenerationTest.RsaNoDefaultSize
+ *
+ * Verifies that failing to specify a key size for RSA key generation returns UNSUPPORTED_KEY_SIZE.
+ */
+TEST_F(NewKeyGenerationTest, RsaNoDefaultSize) {
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
+ GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_ALGORITHM, Algorithm::RSA)
+ .Authorization(TAG_RSA_PUBLIC_EXPONENT, 3U)
+ .SigningKey()));
+}
+
+/*
+ * NewKeyGenerationTest.Ecdsa
+ *
+ * Verifies that keymaster can generate all required EC key sizes, and that the resulting keys have
+ * correct characteristics.
+ */
+TEST_F(NewKeyGenerationTest, Ecdsa) {
+ for (uint32_t key_size : {224, 256, 384, 521}) {
+ HidlBuf key_blob;
+ KeyCharacteristics key_characteristics;
+ ASSERT_EQ(
+ ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(key_size).Digest(Digest::NONE),
+ &key_blob, &key_characteristics));
+ ASSERT_GT(key_blob.size(), 0U);
+ CheckBaseParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
+
+ AuthorizationSet crypto_params;
+ if (IsSecure()) {
+ crypto_params = key_characteristics.hardwareEnforced;
+ } else {
+ crypto_params = key_characteristics.softwareEnforced;
+ }
+
+ EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::EC));
+ EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
+ << "Key size " << key_size << "missing";
+
+ CheckedDeleteKey(&key_blob);
+ }
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaDefaultSize
+ *
+ * Verifies that failing to specify a key size for EC key generation returns UNSUPPORTED_KEY_SIZE.
+ */
+TEST_F(NewKeyGenerationTest, EcdsaDefaultSize) {
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
+ GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_ALGORITHM, Algorithm::EC)
+ .SigningKey()
+ .Digest(Digest::NONE)));
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaInvalidSize
+ *
+ * Verifies that failing to specify an invalid key size for EC key generation returns
+ * UNSUPPORTED_KEY_SIZE.
+ */
+TEST_F(NewKeyGenerationTest, EcdsaInvalidSize) {
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
+ GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(190).Digest(Digest::NONE)));
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaMismatchKeySize
+ *
+ * Verifies that specifying mismatched key size and curve for EC key generation returns
+ * INVALID_ARGUMENT.
+ */
+TEST_F(NewKeyGenerationTest, EcdsaMismatchKeySize) {
+ ASSERT_EQ(ErrorCode::INVALID_ARGUMENT,
+ GenerateKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(224)
+ .Authorization(TAG_EC_CURVE, EcCurve::P_256)
+ .Digest(Digest::NONE)));
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaAllValidSizes
+ *
+ * Verifies that keymaster supports all required EC key sizes.
+ */
+TEST_F(NewKeyGenerationTest, EcdsaAllValidSizes) {
+ size_t valid_sizes[] = {224, 256, 384, 521};
+ for (size_t size : valid_sizes) {
+ EXPECT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(size).Digest(Digest::NONE)))
+ << "Failed to generate size: " << size;
+ CheckCharacteristics(key_blob_, key_characteristics_);
+ CheckedDeleteKey();
+ }
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaAllValidCurves
+ *
+ * Verifies that keymaster supports all required EC curves.
+ */
+TEST_F(NewKeyGenerationTest, EcdsaAllValidCurves) {
+ V4_0::EcCurve curves[] = {EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521};
+ for (V4_0::EcCurve curve : curves) {
+ EXPECT_EQ(
+ ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(curve).Digest(Digest::SHA_2_512)))
+ << "Failed to generate key on curve: " << curve;
+ CheckCharacteristics(key_blob_, key_characteristics_);
+ CheckedDeleteKey();
+ }
+}
+
+/*
+ * NewKeyGenerationTest.Hmac
+ *
+ * Verifies that keymaster supports all required digests, and that the resulting keys have correct
+ * characteristics.
+ */
+TEST_F(NewKeyGenerationTest, Hmac) {
+ for (auto digest : {Digest::MD5, Digest::SHA1, Digest::SHA_2_224, Digest::SHA_2_256,
+ Digest::SHA_2_384, Digest::SHA_2_512}) {
+ HidlBuf key_blob;
+ KeyCharacteristics key_characteristics;
+ constexpr size_t key_size = 128;
+ ASSERT_EQ(
+ ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder().HmacKey(key_size).Digest(digest).Authorization(
+ TAG_MIN_MAC_LENGTH, 128),
+ &key_blob, &key_characteristics));
+
+ ASSERT_GT(key_blob.size(), 0U);
+ CheckBaseParams(key_characteristics);
+ CheckCharacteristics(key_blob, key_characteristics);
+
+ AuthorizationSet hardwareEnforced = key_characteristics.hardwareEnforced;
+ AuthorizationSet softwareEnforced = key_characteristics.softwareEnforced;
+ if (IsSecure()) {
+ EXPECT_TRUE(hardwareEnforced.Contains(TAG_ALGORITHM, Algorithm::HMAC));
+ EXPECT_TRUE(hardwareEnforced.Contains(TAG_KEY_SIZE, key_size))
+ << "Key size " << key_size << "missing";
+ } else {
+ EXPECT_TRUE(softwareEnforced.Contains(TAG_ALGORITHM, Algorithm::HMAC));
+ EXPECT_TRUE(softwareEnforced.Contains(TAG_KEY_SIZE, key_size))
+ << "Key size " << key_size << "missing";
+ }
+
+ CheckedDeleteKey(&key_blob);
+ }
+}
+
+/*
+ * NewKeyGenerationTest.HmacCheckKeySizes
+ *
+ * Verifies that keymaster supports all key sizes, and rejects all invalid key sizes.
+ */
+TEST_F(NewKeyGenerationTest, HmacCheckKeySizes) {
+ for (size_t key_size = 0; key_size <= 512; ++key_size) {
+ if (key_size < 64 || key_size % 8 != 0) {
+ // To keep this test from being very slow, we only test a random fraction of non-byte
+ // key sizes. We test only ~10% of such cases. Since there are 392 of them, we expect
+ // to run ~40 of them in each run.
+ if (key_size % 8 == 0 || random() % 10 == 0) {
+ EXPECT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
+ GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(key_size)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 256)))
+ << "HMAC key size " << key_size << " invalid";
+ }
+ } else {
+ EXPECT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(key_size)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 256)))
+ << "Failed to generate HMAC key of size " << key_size;
+ CheckCharacteristics(key_blob_, key_characteristics_);
+ CheckedDeleteKey();
+ }
+ }
+}
+
+/*
+ * NewKeyGenerationTest.HmacCheckMinMacLengths
+ *
+ * Verifies that keymaster supports all required MAC lengths and rejects all invalid lengths. This
+ * test is probabilistic in order to keep the runtime down, but any failure prints out the specific
+ * MAC length that failed, so reproducing a failed run will be easy.
+ */
+TEST_F(NewKeyGenerationTest, HmacCheckMinMacLengths) {
+ for (size_t min_mac_length = 0; min_mac_length <= 256; ++min_mac_length) {
+ if (min_mac_length < 64 || min_mac_length % 8 != 0) {
+ // To keep this test from being very long, we only test a random fraction of non-byte
+ // lengths. We test only ~10% of such cases. Since there are 172 of them, we expect to
+ // run ~17 of them in each run.
+ if (min_mac_length % 8 == 0 || random() % 10 == 0) {
+ EXPECT_EQ(ErrorCode::UNSUPPORTED_MIN_MAC_LENGTH,
+ GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, min_mac_length)))
+ << "HMAC min mac length " << min_mac_length << " invalid.";
+ }
+ } else {
+ EXPECT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, min_mac_length)))
+ << "Failed to generate HMAC key with min MAC length " << min_mac_length;
+ CheckCharacteristics(key_blob_, key_characteristics_);
+ CheckedDeleteKey();
+ }
+ }
+}
+
+/*
+ * NewKeyGenerationTest.HmacMultipleDigests
+ *
+ * Verifies that keymaster rejects HMAC key generation with multiple specified digest algorithms.
+ */
+TEST_F(NewKeyGenerationTest, HmacMultipleDigests) {
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_DIGEST,
+ GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(Digest::SHA1)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+}
+
+/*
+ * NewKeyGenerationTest.HmacDigestNone
+ *
+ * Verifies that keymaster rejects HMAC key generation with no digest or Digest::NONE
+ */
+TEST_F(NewKeyGenerationTest, HmacDigestNone) {
+ ASSERT_EQ(
+ ErrorCode::UNSUPPORTED_DIGEST,
+ GenerateKey(AuthorizationSetBuilder().HmacKey(128).Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_DIGEST,
+ GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(Digest::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+}
+
+typedef KeymasterHidlTest SigningOperationsTest;
+
+/*
+ * SigningOperationsTest.RsaSuccess
+ *
+ * Verifies that raw RSA signature operations succeed.
+ */
+TEST_F(SigningOperationsTest, RsaSuccess) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(1024, 3)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)));
+ string message = "12345678901234567890123456789012";
+ string signature = SignMessage(
+ message, AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+}
+
+/*
+ * SigningOperationsTest.RsaPssSha256Success
+ *
+ * Verifies that RSA-PSS signature operations succeed.
+ */
+TEST_F(SigningOperationsTest, RsaPssSha256Success) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(1024, 3)
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_PSS)
+ .Authorization(TAG_NO_AUTH_REQUIRED)));
+ // Use large message, which won't work without digesting.
+ string message(1024, 'a');
+ string signature = SignMessage(
+ message, AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Padding(PaddingMode::RSA_PSS));
+}
+
+/*
+ * SigningOperationsTest.RsaPaddingNoneDoesNotAllowOther
+ *
+ * Verifies that keymaster rejects signature operations that specify a padding mode when the key
+ * supports only unpadded operations.
+ */
+TEST_F(SigningOperationsTest, RsaPaddingNoneDoesNotAllowOther) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(1024, 3)
+ .Digest(Digest::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::NONE)));
+ string message = "12345678901234567890123456789012";
+ string signature;
+
+ EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE,
+ Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+}
+
+/*
+ * SigningOperationsTest.RsaPkcs1Sha256Success
+ *
+ * Verifies that digested RSA-PKCS1 signature operations succeed.
+ */
+TEST_F(SigningOperationsTest, RsaPkcs1Sha256Success) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(1024, 3)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+ string message(1024, 'a');
+ string signature = SignMessage(message, AuthorizationSetBuilder()
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN));
+}
+
+/*
+ * SigningOperationsTest.RsaPkcs1NoDigestSuccess
+ *
+ * Verifies that undigested RSA-PKCS1 signature operations succeed.
+ */
+TEST_F(SigningOperationsTest, RsaPkcs1NoDigestSuccess) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(1024, 3)
+ .Digest(Digest::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+ string message(53, 'a');
+ string signature = SignMessage(
+ message,
+ AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::RSA_PKCS1_1_5_SIGN));
+}
+
+/*
+ * SigningOperationsTest.RsaPkcs1NoDigestTooLarge
+ *
+ * Verifies that undigested RSA-PKCS1 signature operations fail with the correct error code when
+ * given a too-long message.
+ */
+TEST_F(SigningOperationsTest, RsaPkcs1NoDigestTooLong) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(1024, 3)
+ .Digest(Digest::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+ string message(129, 'a');
+
+ EXPECT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+ string signature;
+ EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &signature));
+}
+
+/*
+ * SigningOperationsTest.RsaPssSha512TooSmallKey
+ *
+ * Verifies that undigested RSA-PSS signature operations fail with the correct error code when
+ * used with a key that is too small for the message.
+ *
+ * A PSS-padded message is of length salt_size + digest_size + 16 (sizes in bits), and the keymaster
+ * specification requires that salt_size == digest_size, so the message will be digest_size * 2 +
+ * 16. Such a message can only be signed by a given key if the key is at least that size. This test
+ * uses SHA512, which has a digest_size == 512, so the message size is 1040 bits, too large for a
+ * 1024-bit key.
+ */
+TEST_F(SigningOperationsTest, RsaPssSha512TooSmallKey) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(1024, 3)
+ .Digest(Digest::SHA_2_512)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::RSA_PSS)));
+ EXPECT_EQ(
+ ErrorCode::INCOMPATIBLE_DIGEST,
+ Begin(KeyPurpose::SIGN,
+ AuthorizationSetBuilder().Digest(Digest::SHA_2_512).Padding(PaddingMode::RSA_PSS)));
+}
+
+/*
+ * SigningOperationsTest.RsaNoPaddingTooLong
+ *
+ * Verifies that raw RSA signature operations fail with the correct error code when
+ * given a too-long message.
+ */
+TEST_F(SigningOperationsTest, RsaNoPaddingTooLong) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(1024, 3)
+ .Digest(Digest::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+ // One byte too long
+ string message(1024 / 8 + 1, 'a');
+ ASSERT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+ string result;
+ ErrorCode finish_error_code = Finish(message, &result);
+ EXPECT_TRUE(finish_error_code == ErrorCode::INVALID_INPUT_LENGTH ||
+ finish_error_code == ErrorCode::INVALID_ARGUMENT);
+
+ // Very large message that should exceed the transfer buffer size of any reasonable TEE.
+ message = string(128 * 1024, 'a');
+ ASSERT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+ finish_error_code = Finish(message, &result);
+ EXPECT_TRUE(finish_error_code == ErrorCode::INVALID_INPUT_LENGTH ||
+ finish_error_code == ErrorCode::INVALID_ARGUMENT);
+}
+
+/*
+ * SigningOperationsTest.RsaAbort
+ *
+ * Verifies that operations can be aborted correctly. Uses an RSA signing operation for the test,
+ * but the behavior should be algorithm and purpose-independent.
+ */
+TEST_F(SigningOperationsTest, RsaAbort) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(1024, 3)
+ .Digest(Digest::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Padding(PaddingMode::NONE)));
+
+ ASSERT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::SIGN,
+ AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE)));
+ EXPECT_EQ(ErrorCode::OK, Abort(op_handle_));
+
+ // Another abort should fail
+ EXPECT_EQ(ErrorCode::INVALID_OPERATION_HANDLE, Abort(op_handle_));
+
+ // Set to sentinel, so TearDown() doesn't try to abort again.
+ op_handle_ = kOpHandleSentinel;
+}
+
+/*
+ * SigningOperationsTest.RsaUnsupportedPadding
+ *
+ * Verifies that RSA operations fail with the correct error (but key gen succeeds) when used with a
+ * padding mode inappropriate for RSA.
+ */
+TEST_F(SigningOperationsTest, RsaUnsupportedPadding) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(1024, 3)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Digest(Digest::SHA_2_256 /* supported digest */)
+ .Padding(PaddingMode::PKCS7)));
+ ASSERT_EQ(
+ ErrorCode::UNSUPPORTED_PADDING_MODE,
+ Begin(KeyPurpose::SIGN,
+ AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Padding(PaddingMode::PKCS7)));
+}
+
+/*
+ * SigningOperationsTest.RsaPssNoDigest
+ *
+ * Verifies that RSA PSS operations fail when no digest is used. PSS requires a digest.
+ */
+TEST_F(SigningOperationsTest, RsaNoDigest) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(1024, 3)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::RSA_PSS)));
+ ASSERT_EQ(ErrorCode::INCOMPATIBLE_DIGEST,
+ Begin(KeyPurpose::SIGN,
+ AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::RSA_PSS)));
+
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_DIGEST,
+ Begin(KeyPurpose::SIGN, AuthorizationSetBuilder().Padding(PaddingMode::RSA_PSS)));
+}
+
+/*
+ * SigningOperationsTest.RsaPssNoDigest
+ *
+ * Verifies that RSA operations fail when no padding mode is specified. PaddingMode::NONE is
+ * supported in some cases (as validated in other tests), but a mode must be specified.
+ */
+TEST_F(SigningOperationsTest, RsaNoPadding) {
+ // Padding must be specified
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaKey(1024, 3)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SigningKey()
+ .Digest(Digest::NONE)));
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_PADDING_MODE,
+ Begin(KeyPurpose::SIGN, AuthorizationSetBuilder().Digest(Digest::NONE)));
+}
+
+/*
+ * SigningOperationsTest.RsaShortMessage
+ *
+ * Verifies that raw RSA signatures succeed with a message shorter than the key size.
+ */
+TEST_F(SigningOperationsTest, RsaTooShortMessage) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(1024, 3)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)));
+
+ // Barely shorter
+ string message(1024 / 8 - 1, 'a');
+ SignMessage(message, AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+
+ // Much shorter
+ message = "a";
+ SignMessage(message, AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+}
+
+/*
+ * SigningOperationsTest.RsaSignWithEncryptionKey
+ *
+ * Verifies that RSA encryption keys cannot be used to sign.
+ */
+TEST_F(SigningOperationsTest, RsaSignWithEncryptionKey) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(1024, 3)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)));
+ ASSERT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE,
+ Begin(KeyPurpose::SIGN,
+ AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE)));
+}
+
+/*
+ * SigningOperationsTest.RsaSignTooLargeMessage
+ *
+ * Verifies that attempting a raw signature of a message which is the same length as the key, but
+ * numerically larger than the public modulus, fails with the correct error.
+ */
+TEST_F(SigningOperationsTest, RsaSignTooLargeMessage) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(1024, 3)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)));
+
+ // Largest possible message will always be larger than the public modulus.
+ string message(1024 / 8, static_cast<char>(0xff));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)));
+ string signature;
+ ASSERT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(message, &signature));
+}
+
+/*
+ * SigningOperationsTest.EcdsaAllSizesAndHashes
+ *
+ * Verifies that ECDSA operations succeed with all possible key sizes and hashes.
+ */
+TEST_F(SigningOperationsTest, EcdsaAllSizesAndHashes) {
+ for (auto key_size : {224, 256, 384, 521}) {
+ for (auto digest : {
+ Digest::SHA1, Digest::SHA_2_224, Digest::SHA_2_256, Digest::SHA_2_384,
+ Digest::SHA_2_512,
+ }) {
+ ErrorCode error = GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(key_size)
+ .Digest(digest));
+ EXPECT_EQ(ErrorCode::OK, error) << "Failed to generate ECDSA key with size " << key_size
+ << " and digest " << digest;
+ if (error != ErrorCode::OK) continue;
+
+ string message(1024, 'a');
+ if (digest == Digest::NONE) message.resize(key_size / 8);
+ SignMessage(message, AuthorizationSetBuilder().Digest(digest));
+ CheckedDeleteKey();
+ }
+ }
+}
+
+/*
+ * SigningOperationsTest.EcdsaAllCurves
+ *
+ * Verifies that ECDSA operations succeed with all possible curves.
+ */
+TEST_F(SigningOperationsTest, EcdsaAllCurves) {
+ for (auto curve : {EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521}) {
+ ErrorCode error = GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(curve)
+ .Digest(Digest::SHA_2_256));
+ EXPECT_EQ(ErrorCode::OK, error) << "Failed to generate ECDSA key with curve " << curve;
+ if (error != ErrorCode::OK) continue;
+
+ string message(1024, 'a');
+ SignMessage(message, AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
+ CheckedDeleteKey();
+ }
+}
+
+/*
+ * SigningOperationsTest.EcdsaNoDigestHugeData
+ *
+ * Verifies that ECDSA operations support very large messages, even without digesting. This should
+ * work because ECDSA actually only signs the leftmost L_n bits of the message, however large it may
+ * be. Not using digesting is a bad idea, but in some cases digesting is done by the framework.
+ */
+TEST_F(SigningOperationsTest, EcdsaNoDigestHugeData) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(224)
+ .Digest(Digest::NONE)));
+ string message(2 * 1024, 'a');
+ SignMessage(message, AuthorizationSetBuilder().Digest(Digest::NONE));
+}
+
+/*
+ * SigningOperationsTest.AesEcbSign
+ *
+ * Verifies that attempts to use AES keys to sign fail in the correct way.
+ */
+TEST_F(SigningOperationsTest, AesEcbSign) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SigningKey()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)));
+
+ AuthorizationSet out_params;
+ EXPECT_EQ(ErrorCode::UNSUPPORTED_PURPOSE,
+ Begin(KeyPurpose::SIGN, AuthorizationSet() /* in_params */, &out_params));
+ EXPECT_EQ(ErrorCode::UNSUPPORTED_PURPOSE,
+ Begin(KeyPurpose::VERIFY, AuthorizationSet() /* in_params */, &out_params));
+}
+
+/*
+ * SigningOperationsTest.HmacAllDigests
+ *
+ * Verifies that HMAC works with all digests.
+ */
+TEST_F(SigningOperationsTest, HmacAllDigests) {
+ for (auto digest : {Digest::SHA1, Digest::SHA_2_224, Digest::SHA_2_256, Digest::SHA_2_384,
+ Digest::SHA_2_512}) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .HmacKey(128)
+ .Digest(digest)
+ .Authorization(TAG_MIN_MAC_LENGTH, 160)))
+ << "Failed to create HMAC key with digest " << digest;
+ string message = "12345678901234567890123456789012";
+ string signature = MacMessage(message, digest, 160);
+ EXPECT_EQ(160U / 8U, signature.size())
+ << "Failed to sign with HMAC key with digest " << digest;
+ CheckedDeleteKey();
+ }
+}
+
+/*
+ * SigningOperationsTest.HmacSha256TooLargeMacLength
+ *
+ * Verifies that HMAC fails in the correct way when asked to generate a MAC larger than the digest
+ * size.
+ */
+TEST_F(SigningOperationsTest, HmacSha256TooLargeMacLength) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .HmacKey(128)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 256)));
+ AuthorizationSet output_params;
+ EXPECT_EQ(
+ ErrorCode::UNSUPPORTED_MAC_LENGTH,
+ Begin(
+ KeyPurpose::SIGN, key_blob_,
+ AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Authorization(TAG_MAC_LENGTH, 264),
+ &output_params, &op_handle_));
+}
+
+/*
+ * SigningOperationsTest.HmacSha256TooSmallMacLength
+ *
+ * Verifies that HMAC fails in the correct way when asked to generate a MAC smaller than the
+ * specified minimum MAC length.
+ */
+TEST_F(SigningOperationsTest, HmacSha256TooSmallMacLength) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .HmacKey(128)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+ AuthorizationSet output_params;
+ EXPECT_EQ(
+ ErrorCode::INVALID_MAC_LENGTH,
+ Begin(
+ KeyPurpose::SIGN, key_blob_,
+ AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Authorization(TAG_MAC_LENGTH, 120),
+ &output_params, &op_handle_));
+}
+
+/*
+ * SigningOperationsTest.HmacRfc4231TestCase3
+ *
+ * Validates against the test vectors from RFC 4231 test case 3.
+ */
+TEST_F(SigningOperationsTest, HmacRfc4231TestCase3) {
+ string key(20, 0xaa);
+ string message(50, 0xdd);
+ uint8_t sha_224_expected[] = {
+ 0x7f, 0xb3, 0xcb, 0x35, 0x88, 0xc6, 0xc1, 0xf6, 0xff, 0xa9, 0x69, 0x4d, 0x7d, 0x6a,
+ 0xd2, 0x64, 0x93, 0x65, 0xb0, 0xc1, 0xf6, 0x5d, 0x69, 0xd1, 0xec, 0x83, 0x33, 0xea,
+ };
+ uint8_t sha_256_expected[] = {
+ 0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8,
+ 0xeb, 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8,
+ 0xc1, 0x22, 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe,
+ };
+ uint8_t sha_384_expected[] = {
+ 0x88, 0x06, 0x26, 0x08, 0xd3, 0xe6, 0xad, 0x8a, 0x0a, 0xa2, 0xac, 0xe0,
+ 0x14, 0xc8, 0xa8, 0x6f, 0x0a, 0xa6, 0x35, 0xd9, 0x47, 0xac, 0x9f, 0xeb,
+ 0xe8, 0x3e, 0xf4, 0xe5, 0x59, 0x66, 0x14, 0x4b, 0x2a, 0x5a, 0xb3, 0x9d,
+ 0xc1, 0x38, 0x14, 0xb9, 0x4e, 0x3a, 0xb6, 0xe1, 0x01, 0xa3, 0x4f, 0x27,
+ };
+ uint8_t sha_512_expected[] = {
+ 0xfa, 0x73, 0xb0, 0x08, 0x9d, 0x56, 0xa2, 0x84, 0xef, 0xb0, 0xf0, 0x75, 0x6c,
+ 0x89, 0x0b, 0xe9, 0xb1, 0xb5, 0xdb, 0xdd, 0x8e, 0xe8, 0x1a, 0x36, 0x55, 0xf8,
+ 0x3e, 0x33, 0xb2, 0x27, 0x9d, 0x39, 0xbf, 0x3e, 0x84, 0x82, 0x79, 0xa7, 0x22,
+ 0xc8, 0x06, 0xb4, 0x85, 0xa4, 0x7e, 0x67, 0xc8, 0x07, 0xb9, 0x46, 0xa3, 0x37,
+ 0xbe, 0xe8, 0x94, 0x26, 0x74, 0x27, 0x88, 0x59, 0xe1, 0x32, 0x92, 0xfb,
+ };
+
+ CheckHmacTestVector(key, message, Digest::SHA_2_224, make_string(sha_224_expected));
+ CheckHmacTestVector(key, message, Digest::SHA_2_256, make_string(sha_256_expected));
+ CheckHmacTestVector(key, message, Digest::SHA_2_384, make_string(sha_384_expected));
+ CheckHmacTestVector(key, message, Digest::SHA_2_512, make_string(sha_512_expected));
+}
+
+/*
+ * SigningOperationsTest.HmacRfc4231TestCase5
+ *
+ * Validates against the test vectors from RFC 4231 test case 5.
+ */
+TEST_F(SigningOperationsTest, HmacRfc4231TestCase5) {
+ string key(20, 0x0c);
+ string message = "Test With Truncation";
+
+ uint8_t sha_224_expected[] = {
+ 0x0e, 0x2a, 0xea, 0x68, 0xa9, 0x0c, 0x8d, 0x37,
+ 0xc9, 0x88, 0xbc, 0xdb, 0x9f, 0xca, 0x6f, 0xa8,
+ };
+ uint8_t sha_256_expected[] = {
+ 0xa3, 0xb6, 0x16, 0x74, 0x73, 0x10, 0x0e, 0xe0,
+ 0x6e, 0x0c, 0x79, 0x6c, 0x29, 0x55, 0x55, 0x2b,
+ };
+ uint8_t sha_384_expected[] = {
+ 0x3a, 0xbf, 0x34, 0xc3, 0x50, 0x3b, 0x2a, 0x23,
+ 0xa4, 0x6e, 0xfc, 0x61, 0x9b, 0xae, 0xf8, 0x97,
+ };
+ uint8_t sha_512_expected[] = {
+ 0x41, 0x5f, 0xad, 0x62, 0x71, 0x58, 0x0a, 0x53,
+ 0x1d, 0x41, 0x79, 0xbc, 0x89, 0x1d, 0x87, 0xa6,
+ };
+
+ CheckHmacTestVector(key, message, Digest::SHA_2_224, make_string(sha_224_expected));
+ CheckHmacTestVector(key, message, Digest::SHA_2_256, make_string(sha_256_expected));
+ CheckHmacTestVector(key, message, Digest::SHA_2_384, make_string(sha_384_expected));
+ CheckHmacTestVector(key, message, Digest::SHA_2_512, make_string(sha_512_expected));
+}
+
+/*
+ * SigningOperationsTest.HmacRfc4231TestCase6
+ *
+ * Validates against the test vectors from RFC 4231 test case 6.
+ */
+TEST_F(SigningOperationsTest, HmacRfc4231TestCase6) {
+ string key(131, 0xaa);
+ string message = "Test Using Larger Than Block-Size Key - Hash Key First";
+
+ uint8_t sha_224_expected[] = {
+ 0x95, 0xe9, 0xa0, 0xdb, 0x96, 0x20, 0x95, 0xad, 0xae, 0xbe, 0x9b, 0x2d, 0x6f, 0x0d,
+ 0xbc, 0xe2, 0xd4, 0x99, 0xf1, 0x12, 0xf2, 0xd2, 0xb7, 0x27, 0x3f, 0xa6, 0x87, 0x0e,
+ };
+ uint8_t sha_256_expected[] = {
+ 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26,
+ 0xaa, 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28,
+ 0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54,
+ };
+ uint8_t sha_384_expected[] = {
+ 0x4e, 0xce, 0x08, 0x44, 0x85, 0x81, 0x3e, 0x90, 0x88, 0xd2, 0xc6, 0x3a,
+ 0x04, 0x1b, 0xc5, 0xb4, 0x4f, 0x9e, 0xf1, 0x01, 0x2a, 0x2b, 0x58, 0x8f,
+ 0x3c, 0xd1, 0x1f, 0x05, 0x03, 0x3a, 0xc4, 0xc6, 0x0c, 0x2e, 0xf6, 0xab,
+ 0x40, 0x30, 0xfe, 0x82, 0x96, 0x24, 0x8d, 0xf1, 0x63, 0xf4, 0x49, 0x52,
+ };
+ uint8_t sha_512_expected[] = {
+ 0x80, 0xb2, 0x42, 0x63, 0xc7, 0xc1, 0xa3, 0xeb, 0xb7, 0x14, 0x93, 0xc1, 0xdd,
+ 0x7b, 0xe8, 0xb4, 0x9b, 0x46, 0xd1, 0xf4, 0x1b, 0x4a, 0xee, 0xc1, 0x12, 0x1b,
+ 0x01, 0x37, 0x83, 0xf8, 0xf3, 0x52, 0x6b, 0x56, 0xd0, 0x37, 0xe0, 0x5f, 0x25,
+ 0x98, 0xbd, 0x0f, 0xd2, 0x21, 0x5d, 0x6a, 0x1e, 0x52, 0x95, 0xe6, 0x4f, 0x73,
+ 0xf6, 0x3f, 0x0a, 0xec, 0x8b, 0x91, 0x5a, 0x98, 0x5d, 0x78, 0x65, 0x98,
+ };
+
+ CheckHmacTestVector(key, message, Digest::SHA_2_224, make_string(sha_224_expected));
+ CheckHmacTestVector(key, message, Digest::SHA_2_256, make_string(sha_256_expected));
+ CheckHmacTestVector(key, message, Digest::SHA_2_384, make_string(sha_384_expected));
+ CheckHmacTestVector(key, message, Digest::SHA_2_512, make_string(sha_512_expected));
+}
+
+/*
+ * SigningOperationsTest.HmacRfc4231TestCase7
+ *
+ * Validates against the test vectors from RFC 4231 test case 7.
+ */
+TEST_F(SigningOperationsTest, HmacRfc4231TestCase7) {
+ string key(131, 0xaa);
+ string message =
+ "This is a test using a larger than block-size key and a larger than "
+ "block-size data. The key needs to be hashed before being used by the HMAC "
+ "algorithm.";
+
+ uint8_t sha_224_expected[] = {
+ 0x3a, 0x85, 0x41, 0x66, 0xac, 0x5d, 0x9f, 0x02, 0x3f, 0x54, 0xd5, 0x17, 0xd0, 0xb3,
+ 0x9d, 0xbd, 0x94, 0x67, 0x70, 0xdb, 0x9c, 0x2b, 0x95, 0xc9, 0xf6, 0xf5, 0x65, 0xd1,
+ };
+ uint8_t sha_256_expected[] = {
+ 0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f,
+ 0xbc, 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07,
+ 0x13, 0x93, 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2,
+ };
+ uint8_t sha_384_expected[] = {
+ 0x66, 0x17, 0x17, 0x8e, 0x94, 0x1f, 0x02, 0x0d, 0x35, 0x1e, 0x2f, 0x25,
+ 0x4e, 0x8f, 0xd3, 0x2c, 0x60, 0x24, 0x20, 0xfe, 0xb0, 0xb8, 0xfb, 0x9a,
+ 0xdc, 0xce, 0xbb, 0x82, 0x46, 0x1e, 0x99, 0xc5, 0xa6, 0x78, 0xcc, 0x31,
+ 0xe7, 0x99, 0x17, 0x6d, 0x38, 0x60, 0xe6, 0x11, 0x0c, 0x46, 0x52, 0x3e,
+ };
+ uint8_t sha_512_expected[] = {
+ 0xe3, 0x7b, 0x6a, 0x77, 0x5d, 0xc8, 0x7d, 0xba, 0xa4, 0xdf, 0xa9, 0xf9, 0x6e,
+ 0x5e, 0x3f, 0xfd, 0xde, 0xbd, 0x71, 0xf8, 0x86, 0x72, 0x89, 0x86, 0x5d, 0xf5,
+ 0xa3, 0x2d, 0x20, 0xcd, 0xc9, 0x44, 0xb6, 0x02, 0x2c, 0xac, 0x3c, 0x49, 0x82,
+ 0xb1, 0x0d, 0x5e, 0xeb, 0x55, 0xc3, 0xe4, 0xde, 0x15, 0x13, 0x46, 0x76, 0xfb,
+ 0x6d, 0xe0, 0x44, 0x60, 0x65, 0xc9, 0x74, 0x40, 0xfa, 0x8c, 0x6a, 0x58,
+ };
+
+ CheckHmacTestVector(key, message, Digest::SHA_2_224, make_string(sha_224_expected));
+ CheckHmacTestVector(key, message, Digest::SHA_2_256, make_string(sha_256_expected));
+ CheckHmacTestVector(key, message, Digest::SHA_2_384, make_string(sha_384_expected));
+ CheckHmacTestVector(key, message, Digest::SHA_2_512, make_string(sha_512_expected));
+}
+
+typedef KeymasterHidlTest VerificationOperationsTest;
+
+/*
+ * VerificationOperationsTest.RsaSuccess
+ *
+ * Verifies that a simple RSA signature/verification sequence succeeds.
+ */
+TEST_F(VerificationOperationsTest, RsaSuccess) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(1024, 3)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)));
+ string message = "12345678901234567890123456789012";
+ string signature = SignMessage(
+ message, AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+ VerifyMessage(message, signature,
+ AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+}
+
+/*
+ * VerificationOperationsTest.RsaSuccess
+ *
+ * Verifies RSA signature/verification for all padding modes and digests.
+ */
+TEST_F(VerificationOperationsTest, RsaAllPaddingsAndDigests) {
+ ASSERT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(2048, 3)
+ .Digest(Digest::NONE, Digest::MD5, Digest::SHA1, Digest::SHA_2_224,
+ Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512)
+ .Padding(PaddingMode::NONE)
+ .Padding(PaddingMode::RSA_PSS)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+
+ string message(128, 'a');
+ string corrupt_message(message);
+ ++corrupt_message[corrupt_message.size() / 2];
+
+ for (auto padding :
+ {PaddingMode::NONE, PaddingMode::RSA_PSS, PaddingMode::RSA_PKCS1_1_5_SIGN}) {
+ for (auto digest : {Digest::NONE, Digest::MD5, Digest::SHA1, Digest::SHA_2_224,
+ Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512}) {
+ if (padding == PaddingMode::NONE && digest != Digest::NONE) {
+ // Digesting only makes sense with padding.
+ continue;
+ }
+
+ if (padding == PaddingMode::RSA_PSS && digest == Digest::NONE) {
+ // PSS requires digesting.
+ continue;
+ }
+
+ string signature =
+ SignMessage(message, AuthorizationSetBuilder().Digest(digest).Padding(padding));
+ VerifyMessage(message, signature,
+ AuthorizationSetBuilder().Digest(digest).Padding(padding));
+
+ if (digest != Digest::NONE) {
+ // Verify with OpenSSL.
+ HidlBuf pubkey;
+ ASSERT_EQ(ErrorCode::OK, ExportKey(KeyFormat::X509, &pubkey));
+
+ const uint8_t* p = pubkey.data();
+ EVP_PKEY_Ptr pkey(d2i_PUBKEY(nullptr /* alloc new */, &p, pubkey.size()));
+ ASSERT_TRUE(pkey.get());
+
+ EVP_MD_CTX digest_ctx;
+ EVP_MD_CTX_init(&digest_ctx);
+ EVP_PKEY_CTX* pkey_ctx;
+ const EVP_MD* md = openssl_digest(digest);
+ ASSERT_NE(md, nullptr);
+ EXPECT_EQ(1, EVP_DigestVerifyInit(&digest_ctx, &pkey_ctx, md, nullptr /* engine */,
+ pkey.get()));
+
+ switch (padding) {
+ case PaddingMode::RSA_PSS:
+ EXPECT_GT(EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING), 0);
+ EXPECT_GT(EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, EVP_MD_size(md)), 0);
+ break;
+ case PaddingMode::RSA_PKCS1_1_5_SIGN:
+ // PKCS1 is the default; don't need to set anything.
+ break;
+ default:
+ FAIL();
+ break;
+ }
+
+ EXPECT_EQ(1, EVP_DigestVerifyUpdate(&digest_ctx, message.data(), message.size()));
+ EXPECT_EQ(1, EVP_DigestVerifyFinal(
+ &digest_ctx, reinterpret_cast<const uint8_t*>(signature.data()),
+ signature.size()));
+ EVP_MD_CTX_cleanup(&digest_ctx);
+ }
+
+ // Corrupt signature shouldn't verify.
+ string corrupt_signature(signature);
+ ++corrupt_signature[corrupt_signature.size() / 2];
+
+ EXPECT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::VERIFY,
+ AuthorizationSetBuilder().Digest(digest).Padding(padding)));
+ string result;
+ EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(message, corrupt_signature, &result));
+
+ // Corrupt message shouldn't verify
+ EXPECT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::VERIFY,
+ AuthorizationSetBuilder().Digest(digest).Padding(padding)));
+ EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(corrupt_message, signature, &result));
+ }
+ }
+}
+
+/*
+ * VerificationOperationsTest.RsaSuccess
+ *
+ * Verifies ECDSA signature/verification for all digests and curves.
+ */
+TEST_F(VerificationOperationsTest, EcdsaAllDigestsAndCurves) {
+ auto digests = {
+ Digest::NONE, Digest::SHA1, Digest::SHA_2_224,
+ Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512,
+ };
+
+ string message = "1234567890";
+ string corrupt_message = "2234567890";
+ for (auto curve : {EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521}) {
+ ErrorCode error = GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(curve)
+ .Digest(digests));
+ EXPECT_EQ(ErrorCode::OK, error) << "Failed to generate key for EC curve " << curve;
+ if (error != ErrorCode::OK) {
+ continue;
+ }
+
+ for (auto digest : digests) {
+ string signature = SignMessage(message, AuthorizationSetBuilder().Digest(digest));
+ VerifyMessage(message, signature, AuthorizationSetBuilder().Digest(digest));
+
+ // Verify with OpenSSL
+ if (digest != Digest::NONE) {
+ HidlBuf pubkey;
+ ASSERT_EQ(ErrorCode::OK, ExportKey(KeyFormat::X509, &pubkey))
+ << curve << ' ' << digest;
+
+ const uint8_t* p = pubkey.data();
+ EVP_PKEY_Ptr pkey(d2i_PUBKEY(nullptr /* alloc new */, &p, pubkey.size()));
+ ASSERT_TRUE(pkey.get());
+
+ EVP_MD_CTX digest_ctx;
+ EVP_MD_CTX_init(&digest_ctx);
+ EVP_PKEY_CTX* pkey_ctx;
+ const EVP_MD* md = openssl_digest(digest);
+
+ EXPECT_EQ(1, EVP_DigestVerifyInit(&digest_ctx, &pkey_ctx, md, nullptr /* engine */,
+ pkey.get()))
+ << curve << ' ' << digest;
+
+ EXPECT_EQ(1, EVP_DigestVerifyUpdate(&digest_ctx, message.data(), message.size()))
+ << curve << ' ' << digest;
+
+ EXPECT_EQ(1, EVP_DigestVerifyFinal(
+ &digest_ctx, reinterpret_cast<const uint8_t*>(signature.data()),
+ signature.size()))
+ << curve << ' ' << digest;
+
+ EVP_MD_CTX_cleanup(&digest_ctx);
+ }
+
+ // Corrupt signature shouldn't verify.
+ string corrupt_signature(signature);
+ ++corrupt_signature[corrupt_signature.size() / 2];
+
+ EXPECT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::VERIFY, AuthorizationSetBuilder().Digest(digest)))
+ << curve << ' ' << digest;
+
+ string result;
+ EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(message, corrupt_signature, &result))
+ << curve << ' ' << digest;
+
+ // Corrupt message shouldn't verify
+ EXPECT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::VERIFY, AuthorizationSetBuilder().Digest(digest)))
+ << curve << ' ' << digest;
+
+ EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(corrupt_message, signature, &result))
+ << curve << ' ' << digest;
+ }
+
+ auto rc = DeleteKey();
+ ASSERT_TRUE(rc == ErrorCode::OK || rc == ErrorCode::UNIMPLEMENTED);
+ }
+}
+
+/*
+ * VerificationOperationsTest.HmacSigningKeyCannotVerify
+ *
+ * Verifies HMAC signing and verification, but that a signing key cannot be used to verify.
+ */
+TEST_F(VerificationOperationsTest, HmacSigningKeyCannotVerify) {
+ string key_material = "HelloThisIsAKey";
+
+ HidlBuf signing_key, verification_key;
+ KeyCharacteristics signing_key_chars, verification_key_chars;
+ EXPECT_EQ(ErrorCode::OK,
+ ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_ALGORITHM, Algorithm::HMAC)
+ .Authorization(TAG_PURPOSE, KeyPurpose::SIGN)
+ .Digest(Digest::SHA1)
+ .Authorization(TAG_MIN_MAC_LENGTH, 160),
+ KeyFormat::RAW, key_material, &signing_key, &signing_key_chars));
+ EXPECT_EQ(ErrorCode::OK,
+ ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_ALGORITHM, Algorithm::HMAC)
+ .Authorization(TAG_PURPOSE, KeyPurpose::VERIFY)
+ .Digest(Digest::SHA1)
+ .Authorization(TAG_MIN_MAC_LENGTH, 160),
+ KeyFormat::RAW, key_material, &verification_key, &verification_key_chars));
+
+ string message = "This is a message.";
+ string signature = SignMessage(
+ signing_key, message,
+ AuthorizationSetBuilder().Digest(Digest::SHA1).Authorization(TAG_MAC_LENGTH, 160));
+
+ // Signing key should not work.
+ AuthorizationSet out_params;
+ EXPECT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE,
+ Begin(KeyPurpose::VERIFY, signing_key, AuthorizationSetBuilder().Digest(Digest::SHA1),
+ &out_params, &op_handle_));
+
+ // Verification key should work.
+ VerifyMessage(verification_key, message, signature,
+ AuthorizationSetBuilder().Digest(Digest::SHA1));
+
+ CheckedDeleteKey(&signing_key);
+ CheckedDeleteKey(&verification_key);
+}
+
+typedef KeymasterHidlTest ExportKeyTest;
+
+/*
+ * ExportKeyTest.RsaUnsupportedKeyFormat
+ *
+ * Verifies that attempting to export RSA keys in PKCS#8 format fails with the correct error.
+ */
+TEST_F(ExportKeyTest, RsaUnsupportedKeyFormat) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(1024, 3)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)));
+ HidlBuf export_data;
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_FORMAT, ExportKey(KeyFormat::PKCS8, &export_data));
+}
+
+/*
+ * ExportKeyTest.RsaCorruptedKeyBlob
+ *
+ * Verifies that attempting to export RSA keys from corrupted key blobs fails. This is essentially
+ * a poor-man's key blob fuzzer.
+ */
+TEST_F(ExportKeyTest, RsaCorruptedKeyBlob) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(1024, 3)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)));
+ for (size_t i = 0; i < key_blob_.size(); ++i) {
+ HidlBuf corrupted(key_blob_);
+ ++corrupted[i];
+
+ HidlBuf export_data;
+ EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+ ExportKey(KeyFormat::X509, corrupted, HidlBuf(), HidlBuf(), &export_data))
+ << "Blob corrupted at offset " << i << " erroneously accepted as valid";
+ }
+}
+
+/*
+ * ExportKeyTest.RsaCorruptedKeyBlob
+ *
+ * Verifies that attempting to export ECDSA keys from corrupted key blobs fails. This is
+ * essentially a poor-man's key blob fuzzer.
+ */
+TEST_F(ExportKeyTest, EcCorruptedKeyBlob) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Digest(Digest::NONE)));
+ for (size_t i = 0; i < key_blob_.size(); ++i) {
+ HidlBuf corrupted(key_blob_);
+ ++corrupted[i];
+
+ HidlBuf export_data;
+ EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+ ExportKey(KeyFormat::X509, corrupted, HidlBuf(), HidlBuf(), &export_data))
+ << "Blob corrupted at offset " << i << " erroneously accepted as valid";
+ }
+}
+
+/*
+ * ExportKeyTest.AesKeyUnexportable
+ *
+ * Verifies that attempting to export AES keys fails in the expected way.
+ */
+TEST_F(ExportKeyTest, AesKeyUnexportable) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .EcbMode()
+ .Padding(PaddingMode::NONE)));
+
+ HidlBuf export_data;
+ EXPECT_EQ(ErrorCode::UNSUPPORTED_KEY_FORMAT, ExportKey(KeyFormat::X509, &export_data));
+ EXPECT_EQ(ErrorCode::UNSUPPORTED_KEY_FORMAT, ExportKey(KeyFormat::PKCS8, &export_data));
+ EXPECT_EQ(ErrorCode::UNSUPPORTED_KEY_FORMAT, ExportKey(KeyFormat::RAW, &export_data));
+}
+
+class ImportKeyTest : public KeymasterHidlTest {
+ public:
+ template <TagType tag_type, Tag tag, typename ValueT>
+ void CheckCryptoParam(TypedTag<tag_type, tag> ttag, ValueT expected) {
+ SCOPED_TRACE("CheckCryptoParam");
+ if (IsSecure()) {
+ EXPECT_TRUE(contains(key_characteristics_.hardwareEnforced, ttag, expected))
+ << "Tag " << tag << " with value " << expected << " not found";
+ EXPECT_FALSE(contains(key_characteristics_.softwareEnforced, ttag))
+ << "Tag " << tag << " found";
+ } else {
+ EXPECT_TRUE(contains(key_characteristics_.softwareEnforced, ttag, expected))
+ << "Tag " << tag << " with value " << expected << " not found";
+ EXPECT_FALSE(contains(key_characteristics_.hardwareEnforced, ttag))
+ << "Tag " << tag << " found";
+ }
+ }
+
+ void CheckOrigin() {
+ SCOPED_TRACE("CheckOrigin");
+ if (IsSecure()) {
+ EXPECT_TRUE(
+ contains(key_characteristics_.hardwareEnforced, TAG_ORIGIN, KeyOrigin::IMPORTED));
+ } else {
+ EXPECT_TRUE(
+ contains(key_characteristics_.softwareEnforced, TAG_ORIGIN, KeyOrigin::IMPORTED));
+ }
+ }
+};
+
+/*
+ * ImportKeyTest.RsaSuccess
+ *
+ * Verifies that importing and using an RSA key pair works correctly.
+ */
+TEST_F(ImportKeyTest, RsaSuccess) {
+ ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(1024, 65537)
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_PSS),
+ KeyFormat::PKCS8, rsa_key));
+
+ CheckCryptoParam(TAG_ALGORITHM, Algorithm::RSA);
+ CheckCryptoParam(TAG_KEY_SIZE, 1024U);
+ CheckCryptoParam(TAG_RSA_PUBLIC_EXPONENT, 65537U);
+ CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+ CheckCryptoParam(TAG_PADDING, PaddingMode::RSA_PSS);
+ CheckOrigin();
+
+ string message(1024 / 8, 'a');
+ auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Padding(PaddingMode::RSA_PSS);
+ string signature = SignMessage(message, params);
+ VerifyMessage(message, signature, params);
+}
+
+/*
+ * ImportKeyTest.RsaKeySizeMismatch
+ *
+ * Verifies that importing an RSA key pair with a size that doesn't match the key fails in the
+ * correct way.
+ */
+TEST_F(ImportKeyTest, RsaKeySizeMismatch) {
+ ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
+ ImportKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048 /* Doesn't match key */, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE),
+ KeyFormat::PKCS8, rsa_key));
+}
+
+/*
+ * ImportKeyTest.RsaPublicExponentMismatch
+ *
+ * Verifies that importing an RSA key pair with a public exponent that doesn't match the key fails
+ * in the correct way.
+ */
+TEST_F(ImportKeyTest, RsaPublicExponentMismatch) {
+ ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
+ ImportKey(AuthorizationSetBuilder()
+ .RsaSigningKey(1024, 3 /* Doesn't match key */)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE),
+ KeyFormat::PKCS8, rsa_key));
+}
+
+/*
+ * ImportKeyTest.EcdsaSuccess
+ *
+ * Verifies that importing and using an ECDSA P-256 key pair works correctly.
+ */
+TEST_F(ImportKeyTest, EcdsaSuccess) {
+ ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(256)
+ .Digest(Digest::SHA_2_256),
+ KeyFormat::PKCS8, ec_256_key));
+
+ CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+ CheckCryptoParam(TAG_KEY_SIZE, 256U);
+ CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+ CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_256);
+
+ CheckOrigin();
+
+ string message(32, 'a');
+ auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256);
+ string signature = SignMessage(message, params);
+ VerifyMessage(message, signature, params);
+}
+
+/*
+ * ImportKeyTest.Ecdsa521Success
+ *
+ * Verifies that importing and using an ECDSA P-521 key pair works correctly.
+ */
+TEST_F(ImportKeyTest, Ecdsa521Success) {
+ ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(521)
+ .Digest(Digest::SHA_2_256),
+ KeyFormat::PKCS8, ec_521_key));
+
+ CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+ CheckCryptoParam(TAG_KEY_SIZE, 521U);
+ CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+ CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_521);
+ CheckOrigin();
+
+ string message(32, 'a');
+ auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256);
+ string signature = SignMessage(message, params);
+ VerifyMessage(message, signature, params);
+}
+
+/*
+ * ImportKeyTest.EcdsaSizeMismatch
+ *
+ * Verifies that importing an ECDSA key pair with a size that doesn't match the key fails in the
+ * correct way.
+ */
+TEST_F(ImportKeyTest, EcdsaSizeMismatch) {
+ ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
+ ImportKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(224 /* Doesn't match key */)
+ .Digest(Digest::NONE),
+ KeyFormat::PKCS8, ec_256_key));
+}
+
+/*
+ * ImportKeyTest.EcdsaCurveMismatch
+ *
+ * Verifies that importing an ECDSA key pair with a curve that doesn't match the key fails in the
+ * correct way.
+ */
+TEST_F(ImportKeyTest, EcdsaCurveMismatch) {
+ ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
+ ImportKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(EcCurve::P_224 /* Doesn't match key */)
+ .Digest(Digest::NONE),
+ KeyFormat::PKCS8, ec_256_key));
+}
+
+/*
+ * ImportKeyTest.AesSuccess
+ *
+ * Verifies that importing and using an AES key works.
+ */
+TEST_F(ImportKeyTest, AesSuccess) {
+ string key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(key.size() * 8)
+ .EcbMode()
+ .Padding(PaddingMode::PKCS7),
+ KeyFormat::RAW, key));
+
+ CheckCryptoParam(TAG_ALGORITHM, Algorithm::AES);
+ CheckCryptoParam(TAG_KEY_SIZE, 128U);
+ CheckCryptoParam(TAG_PADDING, PaddingMode::PKCS7);
+ CheckCryptoParam(TAG_BLOCK_MODE, BlockMode::ECB);
+ CheckOrigin();
+
+ string message = "Hello World!";
+ auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+ string ciphertext = EncryptMessage(message, params);
+ string plaintext = DecryptMessage(ciphertext, params);
+ EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * ImportKeyTest.AesSuccess
+ *
+ * Verifies that importing and using an HMAC key works.
+ */
+TEST_F(ImportKeyTest, HmacKeySuccess) {
+ string key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .HmacKey(key.size() * 8)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 256),
+ KeyFormat::RAW, key));
+
+ CheckCryptoParam(TAG_ALGORITHM, Algorithm::HMAC);
+ CheckCryptoParam(TAG_KEY_SIZE, 128U);
+ CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+ CheckOrigin();
+
+ string message = "Hello World!";
+ string signature = MacMessage(message, Digest::SHA_2_256, 256);
+ VerifyMessage(message, signature, AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
+}
+
+typedef KeymasterHidlTest EncryptionOperationsTest;
+
+/*
+ * EncryptionOperationsTest.RsaNoPaddingSuccess
+ *
+ * Verifies that raw RSA encryption works.
+ */
+TEST_F(EncryptionOperationsTest, RsaNoPaddingSuccess) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(1024, 3)
+ .Padding(PaddingMode::NONE)));
+
+ string message = string(1024 / 8, 'a');
+ auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
+ string ciphertext1 = EncryptMessage(message, params);
+ EXPECT_EQ(1024U / 8, ciphertext1.size());
+
+ string ciphertext2 = EncryptMessage(message, params);
+ EXPECT_EQ(1024U / 8, ciphertext2.size());
+
+ // Unpadded RSA is deterministic
+ EXPECT_EQ(ciphertext1, ciphertext2);
+}
+
+/*
+ * EncryptionOperationsTest.RsaNoPaddingShortMessage
+ *
+ * Verifies that raw RSA encryption of short messages works.
+ */
+TEST_F(EncryptionOperationsTest, RsaNoPaddingShortMessage) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(1024, 3)
+ .Padding(PaddingMode::NONE)));
+
+ string message = "1";
+ auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
+
+ string ciphertext = EncryptMessage(message, params);
+ EXPECT_EQ(1024U / 8, ciphertext.size());
+
+ string expected_plaintext = string(1024 / 8 - 1, 0) + message;
+ string plaintext = DecryptMessage(ciphertext, params);
+
+ EXPECT_EQ(expected_plaintext, plaintext);
+
+ // Degenerate case, encrypting a numeric 1 yields 0x00..01 as the ciphertext.
+ message = static_cast<char>(1);
+ ciphertext = EncryptMessage(message, params);
+ EXPECT_EQ(1024U / 8, ciphertext.size());
+ EXPECT_EQ(ciphertext, string(1024 / 8 - 1, 0) + message);
+}
+
+/*
+ * EncryptionOperationsTest.RsaNoPaddingTooLong
+ *
+ * Verifies that raw RSA encryption of too-long messages fails in the expected way.
+ */
+TEST_F(EncryptionOperationsTest, RsaNoPaddingTooLong) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(1024, 3)
+ .Padding(PaddingMode::NONE)));
+
+ string message(1024 / 8 + 1, 'a');
+
+ auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+
+ string result;
+ EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &result));
+}
+
+/*
+ * EncryptionOperationsTest.RsaNoPaddingTooLarge
+ *
+ * Verifies that raw RSA encryption of too-large (numerically) messages fails in the expected way.
+ */
+TEST_F(EncryptionOperationsTest, RsaNoPaddingTooLarge) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(1024, 3)
+ .Padding(PaddingMode::NONE)));
+
+ HidlBuf exported;
+ ASSERT_EQ(ErrorCode::OK, ExportKey(KeyFormat::X509, &exported));
+
+ const uint8_t* p = exported.data();
+ EVP_PKEY_Ptr pkey(d2i_PUBKEY(nullptr /* alloc new */, &p, exported.size()));
+ RSA_Ptr rsa(EVP_PKEY_get1_RSA(pkey.get()));
+
+ size_t modulus_len = BN_num_bytes(rsa->n);
+ ASSERT_EQ(1024U / 8, modulus_len);
+ std::unique_ptr<uint8_t[]> modulus_buf(new uint8_t[modulus_len]);
+ BN_bn2bin(rsa->n, modulus_buf.get());
+
+ // The modulus is too big to encrypt.
+ string message(reinterpret_cast<const char*>(modulus_buf.get()), modulus_len);
+
+ auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+
+ string result;
+ EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(message, &result));
+
+ // One smaller than the modulus is okay.
+ BN_sub(rsa->n, rsa->n, BN_value_one());
+ modulus_len = BN_num_bytes(rsa->n);
+ ASSERT_EQ(1024U / 8, modulus_len);
+ BN_bn2bin(rsa->n, modulus_buf.get());
+ message = string(reinterpret_cast<const char*>(modulus_buf.get()), modulus_len);
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+ EXPECT_EQ(ErrorCode::OK, Finish(message, &result));
+}
+
+/*
+ * EncryptionOperationsTest.RsaOaepSuccess
+ *
+ * Verifies that RSA-OAEP encryption operations work, with all digests.
+ */
+TEST_F(EncryptionOperationsTest, RsaOaepSuccess) {
+ auto digests = {Digest::MD5, Digest::SHA1, Digest::SHA_2_224,
+ Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512};
+
+ size_t key_size = 2048; // Need largish key for SHA-512 test.
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(key_size, 3)
+ .Padding(PaddingMode::RSA_OAEP)
+ .Digest(digests)));
+
+ string message = "Hello";
+
+ for (auto digest : digests) {
+ auto params = AuthorizationSetBuilder().Digest(digest).Padding(PaddingMode::RSA_OAEP);
+ string ciphertext1 = EncryptMessage(message, params);
+ if (HasNonfatalFailure()) std::cout << "-->" << digest << std::endl;
+ EXPECT_EQ(key_size / 8, ciphertext1.size());
+
+ string ciphertext2 = EncryptMessage(message, params);
+ EXPECT_EQ(key_size / 8, ciphertext2.size());
+
+ // OAEP randomizes padding so every result should be different (with astronomically high
+ // probability).
+ EXPECT_NE(ciphertext1, ciphertext2);
+
+ string plaintext1 = DecryptMessage(ciphertext1, params);
+ EXPECT_EQ(message, plaintext1) << "RSA-OAEP failed with digest " << digest;
+ string plaintext2 = DecryptMessage(ciphertext2, params);
+ EXPECT_EQ(message, plaintext2) << "RSA-OAEP failed with digest " << digest;
+
+ // Decrypting corrupted ciphertext should fail.
+ size_t offset_to_corrupt = random() % ciphertext1.size();
+ char corrupt_byte;
+ do {
+ corrupt_byte = static_cast<char>(random() % 256);
+ } while (corrupt_byte == ciphertext1[offset_to_corrupt]);
+ ciphertext1[offset_to_corrupt] = corrupt_byte;
+
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+ string result;
+ EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext1, &result));
+ EXPECT_EQ(0U, result.size());
+ }
+}
+
+/*
+ * EncryptionOperationsTest.RsaOaepInvalidDigest
+ *
+ * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to operate
+ * without a digest.
+ */
+TEST_F(EncryptionOperationsTest, RsaOaepInvalidDigest) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(1024, 3)
+ .Padding(PaddingMode::RSA_OAEP)
+ .Digest(Digest::NONE)));
+ string message = "Hello World!";
+
+ auto params = AuthorizationSetBuilder().Padding(PaddingMode::RSA_OAEP).Digest(Digest::NONE);
+ EXPECT_EQ(ErrorCode::INCOMPATIBLE_DIGEST, Begin(KeyPurpose::ENCRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.RsaOaepInvalidDigest
+ *
+ * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to decrypt with a
+ * different digest than was used to encrypt.
+ */
+TEST_F(EncryptionOperationsTest, RsaOaepDecryptWithWrongDigest) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(1024, 3)
+ .Padding(PaddingMode::RSA_OAEP)
+ .Digest(Digest::SHA_2_256, Digest::SHA_2_224)));
+ string message = "Hello World!";
+ string ciphertext = EncryptMessage(
+ message,
+ AuthorizationSetBuilder().Digest(Digest::SHA_2_224).Padding(PaddingMode::RSA_OAEP));
+
+ EXPECT_EQ(
+ ErrorCode::OK,
+ Begin(KeyPurpose::DECRYPT,
+ AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Padding(PaddingMode::RSA_OAEP)));
+ string result;
+ EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext, &result));
+ EXPECT_EQ(0U, result.size());
+}
+
+/*
+ * EncryptionOperationsTest.RsaOaepTooLarge
+ *
+ * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to encrypt a
+ * too-large message.
+ */
+TEST_F(EncryptionOperationsTest, RsaOaepTooLarge) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(1024, 3)
+ .Padding(PaddingMode::RSA_OAEP)
+ .Digest(Digest::SHA1)));
+ constexpr size_t digest_size = 160 /* SHA1 */ / 8;
+ constexpr size_t oaep_overhead = 2 * digest_size + 2;
+ string message(1024 / 8 - oaep_overhead + 1, 'a');
+ EXPECT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::ENCRYPT,
+ AuthorizationSetBuilder().Padding(PaddingMode::RSA_OAEP).Digest(Digest::SHA1)));
+ string result;
+ EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(message, &result));
+ EXPECT_EQ(0U, result.size());
+}
+
+/*
+ * EncryptionOperationsTest.RsaPkcs1Success
+ *
+ * Verifies that RSA PKCS encryption/decrypts works.
+ */
+TEST_F(EncryptionOperationsTest, RsaPkcs1Success) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(1024, 3)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT)));
+
+ string message = "Hello World!";
+ auto params = AuthorizationSetBuilder().Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT);
+ string ciphertext1 = EncryptMessage(message, params);
+ EXPECT_EQ(1024U / 8, ciphertext1.size());
+
+ string ciphertext2 = EncryptMessage(message, params);
+ EXPECT_EQ(1024U / 8, ciphertext2.size());
+
+ // PKCS1 v1.5 randomizes padding so every result should be different.
+ EXPECT_NE(ciphertext1, ciphertext2);
+
+ string plaintext = DecryptMessage(ciphertext1, params);
+ EXPECT_EQ(message, plaintext);
+
+ // Decrypting corrupted ciphertext should fail.
+ size_t offset_to_corrupt = random() % ciphertext1.size();
+ char corrupt_byte;
+ do {
+ corrupt_byte = static_cast<char>(random() % 256);
+ } while (corrupt_byte == ciphertext1[offset_to_corrupt]);
+ ciphertext1[offset_to_corrupt] = corrupt_byte;
+
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+ string result;
+ EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext1, &result));
+ EXPECT_EQ(0U, result.size());
+}
+
+/*
+ * EncryptionOperationsTest.RsaPkcs1TooLarge
+ *
+ * Verifies that RSA PKCS encryption fails in the correct way when the mssage is too large.
+ */
+TEST_F(EncryptionOperationsTest, RsaPkcs1TooLarge) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(1024, 3)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT)));
+ string message(1024 / 8 - 10, 'a');
+
+ auto params = AuthorizationSetBuilder().Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT);
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+ string result;
+ EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(message, &result));
+ EXPECT_EQ(0U, result.size());
+}
+
+/*
+ * EncryptionOperationsTest.EcdsaEncrypt
+ *
+ * Verifies that attempting to use ECDSA keys to encrypt fails in the correct way.
+ */
+TEST_F(EncryptionOperationsTest, EcdsaEncrypt) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(224)
+ .Digest(Digest::NONE)));
+ auto params = AuthorizationSetBuilder().Digest(Digest::NONE);
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_PURPOSE, Begin(KeyPurpose::ENCRYPT, params));
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_PURPOSE, Begin(KeyPurpose::DECRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.HmacEncrypt
+ *
+ * Verifies that attempting to use HMAC keys to encrypt fails in the correct way.
+ */
+TEST_F(EncryptionOperationsTest, HmacEncrypt) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .HmacKey(128)
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+ auto params = AuthorizationSetBuilder()
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128);
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_PURPOSE, Begin(KeyPurpose::ENCRYPT, params));
+ ASSERT_EQ(ErrorCode::UNSUPPORTED_PURPOSE, Begin(KeyPurpose::DECRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbRoundTripSuccess
+ *
+ * Verifies that AES ECB mode works.
+ */
+TEST_F(EncryptionOperationsTest, AesEcbRoundTripSuccess) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)
+ .Padding(PaddingMode::NONE)));
+
+ auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
+
+ // Two-block message.
+ string message = "12345678901234567890123456789012";
+ string ciphertext1 = EncryptMessage(message, params);
+ EXPECT_EQ(message.size(), ciphertext1.size());
+
+ string ciphertext2 = EncryptMessage(string(message), params);
+ EXPECT_EQ(message.size(), ciphertext2.size());
+
+ // ECB is deterministic.
+ EXPECT_EQ(ciphertext1, ciphertext2);
+
+ string plaintext = DecryptMessage(ciphertext1, params);
+ EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbRoundTripSuccess
+ *
+ * Verifies that AES encryption fails in the correct way when an unauthorized mode is specified.
+ */
+TEST_F(EncryptionOperationsTest, AesWrongMode) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::CBC)
+ .Padding(PaddingMode::NONE)));
+ // Two-block message.
+ string message = "12345678901234567890123456789012";
+ EXPECT_EQ(
+ ErrorCode::INCOMPATIBLE_BLOCK_MODE,
+ Begin(KeyPurpose::ENCRYPT,
+ AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE)));
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbNoPaddingWrongInputSize
+ *
+ * Verifies that AES encryption fails in the correct way when provided an input that is not a
+ * multiple of the block size and no padding is specified.
+ */
+TEST_F(EncryptionOperationsTest, AesEcbNoPaddingWrongInputSize) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)
+ .Padding(PaddingMode::NONE)));
+ // Message is slightly shorter than two blocks.
+ string message(16 * 2 - 1, 'a');
+
+ auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+ string ciphertext;
+ EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &ciphertext));
+ EXPECT_EQ(0U, ciphertext.size());
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbPkcs7Padding
+ *
+ * Verifies that AES PKCS7 padding works for any message length.
+ */
+TEST_F(EncryptionOperationsTest, AesEcbPkcs7Padding) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)
+ .Padding(PaddingMode::PKCS7)));
+
+ auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+
+ // Try various message lengths; all should work.
+ for (size_t i = 0; i < 32; ++i) {
+ string message(i, 'a');
+ string ciphertext = EncryptMessage(message, params);
+ EXPECT_EQ(i + 16 - (i % 16), ciphertext.size());
+ string plaintext = DecryptMessage(ciphertext, params);
+ EXPECT_EQ(message, plaintext);
+ }
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbWrongPadding
+ *
+ * Verifies that AES enryption fails in the correct way when an unauthorized padding mode is
+ * specified.
+ */
+TEST_F(EncryptionOperationsTest, AesEcbWrongPadding) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)
+ .Padding(PaddingMode::NONE)));
+
+ auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+
+ // Try various message lengths; all should fail
+ for (size_t i = 0; i < 32; ++i) {
+ string message(i, 'a');
+ EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, params));
+ }
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbPkcs7PaddingCorrupted
+ *
+ * Verifies that AES decryption fails in the correct way when the padding is corrupted.
+ */
+TEST_F(EncryptionOperationsTest, AesEcbPkcs7PaddingCorrupted) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)
+ .Padding(PaddingMode::PKCS7)));
+
+ auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+
+ string message = "a";
+ string ciphertext = EncryptMessage(message, params);
+ EXPECT_EQ(16U, ciphertext.size());
+ EXPECT_NE(ciphertext, message);
+ ++ciphertext[ciphertext.size() / 2];
+
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+ string plaintext;
+ EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &plaintext));
+}
+
+HidlBuf CopyIv(const AuthorizationSet& set) {
+ auto iv = set.GetTagValue(TAG_NONCE);
+ EXPECT_TRUE(iv.isOk());
+ return iv.value();
+}
+
+/*
+ * EncryptionOperationsTest.AesCtrRoundTripSuccess
+ *
+ * Verifies that AES CTR mode works.
+ */
+TEST_F(EncryptionOperationsTest, AesCtrRoundTripSuccess) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::CTR)
+ .Padding(PaddingMode::NONE)));
+
+ auto params = AuthorizationSetBuilder().BlockMode(BlockMode::CTR).Padding(PaddingMode::NONE);
+
+ string message = "123";
+ AuthorizationSet out_params;
+ string ciphertext1 = EncryptMessage(message, params, &out_params);
+ HidlBuf iv1 = CopyIv(out_params);
+ EXPECT_EQ(16U, iv1.size());
+
+ EXPECT_EQ(message.size(), ciphertext1.size());
+
+ out_params.Clear();
+ string ciphertext2 = EncryptMessage(message, params, &out_params);
+ HidlBuf iv2 = CopyIv(out_params);
+ EXPECT_EQ(16U, iv2.size());
+
+ // IVs should be random, so ciphertexts should differ.
+ EXPECT_NE(ciphertext1, ciphertext2);
+
+ auto params_iv1 =
+ AuthorizationSetBuilder().Authorizations(params).Authorization(TAG_NONCE, iv1);
+ auto params_iv2 =
+ AuthorizationSetBuilder().Authorizations(params).Authorization(TAG_NONCE, iv2);
+
+ string plaintext = DecryptMessage(ciphertext1, params_iv1);
+ EXPECT_EQ(message, plaintext);
+ plaintext = DecryptMessage(ciphertext2, params_iv2);
+ EXPECT_EQ(message, plaintext);
+
+ // Using the wrong IV will result in a "valid" decryption, but the data will be garbage.
+ plaintext = DecryptMessage(ciphertext1, params_iv2);
+ EXPECT_NE(message, plaintext);
+ plaintext = DecryptMessage(ciphertext2, params_iv1);
+ EXPECT_NE(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesIncremental
+ *
+ * Verifies that AES works, all modes, when provided data in various size increments.
+ */
+TEST_F(EncryptionOperationsTest, AesIncremental) {
+ auto block_modes = {
+ BlockMode::ECB, BlockMode::CBC, BlockMode::CTR, BlockMode::GCM,
+ };
+
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .BlockMode(block_modes)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+ for (int increment = 1; increment <= 240; ++increment) {
+ for (auto block_mode : block_modes) {
+ string message(240, 'a');
+ auto params = AuthorizationSetBuilder()
+ .BlockMode(block_mode)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128) /* for GCM */;
+
+ AuthorizationSet output_params;
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &output_params));
+
+ string ciphertext;
+ size_t input_consumed;
+ string to_send;
+ for (size_t i = 0; i < message.size(); i += increment) {
+ to_send.append(message.substr(i, increment));
+ EXPECT_EQ(ErrorCode::OK, Update(to_send, &ciphertext, &input_consumed));
+ to_send = to_send.substr(input_consumed);
+
+ switch (block_mode) {
+ case BlockMode::ECB:
+ case BlockMode::CBC:
+ // Implementations must take as many blocks as possible, leaving less than
+ // a block.
+ EXPECT_LE(to_send.length(), 16U);
+ break;
+ case BlockMode::GCM:
+ case BlockMode::CTR:
+ // Implementations must always take all the data.
+ EXPECT_EQ(0U, to_send.length());
+ break;
+ }
+ }
+ EXPECT_EQ(ErrorCode::OK, Finish(to_send, &ciphertext)) << "Error sending " << to_send;
+
+ switch (block_mode) {
+ case BlockMode::GCM:
+ EXPECT_EQ(message.size() + 16, ciphertext.size());
+ break;
+ case BlockMode::CTR:
+ EXPECT_EQ(message.size(), ciphertext.size());
+ break;
+ case BlockMode::CBC:
+ case BlockMode::ECB:
+ EXPECT_EQ(message.size() + message.size() % 16, ciphertext.size());
+ break;
+ }
+
+ auto iv = output_params.GetTagValue(TAG_NONCE);
+ switch (block_mode) {
+ case BlockMode::CBC:
+ case BlockMode::GCM:
+ case BlockMode::CTR:
+ ASSERT_TRUE(iv.isOk()) << "No IV for block mode " << block_mode;
+ EXPECT_EQ(block_mode == BlockMode::GCM ? 12U : 16U, iv.value().size());
+ params.push_back(TAG_NONCE, iv.value());
+ break;
+
+ case BlockMode::ECB:
+ EXPECT_FALSE(iv.isOk()) << "ECB mode should not generate IV";
+ break;
+ }
+
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params))
+ << "Decrypt begin() failed for block mode " << block_mode;
+
+ string plaintext;
+ for (size_t i = 0; i < ciphertext.size(); i += increment) {
+ to_send.append(ciphertext.substr(i, increment));
+ EXPECT_EQ(ErrorCode::OK, Update(to_send, &plaintext, &input_consumed));
+ to_send = to_send.substr(input_consumed);
+ }
+ ErrorCode error = Finish(to_send, &plaintext);
+ ASSERT_EQ(ErrorCode::OK, error) << "Decryption failed for block mode " << block_mode
+ << " and increment " << increment;
+ if (error == ErrorCode::OK) {
+ ASSERT_EQ(message, plaintext) << "Decryption didn't match for block mode "
+ << block_mode << " and increment " << increment;
+ }
+ }
+ }
+}
+
+struct AesCtrSp80038aTestVector {
+ const char* key;
+ const char* nonce;
+ const char* plaintext;
+ const char* ciphertext;
+};
+
+// These test vectors are taken from
+// http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf, section F.5.
+static const AesCtrSp80038aTestVector kAesCtrSp80038aTestVectors[] = {
+ // AES-128
+ {
+ "2b7e151628aed2a6abf7158809cf4f3c", "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+ "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
+ "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
+ "874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff"
+ "5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee",
+ },
+ // AES-192
+ {
+ "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b", "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+ "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
+ "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
+ "1abc932417521ca24f2b0459fe7e6e0b090339ec0aa6faefd5ccc2c6f4ce8e94"
+ "1e36b26bd1ebc670d1bd1d665620abf74f78a7f6d29809585a97daec58c6b050",
+ },
+ // AES-256
+ {
+ "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
+ "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+ "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
+ "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
+ "601ec313775789a5b7a7f504bbf3d228f443e3ca4d62b59aca84e990cacaf5c5"
+ "2b0930daa23de94ce87017ba2d84988ddfc9c58db67aada613c2dd08457941a6",
+ },
+};
+
+/*
+ * EncryptionOperationsTest.AesCtrSp80038aTestVector
+ *
+ * Verifies AES CTR implementation against SP800-38A test vectors.
+ */
+TEST_F(EncryptionOperationsTest, AesCtrSp80038aTestVector) {
+ for (size_t i = 0; i < 3; i++) {
+ const AesCtrSp80038aTestVector& test(kAesCtrSp80038aTestVectors[i]);
+ const string key = hex2str(test.key);
+ const string nonce = hex2str(test.nonce);
+ const string plaintext = hex2str(test.plaintext);
+ const string ciphertext = hex2str(test.ciphertext);
+ CheckAesCtrTestVector(key, nonce, plaintext, ciphertext);
+ }
+}
+
+/*
+ * EncryptionOperationsTest.AesCtrIncompatiblePaddingMode
+ *
+ * Verifies that keymaster rejects use of CTR mode with PKCS7 padding in the correct way.
+ */
+TEST_F(EncryptionOperationsTest, AesCtrIncompatiblePaddingMode) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::CTR)
+ .Padding(PaddingMode::PKCS7)));
+ auto params = AuthorizationSetBuilder().BlockMode(BlockMode::CTR).Padding(PaddingMode::NONE);
+ EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.AesCtrInvalidCallerNonce
+ *
+ * Verifies that keymaster fails correctly when the user supplies an incorrect-size nonce.
+ */
+TEST_F(EncryptionOperationsTest, AesCtrInvalidCallerNonce) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::CTR)
+ .Authorization(TAG_CALLER_NONCE)
+ .Padding(PaddingMode::NONE)));
+
+ auto params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::CTR)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NONCE, HidlBuf(string(1, 'a')));
+ EXPECT_EQ(ErrorCode::INVALID_NONCE, Begin(KeyPurpose::ENCRYPT, params));
+
+ params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::CTR)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NONCE, HidlBuf(string(15, 'a')));
+ EXPECT_EQ(ErrorCode::INVALID_NONCE, Begin(KeyPurpose::ENCRYPT, params));
+
+ params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::CTR)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NONCE, HidlBuf(string(17, 'a')));
+ EXPECT_EQ(ErrorCode::INVALID_NONCE, Begin(KeyPurpose::ENCRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.AesCtrInvalidCallerNonce
+ *
+ * Verifies that keymaster fails correctly when the user supplies an incorrect-size nonce.
+ */
+TEST_F(EncryptionOperationsTest, AesCbcRoundTripSuccess) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::CBC)
+ .Padding(PaddingMode::NONE)));
+ // Two-block message.
+ string message = "12345678901234567890123456789012";
+ auto params = AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+ AuthorizationSet out_params;
+ string ciphertext1 = EncryptMessage(message, params, &out_params);
+ HidlBuf iv1 = CopyIv(out_params);
+ EXPECT_EQ(message.size(), ciphertext1.size());
+
+ out_params.Clear();
+
+ string ciphertext2 = EncryptMessage(message, params, &out_params);
+ HidlBuf iv2 = CopyIv(out_params);
+ EXPECT_EQ(message.size(), ciphertext2.size());
+
+ // IVs should be random, so ciphertexts should differ.
+ EXPECT_NE(ciphertext1, ciphertext2);
+
+ params.push_back(TAG_NONCE, iv1);
+ string plaintext = DecryptMessage(ciphertext1, params);
+ EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesCallerNonce
+ *
+ * Verifies that AES caller-provided nonces work correctly.
+ */
+TEST_F(EncryptionOperationsTest, AesCallerNonce) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::CBC)
+ .Authorization(TAG_CALLER_NONCE)
+ .Padding(PaddingMode::NONE)));
+
+ string message = "12345678901234567890123456789012";
+
+ // Don't specify nonce, should get a random one.
+ AuthorizationSetBuilder params =
+ AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+ AuthorizationSet out_params;
+ string ciphertext = EncryptMessage(message, params, &out_params);
+ EXPECT_EQ(message.size(), ciphertext.size());
+ EXPECT_EQ(16U, out_params.GetTagValue(TAG_NONCE).value().size());
+
+ params.push_back(TAG_NONCE, out_params.GetTagValue(TAG_NONCE).value());
+ string plaintext = DecryptMessage(ciphertext, params);
+ EXPECT_EQ(message, plaintext);
+
+ // Now specify a nonce, should also work.
+ params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::CBC)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NONCE, HidlBuf("abcdefghijklmnop"));
+ out_params.Clear();
+ ciphertext = EncryptMessage(message, params, &out_params);
+
+ // Decrypt with correct nonce.
+ plaintext = DecryptMessage(ciphertext, params);
+ EXPECT_EQ(message, plaintext);
+
+ // Try with wrong nonce.
+ params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::CBC)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NONCE, HidlBuf("aaaaaaaaaaaaaaaa"));
+ plaintext = DecryptMessage(ciphertext, params);
+ EXPECT_NE(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesCallerNonceProhibited
+ *
+ * Verifies that caller-provided nonces are not permitted when not specified in the key
+ * authorizations.
+ */
+TEST_F(EncryptionOperationsTest, AesCallerNonceProhibited) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::CBC)
+ .Padding(PaddingMode::NONE)));
+
+ string message = "12345678901234567890123456789012";
+
+ // Don't specify nonce, should get a random one.
+ AuthorizationSetBuilder params =
+ AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+ AuthorizationSet out_params;
+ string ciphertext = EncryptMessage(message, params, &out_params);
+ EXPECT_EQ(message.size(), ciphertext.size());
+ EXPECT_EQ(16U, out_params.GetTagValue(TAG_NONCE).value().size());
+
+ params.push_back(TAG_NONCE, out_params.GetTagValue(TAG_NONCE).value());
+ string plaintext = DecryptMessage(ciphertext, params);
+ EXPECT_EQ(message, plaintext);
+
+ // Now specify a nonce, should fail
+ params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::CBC)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NONCE, HidlBuf("abcdefghijklmnop"));
+ out_params.Clear();
+ EXPECT_EQ(ErrorCode::CALLER_NONCE_PROHIBITED, Begin(KeyPurpose::ENCRYPT, params, &out_params));
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmRoundTripSuccess
+ *
+ * Verifies that AES GCM mode works.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmRoundTripSuccess) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+ string aad = "foobar";
+ string message = "123456789012345678901234567890123456";
+
+ auto begin_params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128);
+
+ auto update_params =
+ AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+ // Encrypt
+ AuthorizationSet begin_out_params;
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params))
+ << "Begin encrypt";
+ string ciphertext;
+ AuthorizationSet update_out_params;
+ ASSERT_EQ(ErrorCode::OK,
+ Finish(op_handle_, update_params, message, "", &update_out_params, &ciphertext));
+
+ // Grab nonce
+ begin_params.push_back(begin_out_params);
+
+ // Decrypt.
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params)) << "Begin decrypt";
+ string plaintext;
+ size_t input_consumed;
+ ASSERT_EQ(ErrorCode::OK, Update(op_handle_, update_params, ciphertext, &update_out_params,
+ &plaintext, &input_consumed));
+ EXPECT_EQ(ciphertext.size(), input_consumed);
+ EXPECT_EQ(ErrorCode::OK, Finish("", &plaintext));
+
+ EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmTooShortTag
+ *
+ * Verifies that AES GCM mode fails correctly when a too-short tag length is specified.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmTooShortTag) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+ string message = "123456789012345678901234567890123456";
+ auto params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 96);
+
+ EXPECT_EQ(ErrorCode::INVALID_MAC_LENGTH, Begin(KeyPurpose::ENCRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmTooShortTagOnDecrypt
+ *
+ * Verifies that AES GCM mode fails correctly when a too-short tag is provided to decryption.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmTooShortTagOnDecrypt) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+ string aad = "foobar";
+ string message = "123456789012345678901234567890123456";
+ auto params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128);
+
+ auto finish_params =
+ AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+ // Encrypt
+ AuthorizationSet begin_out_params;
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
+ EXPECT_EQ(1U, begin_out_params.size());
+ ASSERT_TRUE(begin_out_params.GetTagValue(TAG_NONCE).isOk());
+
+ AuthorizationSet finish_out_params;
+ string ciphertext;
+ EXPECT_EQ(ErrorCode::OK, Finish(op_handle_, finish_params, message, "" /* signature */,
+ &finish_out_params, &ciphertext));
+
+ params = AuthorizationSetBuilder()
+ .Authorizations(begin_out_params)
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 96);
+
+ // Decrypt.
+ EXPECT_EQ(ErrorCode::INVALID_MAC_LENGTH, Begin(KeyPurpose::DECRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmCorruptKey
+ *
+ * Verifies that AES GCM mode fails correctly when the decryption key is incorrect.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmCorruptKey) {
+ const uint8_t nonce_bytes[] = {
+ 0xb7, 0x94, 0x37, 0xae, 0x08, 0xff, 0x35, 0x5d, 0x7d, 0x8a, 0x4d, 0x0f,
+ };
+ string nonce = make_string(nonce_bytes);
+ const uint8_t ciphertext_bytes[] = {
+ 0xb3, 0xf6, 0x79, 0x9e, 0x8f, 0x93, 0x26, 0xf2, 0xdf, 0x1e, 0x80, 0xfc, 0xd2, 0xcb, 0x16,
+ 0xd7, 0x8c, 0x9d, 0xc7, 0xcc, 0x14, 0xbb, 0x67, 0x78, 0x62, 0xdc, 0x6c, 0x63, 0x9b, 0x3a,
+ 0x63, 0x38, 0xd2, 0x4b, 0x31, 0x2d, 0x39, 0x89, 0xe5, 0x92, 0x0b, 0x5d, 0xbf, 0xc9, 0x76,
+ 0x76, 0x5e, 0xfb, 0xfe, 0x57, 0xbb, 0x38, 0x59, 0x40, 0xa7, 0xa4, 0x3b, 0xdf, 0x05, 0xbd,
+ 0xda, 0xe3, 0xc9, 0xd6, 0xa2, 0xfb, 0xbd, 0xfc, 0xc0, 0xcb, 0xa0,
+ };
+ string ciphertext = make_string(ciphertext_bytes);
+
+ auto params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128)
+ .Authorization(TAG_NONCE, nonce.data(), nonce.size());
+
+ auto import_params = AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_CALLER_NONCE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128);
+
+ // Import correct key and decrypt
+ const uint8_t key_bytes[] = {
+ 0xba, 0x76, 0x35, 0x4f, 0x0a, 0xed, 0x6e, 0x8d,
+ 0x91, 0xf4, 0x5c, 0x4f, 0xf5, 0xa0, 0x62, 0xdb,
+ };
+ string key = make_string(key_bytes);
+ ASSERT_EQ(ErrorCode::OK, ImportKey(import_params, KeyFormat::RAW, key));
+ string plaintext = DecryptMessage(ciphertext, params);
+ CheckedDeleteKey();
+
+ // Corrupt key and attempt to decrypt
+ key[0] = 0;
+ ASSERT_EQ(ErrorCode::OK, ImportKey(import_params, KeyFormat::RAW, key));
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+ EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(ciphertext, &plaintext));
+ CheckedDeleteKey();
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmAadNoData
+ *
+ * Verifies that AES GCM mode works when provided additional authenticated data, but no data to
+ * encrypt.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmAadNoData) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+ string aad = "1234567890123456";
+ auto params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128);
+
+ auto finish_params =
+ AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+ // Encrypt
+ AuthorizationSet begin_out_params;
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
+ string ciphertext;
+ AuthorizationSet finish_out_params;
+ EXPECT_EQ(ErrorCode::OK, Finish(op_handle_, finish_params, "" /* input */, "" /* signature */,
+ &finish_out_params, &ciphertext));
+ EXPECT_TRUE(finish_out_params.empty());
+
+ // Grab nonce
+ params.push_back(begin_out_params);
+
+ // Decrypt.
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+ string plaintext;
+ EXPECT_EQ(ErrorCode::OK, Finish(op_handle_, finish_params, ciphertext, "" /* signature */,
+ &finish_out_params, &plaintext));
+
+ EXPECT_TRUE(finish_out_params.empty());
+
+ EXPECT_EQ("", plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmMultiPartAad
+ *
+ * Verifies that AES GCM mode works when provided additional authenticated data in multiple chunks.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmMultiPartAad) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+ string message = "123456789012345678901234567890123456";
+ auto begin_params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128);
+ AuthorizationSet begin_out_params;
+
+ auto update_params =
+ AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foo", (size_t)3);
+
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+
+ // No data, AAD only.
+ string ciphertext;
+ size_t input_consumed;
+ AuthorizationSet update_out_params;
+ EXPECT_EQ(ErrorCode::OK, Update(op_handle_, update_params, "" /* input */, &update_out_params,
+ &ciphertext, &input_consumed));
+ EXPECT_EQ(0U, input_consumed);
+ EXPECT_EQ(0U, ciphertext.size());
+ EXPECT_TRUE(update_out_params.empty());
+
+ // AAD and data.
+ EXPECT_EQ(ErrorCode::OK, Update(op_handle_, update_params, message, &update_out_params,
+ &ciphertext, &input_consumed));
+ EXPECT_EQ(message.size(), input_consumed);
+ EXPECT_EQ(message.size(), ciphertext.size());
+ EXPECT_TRUE(update_out_params.empty());
+
+ EXPECT_EQ(ErrorCode::OK, Finish("" /* input */, &ciphertext));
+
+ // Grab nonce.
+ begin_params.push_back(begin_out_params);
+
+ // Decrypt
+ update_params =
+ AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foofoo", (size_t)6);
+
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+ string plaintext;
+ EXPECT_EQ(ErrorCode::OK, Finish(op_handle_, update_params, ciphertext, "" /* signature */,
+ &update_out_params, &plaintext));
+ EXPECT_TRUE(update_out_params.empty());
+ EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmAadOutOfOrder
+ *
+ * Verifies that AES GCM mode fails correctly when given AAD after data to encipher.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmAadOutOfOrder) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+ string message = "123456789012345678901234567890123456";
+ auto begin_params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128);
+ AuthorizationSet begin_out_params;
+
+ auto update_params =
+ AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foo", (size_t)3);
+
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+
+ // No data, AAD only.
+ string ciphertext;
+ size_t input_consumed;
+ AuthorizationSet update_out_params;
+ EXPECT_EQ(ErrorCode::OK, Update(op_handle_, update_params, "" /* input */, &update_out_params,
+ &ciphertext, &input_consumed));
+ EXPECT_EQ(0U, input_consumed);
+ EXPECT_EQ(0U, ciphertext.size());
+ EXPECT_TRUE(update_out_params.empty());
+
+ // AAD and data.
+ EXPECT_EQ(ErrorCode::OK, Update(op_handle_, update_params, message, &update_out_params,
+ &ciphertext, &input_consumed));
+ EXPECT_EQ(message.size(), input_consumed);
+ EXPECT_EQ(message.size(), ciphertext.size());
+ EXPECT_TRUE(update_out_params.empty());
+
+ // More AAD
+ EXPECT_EQ(ErrorCode::INVALID_TAG, Update(op_handle_, update_params, "", &update_out_params,
+ &ciphertext, &input_consumed));
+
+ op_handle_ = kOpHandleSentinel;
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmBadAad
+ *
+ * Verifies that AES GCM decryption fails correctly when additional authenticated date is wrong.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmBadAad) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+ string message = "12345678901234567890123456789012";
+ auto begin_params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128);
+
+ auto finish_params =
+ AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foobar", (size_t)6);
+
+ // Encrypt
+ AuthorizationSet begin_out_params;
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+ string ciphertext;
+ AuthorizationSet finish_out_params;
+ EXPECT_EQ(ErrorCode::OK, Finish(op_handle_, finish_params, message, "" /* signature */,
+ &finish_out_params, &ciphertext));
+
+ // Grab nonce
+ begin_params.push_back(begin_out_params);
+
+ finish_params = AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA,
+ "barfoo" /* Wrong AAD */, (size_t)6);
+
+ // Decrypt.
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params));
+ string plaintext;
+ EXPECT_EQ(ErrorCode::VERIFICATION_FAILED,
+ Finish(op_handle_, finish_params, ciphertext, "" /* signature */, &finish_out_params,
+ &plaintext));
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmWrongNonce
+ *
+ * Verifies that AES GCM decryption fails correctly when the nonce is incorrect.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmWrongNonce) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+ string message = "12345678901234567890123456789012";
+ auto begin_params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128);
+
+ auto finish_params =
+ AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foobar", (size_t)6);
+
+ // Encrypt
+ AuthorizationSet begin_out_params;
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+ string ciphertext;
+ AuthorizationSet finish_out_params;
+ EXPECT_EQ(ErrorCode::OK, Finish(op_handle_, finish_params, message, "" /* signature */,
+ &finish_out_params, &ciphertext));
+
+ // Wrong nonce
+ begin_params.push_back(TAG_NONCE, HidlBuf("123456789012"));
+
+ // Decrypt.
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params));
+ string plaintext;
+ EXPECT_EQ(ErrorCode::VERIFICATION_FAILED,
+ Finish(op_handle_, finish_params, ciphertext, "" /* signature */, &finish_out_params,
+ &plaintext));
+
+ // With wrong nonce, should have gotten garbage plaintext (or none).
+ EXPECT_NE(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmCorruptTag
+ *
+ * Verifies that AES GCM decryption fails correctly when the tag is wrong.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmCorruptTag) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+ string aad = "1234567890123456";
+ string message = "123456789012345678901234567890123456";
+
+ auto params = AuthorizationSetBuilder()
+ .BlockMode(BlockMode::GCM)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAC_LENGTH, 128);
+
+ auto finish_params =
+ AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+ // Encrypt
+ AuthorizationSet begin_out_params;
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
+ string ciphertext;
+ AuthorizationSet finish_out_params;
+ EXPECT_EQ(ErrorCode::OK, Finish(op_handle_, finish_params, message, "" /* signature */,
+ &finish_out_params, &ciphertext));
+ EXPECT_TRUE(finish_out_params.empty());
+
+ // Corrupt tag
+ ++(*ciphertext.rbegin());
+
+ // Grab nonce
+ params.push_back(begin_out_params);
+
+ // Decrypt.
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+ string plaintext;
+ EXPECT_EQ(ErrorCode::VERIFICATION_FAILED,
+ Finish(op_handle_, finish_params, ciphertext, "" /* signature */, &finish_out_params,
+ &plaintext));
+ EXPECT_TRUE(finish_out_params.empty());
+}
+
+typedef KeymasterHidlTest MaxOperationsTest;
+
+/*
+ * MaxOperationsTest.TestLimitAes
+ *
+ * Verifies that the max uses per boot tag works correctly with AES keys.
+ */
+TEST_F(MaxOperationsTest, TestLimitAes) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .EcbMode()
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_MAX_USES_PER_BOOT, 3)));
+
+ string message = "1234567890123456";
+
+ auto params = AuthorizationSetBuilder().EcbMode().Padding(PaddingMode::NONE);
+
+ EncryptMessage(message, params);
+ EncryptMessage(message, params);
+ EncryptMessage(message, params);
+
+ // Fourth time should fail.
+ EXPECT_EQ(ErrorCode::KEY_MAX_OPS_EXCEEDED, Begin(KeyPurpose::ENCRYPT, params));
+}
+
+/*
+ * MaxOperationsTest.TestLimitAes
+ *
+ * Verifies that the max uses per boot tag works correctly with RSA keys.
+ */
+TEST_F(MaxOperationsTest, TestLimitRsa) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(1024, 3)
+ .NoDigestOrPadding()
+ .Authorization(TAG_MAX_USES_PER_BOOT, 3)));
+
+ string message = "1234567890123456";
+
+ auto params = AuthorizationSetBuilder().NoDigestOrPadding();
+
+ SignMessage(message, params);
+ SignMessage(message, params);
+ SignMessage(message, params);
+
+ // Fourth time should fail.
+ EXPECT_EQ(ErrorCode::KEY_MAX_OPS_EXCEEDED, Begin(KeyPurpose::SIGN, params));
+}
+
+typedef KeymasterHidlTest AddEntropyTest;
+
+/*
+ * AddEntropyTest.AddEntropy
+ *
+ * Verifies that the addRngEntropy method doesn't blow up. There's no way to test that entropy is
+ * actually added.
+ */
+TEST_F(AddEntropyTest, AddEntropy) {
+ EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf("foo")));
+}
+
+/*
+ * AddEntropyTest.AddEmptyEntropy
+ *
+ * Verifies that the addRngEntropy method doesn't blow up when given an empty buffer.
+ */
+TEST_F(AddEntropyTest, AddEmptyEntropy) {
+ EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf()));
+}
+
+/*
+ * AddEntropyTest.AddLargeEntropy
+ *
+ * Verifies that the addRngEntropy method doesn't blow up when given a largish amount of data.
+ */
+TEST_F(AddEntropyTest, AddLargeEntropy) {
+ EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf(string(2 * 1024, 'a'))));
+}
+
+typedef KeymasterHidlTest AttestationTest;
+
+/*
+ * AttestationTest.RsaAttestation
+ *
+ * Verifies that attesting to RSA keys works and generates the expected output.
+ */
+TEST_F(AttestationTest, RsaAttestation) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(1024, 3)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID)));
+
+ hidl_vec<hidl_vec<uint8_t>> cert_chain;
+ ASSERT_EQ(ErrorCode::OK,
+ AttestKey(AuthorizationSetBuilder()
+ .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")),
+ &cert_chain));
+ EXPECT_GE(cert_chain.size(), 2U);
+ EXPECT_TRUE(verify_chain(cert_chain));
+ EXPECT_TRUE(verify_attestation_record("challenge", "foo", //
+ key_characteristics_.softwareEnforced, //
+ key_characteristics_.hardwareEnforced, //
+ cert_chain[0]));
+}
+
+/*
+ * AttestationTest.RsaAttestationRequiresAppId
+ *
+ * Verifies that attesting to RSA requires app ID.
+ */
+TEST_F(AttestationTest, RsaAttestationRequiresAppId) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(1024, 3)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID)));
+
+ hidl_vec<hidl_vec<uint8_t>> cert_chain;
+ EXPECT_EQ(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING,
+ AttestKey(AuthorizationSetBuilder().Authorization(TAG_ATTESTATION_CHALLENGE,
+ HidlBuf("challenge")),
+ &cert_chain));
+}
+
+/*
+ * AttestationTest.EcAttestation
+ *
+ * Verifies that attesting to EC keys works and generates the expected output.
+ */
+TEST_F(AttestationTest, EcAttestation) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID)));
+
+ hidl_vec<hidl_vec<uint8_t>> cert_chain;
+ ASSERT_EQ(ErrorCode::OK,
+ AttestKey(AuthorizationSetBuilder()
+ .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")),
+ &cert_chain));
+ EXPECT_GE(cert_chain.size(), 2U);
+ EXPECT_TRUE(verify_chain(cert_chain));
+
+ EXPECT_TRUE(verify_attestation_record("challenge", "foo", //
+ key_characteristics_.softwareEnforced, //
+ key_characteristics_.hardwareEnforced, //
+ cert_chain[0]));
+}
+
+/*
+ * AttestationTest.EcAttestationRequiresAttestationAppId
+ *
+ * Verifies that attesting to EC keys requires app ID
+ */
+TEST_F(AttestationTest, EcAttestationRequiresAttestationAppId) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID)));
+
+ hidl_vec<hidl_vec<uint8_t>> cert_chain;
+ EXPECT_EQ(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING,
+ AttestKey(AuthorizationSetBuilder().Authorization(TAG_ATTESTATION_CHALLENGE,
+ HidlBuf("challenge")),
+ &cert_chain));
+}
+
+/*
+ * AttestationTest.AesAttestation
+ *
+ * Verifies that attesting to AES keys fails in the expected way.
+ */
+TEST_F(AttestationTest, AesAttestation) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .EcbMode()
+ .Padding(PaddingMode::PKCS7)));
+
+ hidl_vec<hidl_vec<uint8_t>> cert_chain;
+ EXPECT_EQ(ErrorCode::INCOMPATIBLE_ALGORITHM,
+ AttestKey(AuthorizationSetBuilder()
+ .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")),
+ &cert_chain));
+}
+
+/*
+ * AttestationTest.HmacAttestation
+ *
+ * Verifies that attesting to HMAC keys fails in the expected way.
+ */
+TEST_F(AttestationTest, HmacAttestation) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .HmacKey(128)
+ .EcbMode()
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+ hidl_vec<hidl_vec<uint8_t>> cert_chain;
+ EXPECT_EQ(ErrorCode::INCOMPATIBLE_ALGORITHM,
+ AttestKey(AuthorizationSetBuilder()
+ .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+ .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")),
+ &cert_chain));
+}
+
+typedef KeymasterHidlTest KeyDeletionTest;
+
+/**
+ * KeyDeletionTest.DeleteKey
+ *
+ * This test checks that if rollback protection is implemented, DeleteKey invalidates a formerly
+ * valid key blob.
+ *
+ * TODO(swillden): Update to incorporate changes in rollback resistance semantics.
+ */
+TEST_F(KeyDeletionTest, DeleteKey) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(1024, 3)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)));
+
+ // Delete must work if rollback protection is implemented
+ AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced);
+ bool rollback_protected = hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE);
+
+ if (rollback_protected) {
+ ASSERT_EQ(ErrorCode::OK, DeleteKey(true /* keep key blob */));
+ } else {
+ auto delete_result = DeleteKey(true /* keep key blob */);
+ ASSERT_TRUE(delete_result == ErrorCode::OK | delete_result == ErrorCode::UNIMPLEMENTED);
+ }
+
+ string message = "12345678901234567890123456789012";
+ AuthorizationSet begin_out_params;
+
+ if (rollback_protected) {
+ EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+ Begin(KeyPurpose::SIGN, key_blob_,
+ AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
+ &begin_out_params, &op_handle_));
+ } else {
+ EXPECT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::SIGN, key_blob_,
+ AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
+ &begin_out_params, &op_handle_));
+ }
+ AbortIfNeeded();
+ key_blob_ = HidlBuf();
+}
+
+/**
+ * KeyDeletionTest.DeleteInvalidKey
+ *
+ * This test checks that the HAL excepts invalid key blobs.
+ *
+ * TODO(swillden): Update to incorporate changes in rollback resistance semantics.
+ */
+TEST_F(KeyDeletionTest, DeleteInvalidKey) {
+ // Generate key just to check if rollback protection is implemented
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(1024, 3)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)));
+
+ // Delete must work if rollback protection is implemented
+ AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced);
+ bool rollback_protected = hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE);
+
+ // Delete the key we don't care about the result at this point.
+ DeleteKey();
+
+ // Now create an invalid key blob and delete it.
+ key_blob_ = HidlBuf("just some garbage data which is not a valid key blob");
+
+ if (rollback_protected) {
+ ASSERT_EQ(ErrorCode::OK, DeleteKey());
+ } else {
+ auto delete_result = DeleteKey();
+ ASSERT_TRUE(delete_result == ErrorCode::OK | delete_result == ErrorCode::UNIMPLEMENTED);
+ }
+}
+
+/**
+ * KeyDeletionTest.DeleteAllKeys
+ *
+ * This test is disarmed by default. To arm it use --arm_deleteAllKeys.
+ *
+ * BEWARE: This test has serious side effects. All user keys will be lost! This includes
+ * FBE/FDE encryption keys, which means that the device will not even boot until after the
+ * device has been wiped manually (e.g., fastboot flashall -w), and new FBE/FDE keys have
+ * been provisioned. Use this test only on dedicated testing devices that have no valuable
+ * credentials stored in Keystore/Keymaster.
+ *
+ * TODO(swillden): Update to incorporate changes in rollback resistance semantics.
+ */
+TEST_F(KeyDeletionTest, DeleteAllKeys) {
+ if (!arm_deleteAllKeys) return;
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(1024, 3)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)));
+
+ // Delete must work if rollback protection is implemented
+ AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced);
+ bool rollback_protected = hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE);
+
+ ASSERT_EQ(ErrorCode::OK, DeleteAllKeys());
+
+ string message = "12345678901234567890123456789012";
+ AuthorizationSet begin_out_params;
+
+ if (rollback_protected) {
+ EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+ Begin(KeyPurpose::SIGN, key_blob_,
+ AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
+ &begin_out_params, &op_handle_));
+ } else {
+ EXPECT_EQ(ErrorCode::OK,
+ Begin(KeyPurpose::SIGN, key_blob_,
+ AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
+ &begin_out_params, &op_handle_));
+ }
+ AbortIfNeeded();
+ key_blob_ = HidlBuf();
+}
+
+using UpgradeKeyTest = KeymasterHidlTest;
+
+/*
+ * UpgradeKeyTest.UpgradeKey
+ *
+ * Verifies that calling upgrade key on an up-to-date key works (i.e. does nothing).
+ */
+TEST_F(UpgradeKeyTest, UpgradeKey) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)));
+
+ auto result = UpgradeKey(key_blob_);
+
+ // Key doesn't need upgrading. Should get okay, but no new key blob.
+ EXPECT_EQ(result, std::make_pair(ErrorCode::OK, HidlBuf()));
+}
+
+} // namespace test
+} // namespace V4_0
+} // namespace keymaster
+} // namespace hardware
+} // namespace android
+
+using android::hardware::keymaster::V4_0::test::KeymasterHidlEnvironment;
+
+int main(int argc, char** argv) {
+ ::testing::AddGlobalTestEnvironment(KeymasterHidlEnvironment::Instance());
+ ::testing::InitGoogleTest(&argc, argv);
+ KeymasterHidlEnvironment::Instance()->init(&argc, argv);
+ for (int i = 1; i < argc; ++i) {
+ if (argv[i][0] == '-') {
+ if (std::string(argv[i]) == "--arm_deleteAllKeys") {
+ arm_deleteAllKeys = true;
+ }
+ if (std::string(argv[i]) == "--dump_attestations") {
+ dump_Attestations = true;
+ }
+ }
+ }
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
+}
diff --git a/keymaster/Android.bp b/keymaster/Android.bp
deleted file mode 100644
index 90a0195..0000000
--- a/keymaster/Android.bp
+++ /dev/null
@@ -1,5 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "3.0",
- "3.0/vts/functional",
-]
diff --git a/light/Android.bp b/light/Android.bp
deleted file mode 100644
index 654bb80..0000000
--- a/light/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "2.0",
- "2.0/default",
- "2.0/vts/functional",
-]
diff --git a/media/Android.bp b/media/Android.bp
deleted file mode 100644
index 53e82bd..0000000
--- a/media/Android.bp
+++ /dev/null
@@ -1,10 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "omx/1.0",
- "omx/1.0/vts/functional/audio",
- "omx/1.0/vts/functional/common",
- "omx/1.0/vts/functional/component",
- "omx/1.0/vts/functional/master",
- "omx/1.0/vts/functional/video",
-]
diff --git a/memtrack/Android.bp b/memtrack/Android.bp
deleted file mode 100644
index ed19a37..0000000
--- a/memtrack/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "1.0/default",
- "1.0/vts/functional",
-]
diff --git a/neuralnetworks/Android.bp b/neuralnetworks/Android.bp
deleted file mode 100644
index 33f70eb..0000000
--- a/neuralnetworks/Android.bp
+++ /dev/null
@@ -1,5 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "1.0/vts/functional",
-]
diff --git a/nfc/Android.bp b/nfc/Android.bp
deleted file mode 100644
index ed19a37..0000000
--- a/nfc/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "1.0/default",
- "1.0/vts/functional",
-]
diff --git a/oemlock/Android.bp b/oemlock/Android.bp
deleted file mode 100644
index 33f70eb..0000000
--- a/oemlock/Android.bp
+++ /dev/null
@@ -1,5 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "1.0/vts/functional",
-]
diff --git a/power/Android.bp b/power/Android.bp
deleted file mode 100644
index a5415df..0000000
--- a/power/Android.bp
+++ /dev/null
@@ -1,8 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "1.0/default",
- "1.0/vts/functional",
- "1.1",
- "1.1/vts/functional",
-]
diff --git a/radio/Android.bp b/radio/Android.bp
deleted file mode 100644
index 758de07..0000000
--- a/radio/Android.bp
+++ /dev/null
@@ -1,10 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "1.0/vts/functional",
- "1.1",
- "1.1/vts/functional",
- "1.2",
- "1.2/vts/functional",
- "deprecated/1.0",
-]
diff --git a/renderscript/Android.bp b/renderscript/Android.bp
deleted file mode 100644
index ed19a37..0000000
--- a/renderscript/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "1.0/default",
- "1.0/vts/functional",
-]
diff --git a/sensors/Android.bp b/sensors/Android.bp
deleted file mode 100644
index ed19a37..0000000
--- a/sensors/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "1.0/default",
- "1.0/vts/functional",
-]
diff --git a/soundtrigger/Android.bp b/soundtrigger/Android.bp
deleted file mode 100644
index 8d2c986..0000000
--- a/soundtrigger/Android.bp
+++ /dev/null
@@ -1,5 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "2.0",
- "2.0/vts/functional",
-]
diff --git a/tests/Android.bp b/tests/Android.bp
deleted file mode 100644
index 0031637..0000000
--- a/tests/Android.bp
+++ /dev/null
@@ -1,31 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "bar/1.0",
- "bar/1.0/default",
- "baz/1.0",
- "baz/1.0/default",
- "expression/1.0",
- "extension/light/2.0",
- "extension/light/2.0/default",
- "foo/1.0",
- "foo/1.0/default",
- "foo/1.0/default/lib",
- "hash/1.0",
- "hash/1.0/default",
- "inheritance/1.0",
- "inheritance/1.0/default",
- "libhwbinder/1.0",
- "libhwbinder/1.0/default",
- "libhwbinder/aidl",
- "memory/1.0",
- "memory/1.0/default",
- "msgq/1.0",
- "msgq/1.0/default",
- "multithread/1.0",
- "multithread/1.0/default",
- "pointer/1.0",
- "pointer/1.0/default",
- "pointer/1.0/default/lib",
- "trie/1.0",
- "trie/1.0/default",
-]
diff --git a/tests/foo/1.0/Android.bp b/tests/foo/1.0/Android.bp
index 986115c..769de2d 100644
--- a/tests/foo/1.0/Android.bp
+++ b/tests/foo/1.0/Android.bp
@@ -17,6 +17,7 @@
types: [
"Abc",
"Def",
+ "EnumIterators",
"Outer",
"Unrelated",
],
diff --git a/tetheroffload/Android.bp b/tetheroffload/Android.bp
deleted file mode 100644
index f3c7021..0000000
--- a/tetheroffload/Android.bp
+++ /dev/null
@@ -1,7 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "config/1.0",
- "config/1.0/vts/functional",
- "control/1.0",
- "control/1.0/vts/functional",
-]
diff --git a/thermal/Android.bp b/thermal/Android.bp
deleted file mode 100644
index a5415df..0000000
--- a/thermal/Android.bp
+++ /dev/null
@@ -1,8 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "1.0/default",
- "1.0/vts/functional",
- "1.1",
- "1.1/vts/functional",
-]
diff --git a/tv/Android.bp b/tv/Android.bp
deleted file mode 100644
index 58d840e..0000000
--- a/tv/Android.bp
+++ /dev/null
@@ -1,8 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "cec/1.0",
- "cec/1.0/default",
- "input/1.0",
- "input/1.0/default",
- "input/1.0/vts/functional",
-]
diff --git a/usb/1.0/default/OWNERS b/usb/1.0/default/OWNERS
new file mode 100644
index 0000000..fefae56
--- /dev/null
+++ b/usb/1.0/default/OWNERS
@@ -0,0 +1 @@
+badhri@google.com
diff --git a/usb/1.0/vts/OWNERS b/usb/1.0/vts/OWNERS
new file mode 100644
index 0000000..54f268f
--- /dev/null
+++ b/usb/1.0/vts/OWNERS
@@ -0,0 +1,3 @@
+badhri@google.com
+yim@google.com
+trong@google.com
diff --git a/usb/1.1/vts/OWNERS b/usb/1.1/vts/OWNERS
new file mode 100644
index 0000000..54f268f
--- /dev/null
+++ b/usb/1.1/vts/OWNERS
@@ -0,0 +1,3 @@
+badhri@google.com
+yim@google.com
+trong@google.com
diff --git a/usb/Android.bp b/usb/Android.bp
deleted file mode 100644
index a5415df..0000000
--- a/usb/Android.bp
+++ /dev/null
@@ -1,8 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "1.0/default",
- "1.0/vts/functional",
- "1.1",
- "1.1/vts/functional",
-]
diff --git a/vibrator/Android.bp b/vibrator/Android.bp
deleted file mode 100644
index a5415df..0000000
--- a/vibrator/Android.bp
+++ /dev/null
@@ -1,8 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "1.0/default",
- "1.0/vts/functional",
- "1.1",
- "1.1/vts/functional",
-]
diff --git a/vr/Android.bp b/vr/Android.bp
deleted file mode 100644
index ed19a37..0000000
--- a/vr/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "1.0/default",
- "1.0/vts/functional",
-]
diff --git a/weaver/Android.bp b/weaver/Android.bp
deleted file mode 100644
index 33f70eb..0000000
--- a/weaver/Android.bp
+++ /dev/null
@@ -1,5 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "1.0/vts/functional",
-]
diff --git a/wifi/Android.bp b/wifi/Android.bp
deleted file mode 100644
index efc6fa7..0000000
--- a/wifi/Android.bp
+++ /dev/null
@@ -1,13 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
- "1.0",
- "1.0/vts/functional",
- "1.1",
- "1.1/vts/functional",
- "1.2",
- "offload/1.0",
- "offload/1.0/vts/functional",
- "supplicant/1.0",
- "supplicant/1.0/vts/functional",
- "supplicant/1.1",
-]