Snap for 6199579 from 2b06348d8ff10896b859f6fe13f1a4e396dccf79 to rvc-release am: 41b4eeeafb

Original change: https://googleplex-android-review.googlesource.com/c/platform/system/keymaster/+/10303038

Change-Id: I88aef5e5a87e24928e5ec6ea18332b198a39b725
diff --git a/Android.bp b/Android.bp
index e0bcd41..b56af0f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -14,6 +14,37 @@
 
 // libkeymaster_messages contains just the code necessary to communicate with a
 // AndroidKeymaster implementation, e.g. one running in TrustZone.
+package {
+    default_applicable_licenses: ["system_keymaster_license"],
+}
+
+// Added automatically by a large-scale-change that took the approach of
+// 'apply every license found to every target'. While this makes sure we respect
+// every license restriction, it may not be entirely correct.
+//
+// e.g. GPL in an MIT project might only apply to the contrib/ directory.
+//
+// Please consider splitting the single license below into multiple licenses,
+// taking care not to lose any license_kind information, and overriding the
+// default license using the 'licenses: [...]' property on targets as needed.
+//
+// For unused files, consider creating a 'fileGroup' with "//visibility:private"
+// to attach the license to, and including a comment whether the files may be
+// used in the current project.
+// See: http://go/android-license-faq
+license {
+    name: "system_keymaster_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+        "SPDX-license-identifier-ISC",
+        "legacy_unencumbered",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_defaults {
     name: "keymaster_defaults",
     vendor_available: true,
@@ -31,6 +62,10 @@
         // Currently, if enabled, these flags will cause an internal error in Clang.
         "-fno-sanitize-coverage=edge,indirect-calls,8bit-counters,trace-cmp"
     ],
+    tidy: true,
+    tidy_checks: [
+        "-performance-noexcept-move-constructor",
+    ],
     sanitize: {
         integer_overflow: false,
     },
@@ -45,15 +80,21 @@
         "android_keymaster/keymaster_tags.cpp",
         "android_keymaster/logger.cpp",
         "android_keymaster/serializable.cpp",
-        "android_keymaster/keymaster_stl.cpp",
     ],
     header_libs: ["libhardware_headers"],
     defaults: ["keymaster_defaults" ],
     clang_cflags: [
         "-DKEYMASTER_NAME_TAGS",
     ],
-    stl: "none",
     export_include_dirs: ["include"],
+    host_supported: true,
+    target: {
+        host: {
+            clang_cflags: [
+                "-fno-rtti", // TODO(b/156427382): Remove workaround when possible.
+            ],
+        },
+    },
 }
 
 // libkeymaster_portable contains almost everything needed for a keymaster
@@ -68,11 +109,12 @@
         "android_keymaster/android_keymaster_utils.cpp",
         "android_keymaster/authorization_set.cpp",
         "android_keymaster/keymaster_enforcement.cpp",
-        "android_keymaster/keymaster_stl.cpp",
         "android_keymaster/keymaster_tags.cpp",
         "android_keymaster/logger.cpp",
         "android_keymaster/operation.cpp",
         "android_keymaster/operation_table.cpp",
+        "android_keymaster/pure_soft_secure_key_storage.cpp",
+        "android_keymaster/remote_provisioning_utils.cpp",
         "android_keymaster/serializable.cpp",
         "key_blob_utils/auth_encrypted_key_blob.cpp",
         "key_blob_utils/integrity_assured_key_blob.cpp",
@@ -86,9 +128,11 @@
         "km_openssl/attestation_record.cpp",
         "km_openssl/attestation_utils.cpp",
         "km_openssl/block_cipher_operation.cpp",
+        "km_openssl/certificate_utils.cpp",
         "km_openssl/ckdf.cpp",
         "km_openssl/ec_key.cpp",
         "km_openssl/ec_key_factory.cpp",
+        "km_openssl/ecdh_operation.cpp",
         "km_openssl/ecdsa_operation.cpp",
         "km_openssl/ecies_kem.cpp",
         "km_openssl/hkdf.cpp",
@@ -112,19 +156,22 @@
 
     shared_libs: [
         "libcrypto",
+        "libcppbor_external",
+        "libcppcose_rkp",
     ],
+    export_shared_lib_headers: ["libcppbor_external"],
     header_libs: ["libhardware_headers"],
     export_header_lib_headers: ["libhardware_headers"],
     defaults: ["keymaster_defaults" ],
-    cflags: [
-        "-DBORINGSSL_NO_CXX",
-    ],
-    // NOTE: libkeymaster_portable must run unchanged in the trusty runtime environment.
-    // Therefore, it must not link against any c++ stl library. keymaster_stl.cpp
-    // weakly defines the subset of stl symbols required for this library to work
-    // and which are also available in the trusty context.
-    stl: "none",
+    host_supported: true,
     export_include_dirs: ["include"],
+    target: {
+        host: {
+            clang_cflags: [
+                "-fno-rtti", // TODO(b/156427382): Remove workaround when possible.
+            ],
+        },
+    },
 }
 
 // libsoftkeymaster provides a software-based keymaster HAL implementation.
@@ -134,28 +181,29 @@
     name: "libsoftkeymasterdevice",
     srcs: [
         "android_keymaster/keymaster_configuration.cpp",
-        "legacy_support/ec_keymaster0_key.cpp",
+        "contexts/pure_soft_keymaster_context.cpp",
+        "contexts/pure_soft_remote_provisioning_context.cpp",
+        "contexts/soft_attestation_context.cpp",
+        "contexts/soft_keymaster_context.cpp",
+        "contexts/soft_keymaster_device.cpp",
+        "contexts/soft_keymaster_logger.cpp",
+        "km_openssl/soft_keymaster_enforcement.cpp",
         "legacy_support/ec_keymaster1_key.cpp",
         "legacy_support/ecdsa_keymaster1_operation.cpp",
-        "legacy_support/keymaster0_engine.cpp",
         "legacy_support/keymaster1_engine.cpp",
-        "legacy_support/rsa_keymaster0_key.cpp",
+        "legacy_support/keymaster1_legacy_support.cpp",
         "legacy_support/rsa_keymaster1_key.cpp",
         "legacy_support/rsa_keymaster1_operation.cpp",
-        "legacy_support/keymaster1_legacy_support.cpp",
-        "contexts/soft_attestation_cert.cpp",
-        "contexts/soft_keymaster_context.cpp",
-        "contexts/pure_soft_keymaster_context.cpp",
-        "contexts/soft_keymaster_device.cpp",
-        "km_openssl/soft_keymaster_enforcement.cpp",
-        "contexts/soft_keymaster_logger.cpp",
     ],
     defaults: ["keymaster_defaults"],
     shared_libs: [
         "libkeymaster_messages",
         "libkeymaster_portable",
+        "libsoft_attestation_cert",
         "liblog",
         "libbase",
+        "libcppbor_external",
+        "libcppcose_rkp",
         "libcrypto",
         "libcutils",
     ],
@@ -163,11 +211,26 @@
 }
 
 cc_library {
+    name: "libsoft_attestation_cert",
+    srcs: [
+        "contexts/soft_attestation_cert.cpp",
+    ],
+    defaults: ["keymaster_defaults"],
+    shared_libs: [
+        "libkeymaster_portable",
+    ],
+
+    host_supported: true,
+    export_include_dirs: ["include"],
+}
+
+cc_library {
     name: "libpuresoftkeymasterdevice",
     srcs: [
         "android_keymaster/keymaster_configuration.cpp",
-        "contexts/soft_attestation_cert.cpp",
+        "contexts/soft_attestation_context.cpp",
         "contexts/pure_soft_keymaster_context.cpp",
+        "contexts/pure_soft_remote_provisioning_context.cpp",
         "contexts/soft_keymaster_logger.cpp",
         "km_openssl/soft_keymaster_enforcement.cpp",
     ],
@@ -175,12 +238,44 @@
     shared_libs: [
         "libkeymaster_messages",
         "libkeymaster_portable",
+        "libsoft_attestation_cert",
         "liblog",
+        "libcppbor_external",
+        "libcppcose_rkp",
         "libcrypto",
         "libcutils",
         "libbase",
     ],
+    export_include_dirs: ["include"],
+}
 
+cc_library {
+    name: "libpuresoftkeymasterdevice_host",
+    srcs: [
+        "contexts/pure_soft_keymaster_context.cpp",
+        "contexts/pure_soft_remote_provisioning_context.cpp",
+        "contexts/soft_attestation_context.cpp",
+        "contexts/soft_keymaster_logger.cpp",
+        "km_openssl/soft_keymaster_enforcement.cpp",
+    ],
+    defaults: ["keymaster_defaults"],
+    host_supported: true,
+    device_supported: false,
+    shared_libs: [
+        "libkeymaster_messages",
+        "libkeymaster_portable",
+        "libsoft_attestation_cert",
+        "liblog",
+        "libcppbor_external",
+        "libcppcose_rkp",
+        "libcrypto",
+        "libcutils",
+        "libbase",
+    ],
+    clang_cflags: [
+        "-DKEYMASTER_NAME_TAGS",
+        "-fno-rtti", // TODO(b/156427382): Remove workaround when possible.
+    ],
     export_include_dirs: ["include"],
 }
 
@@ -194,13 +289,10 @@
         "contexts/keymaster2_passthrough_context.cpp",
         "ng/AndroidKeymaster3Device.cpp",
         "android_keymaster/keymaster_configuration.cpp",
-        "legacy_support/ec_keymaster0_key.cpp",
         "legacy_support/ec_keymaster1_key.cpp",
         "legacy_support/ecdsa_keymaster1_operation.cpp",
-        "legacy_support/keymaster0_engine.cpp",
         "legacy_support/keymaster1_engine.cpp",
         "legacy_support/keymaster1_legacy_support.cpp",
-        "legacy_support/rsa_keymaster0_key.cpp",
         "legacy_support/rsa_keymaster1_key.cpp",
         "legacy_support/rsa_keymaster1_operation.cpp",
     ],
@@ -213,8 +305,9 @@
         "libbase",
         "libhidlbase",
         "libkeymaster_portable",
-        "libpuresoftkeymasterdevice",
         "liblog",
+        "libpuresoftkeymasterdevice",
+        "libsoft_attestation_cert",
         "libutils",
     ],
     export_include_dirs: ["include", "ng/include"],
@@ -243,7 +336,10 @@
         "libutils",
         "libkeymaster4support",
     ],
-    export_include_dirs: ["ng/include"],
+    export_include_dirs: [
+        "ng/include",
+        "include"
+    ],
 }
 
 cc_library_shared {
@@ -272,11 +368,114 @@
     export_include_dirs: ["ng/include"],
 }
 
-// libkeymasterfiles is an empty library that exports all of the files in keymaster as includes.
-cc_library_static {
-    name: "libkeymasterfiles",
+cc_library {
+    name: "lib_android_keymaster_keymint_utils",
+    vendor_available: true,
+    srcs: [
+        "ng/KeyMintUtils.cpp",
+    ],
+    defaults: ["keymaster_defaults"],
+    shared_libs: [
+        "android.hardware.security.keymint-V1-ndk_platform",
+        "libbase",
+        "libhardware",
+    ],
     export_include_dirs: [
-        ".",
+        "ng/include",
         "include",
     ],
 }
+
+cc_library {
+    name: "libkeymint",
+    vendor_available: true,
+    srcs: [
+        "android_keymaster/keymaster_configuration.cpp",
+        "legacy_support/keymaster_passthrough_engine.cpp",
+        "legacy_support/keymaster_passthrough_key.cpp",
+        "legacy_support/keymaster_passthrough_operation.cpp",
+        "ng/AndroidKeyMintDevice.cpp",
+        "ng/AndroidKeyMintOperation.cpp",
+        "ng/AndroidRemotelyProvisionedComponentDevice.cpp",
+        "ng/AndroidSharedSecret.cpp",
+        "ng/AndroidSecureClock.cpp",
+    ],
+    defaults: ["keymaster_defaults"],
+    shared_libs: [
+	"libhidlbase",
+        "android.hardware.security.keymint-V1-ndk_platform",
+        "android.hardware.security.secureclock-V1-ndk_platform",
+        "android.hardware.security.sharedsecret-V1-ndk_platform",
+        "lib_android_keymaster_keymint_utils",
+        "libbase",
+        "libbinder_ndk",
+        "libcppbor_external",
+        "libcrypto",
+        "libcutils",
+        "libkeymaster_messages",
+        "libkeymaster_portable",
+        "liblog",
+        "libpuresoftkeymasterdevice",
+        "libutils",
+    ],
+    export_include_dirs: ["include", "ng/include"],
+}
+
+cc_library {
+    name: "libcppcose_rkp",
+    vendor_available: true,
+    host_supported: true,
+    srcs: [
+        "cppcose/cppcose.cpp",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+    shared_libs: [
+        "libcppbor_external",
+        "libcrypto",
+        "liblog",
+    ],
+}
+
+cc_defaults {
+    name: "keymaster_fuzz_defaults",
+    header_libs: ["libhardware_headers"],
+    shared_libs: [
+        "libkeymaster_messages",
+    ],
+    // Not using defaults because the fuzzer relies on sanitizers that are explicitly disabled there.
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wunused",
+        "-Wno-error=unused-const-variable",
+        "-Wno-error=unused-private-field",
+        "-Wimplicit-fallthrough",
+        "-DKEYMASTER_NAME_TAGS",
+    ],
+    host_supported: true,
+    target: {
+        host: {
+            clang_cflags: [
+                "-fno-rtti", // TODO(b/156427382): Remove when default library removes this
+            ],
+        },
+    },
+}
+
+cc_fuzz {
+    name: "libkeymaster_fuzz_buffer",
+    defaults: ["keymaster_fuzz_defaults"],
+    srcs: [
+        "tests/fuzzers/buffer_fuzz.cpp",
+    ],
+}
+
+cc_fuzz {
+    name: "libkeymaster_fuzz_serializable",
+    defaults: ["keymaster_fuzz_defaults"],
+    srcs: [
+        "tests/fuzzers/message_serializable_fuzz.cpp",
+    ],
+}
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..d97975c
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,3 @@
+third_party {
+  license_type: NOTICE
+}
diff --git a/Makefile b/Makefile
deleted file mode 100644
index fdb11ac..0000000
--- a/Makefile
+++ /dev/null
@@ -1,441 +0,0 @@
-#####
-# Local unit test Makefile
-#
-# This makefile builds and runs the keymaster unit tests locally on the development
-# machine, not on an Android device.  Android.mk builds the same tests into the
-# "keymaster_tests" binary for execution on-device, but this Makefile runs them locally,
-# for a very fast edit/build/test development cycle.
-#
-# To build and run these tests, one pre-requisite must be manually installed: BoringSSL.
-# This Makefile expects to find BoringSSL in a directory adjacent to $ANDROID_BUILD_TOP.
-# To get and build it, first install the Ninja build tool (e.g. apt-get install
-# ninja-build), then do:
-#
-# cd $ANDROID_BUILD_TOP/..
-# git clone https://boringssl.googlesource.com/boringssl
-# cd boringssl
-# mdkir build
-# cd build
-# cmake -GNinja ..
-# ninja
-#
-# Then return to $ANDROID_BUILD_TOP/system/keymaster and run "make".
-#####
-
-BASE=../..
-SUBS=system/core \
-	hardware/libhardware \
-	external/gtest \
-	system/security/softkeymaster \
-	system/security/keystore
-GTEST=$(BASE)/external/googletest/googletest
-
-INCLUDES=$(foreach dir,$(SUBS),-I $(BASE)/$(dir)/include) \
-	-I $(BASE)/libnativehelper/include/nativehelper \
-	-I $(GTEST)/include -isystem $(GTEST) -Iinclude -I$(BASE)/../boringssl/include
-
-ifdef FORCE_32_BIT
-ARCH_FLAGS = -m32
-endif
-
-ifdef USE_GCC
-CXXFLAGS +=-std=c++14 -fprofile-arcs -ftest-coverage
-CFLAGS += -fprofile-arcs -ftest-coverage
-else
-CC=$(BASE)/prebuilts/clang/host/linux-x86/clang-r370808/bin/clang
-CXX=$(BASE)/prebuilts/clang/host/linux-x86/clang-r370808/bin/clang++
-CXXFLAGS +=-std=c++14 -DKEYMASTER_CLANG_TEST_BUILD
-CFLAGS += -DKEYMASTER_CLANG_TEST_BUILD
-endif
-
-LDFLAGS += $(ARCH_FLAGS)
-CPPFLAGS = $(INCLUDES) -g -O0 -MD -MP $(ARCH_FLAGS) -DKEYMASTER_UNIT_TEST_BUILD -DHOST_BUILD
-CXXFLAGS += -Wall -Werror -Wno-unused -Winit-self -Wpointer-arith -Wunused-parameter \
-	-Werror=sign-compare -Werror=return-type -fno-permissive \
-	-Wno-deprecated-declarations -fno-exceptions -DKEYMASTER_NAME_TAGS $(ARCH_FLAGS)
-CFLAGS += $(ARCH_FLAGS) -DKEYMASTER_UNIT_TEST_BUILD -DHOST_BUILD
-
-# Uncomment to enable debug logging.
-# CXXFLAGS += -DDEBUG
-
-LDLIBS=-L$(BASE)/../boringssl/build/crypto -lcrypto -lpthread -lstdc++ -lgcov
-
-CPPSRCS=\
-	km_openssl/aes_key.cpp \
-	km_openssl/aes_operation.cpp \
-	km_openssl/triple_des_key.cpp \
-	km_openssl/triple_des_operation.cpp \
-	android_keymaster/android_keymaster.cpp \
-	android_keymaster/android_keymaster_messages.cpp \
-	tests/android_keymaster_messages_test.cpp \
-	tests/android_keymaster_test.cpp \
-	tests/android_keymaster_test_utils.cpp \
-	android_keymaster/android_keymaster_utils.cpp \
-	km_openssl/asymmetric_key.cpp \
-	km_openssl/asymmetric_key_factory.cpp \
-	km_openssl/attestation_record.cpp \
-	km_openssl/block_cipher_operation.cpp \
-	tests/attestation_record_test.cpp \
-	key_blob_utils/auth_encrypted_key_blob.cpp \
-	android_keymaster/authorization_set.cpp \
-	tests/authorization_set_test.cpp \
-	km_openssl/ec_key.cpp \
-	km_openssl/ec_key_factory.cpp \
-	legacy_support/ec_keymaster0_key.cpp \
-	legacy_support/ec_keymaster1_key.cpp \
-	legacy_support/ecdsa_keymaster1_operation.cpp \
-	km_openssl/ecdsa_operation.cpp \
-	km_openssl/ecies_kem.cpp \
-	tests/ecies_kem_test.cpp \
-	tests/gtest_main.cpp \
-	km_openssl/ckdf.cpp \
-	tests/hkdf_test.cpp \
-	km_openssl/hkdf.cpp \
-	tests/hkdf_test.cpp \
-	km_openssl/hmac.cpp \
-	km_openssl/hmac_key.cpp \
-	km_openssl/hmac_operation.cpp \
-	tests/hmac_test.cpp \
-	key_blob_utils/integrity_assured_key_blob.cpp \
-	km_openssl/iso18033kdf.cpp \
-	km_openssl/kdf.cpp \
-	tests/kdf1_test.cpp \
-	tests/kdf2_test.cpp \
-	tests/kdf_test.cpp \
-	tests/key_blob_test.cpp \
-	legacy_support/keymaster0_engine.cpp \
-	legacy_support/keymaster1_engine.cpp \
-	android_keymaster/keymaster_configuration.cpp \
-	tests/keymaster_configuration_test.cpp \
-	android_keymaster/keymaster_enforcement.cpp \
-	km_openssl/soft_keymaster_enforcement.cpp \
-	tests/keymaster_enforcement_test.cpp \
-	android_keymaster/keymaster_tags.cpp \
-	android_keymaster/logger.cpp \
-	km_openssl/nist_curve_key_exchange.cpp \
-	tests/nist_curve_key_exchange_test.cpp \
-	key_blob_utils/ocb_utils.cpp \
-	km_openssl/openssl_err.cpp \
-	km_openssl/openssl_utils.cpp \
-	android_keymaster/operation.cpp \
-	android_keymaster/operation_table.cpp \
-	km_openssl/rsa_key.cpp \
-	km_openssl/rsa_key_factory.cpp \
-	legacy_support/rsa_keymaster0_key.cpp \
-	legacy_support/rsa_keymaster1_key.cpp \
-	legacy_support/rsa_keymaster1_operation.cpp \
-	km_openssl/rsa_operation.cpp \
-	android_keymaster/serializable.cpp \
-	contexts/soft_keymaster_context.cpp \
-	contexts/soft_keymaster_device.cpp \
-	contexts/pure_soft_keymaster_context.cpp \
-	km_openssl/symmetric_key.cpp \
-	km_openssl/software_random_source.cpp \
-	contexts/soft_attestation_cert.cpp \
-	km_openssl/attestation_utils.cpp \
-	key_blob_utils/software_keyblobs.cpp \
-	km_openssl/wrapped_key.cpp
-
-CCSRCS=$(GTEST)/src/gtest-all.cc
-CSRCS=key_blob_utils/ocb.c
-
-OBJS=$(CPPSRCS:.cpp=.o) $(CCSRCS:.cc=.o) $(CSRCS:.c=.o)
-DEPS=$(CPPSRCS:.cpp=.d) $(CCSRCS:.cc=.d) $(CSRCS:.c=.d)
-
-BINARIES = \
-	tests/android_keymaster_messages_test \
-	tests/android_keymaster_test \
-	tests/attestation_record_test \
-	tests/authorization_set_test \
-	tests/ecies_kem_test \
-	tests/ckdf_test \
-	tests/hkdf_test \
-	tests/hmac_test \
-	tests/kdf1_test \
-	tests/kdf2_test \
-	tests/kdf_test \
-	tests/key_blob_test \
-	tests/keymaster_configuration_test \
-	tests/keymaster_enforcement_test \
-	tests/nist_curve_key_exchange_test
-
-.PHONY: coverage memcheck massif clean run
-
-%.run: %
-	./$<
-	touch $@
-
-run: $(BINARIES:=.run)
-
-coverage: coverage.info
-	genhtml coverage.info --output-directory coverage
-
-coverage.info: run
-	lcov --capture --directory=. --output-file coverage.info
-
-%.coverage : %
-	$(MAKE) clean && $(MAKE) $<
-	./$<
-	lcov --capture --directory=. --output-file coverage.info
-	genhtml coverage.info --output-directory coverage
-
-#UNINIT_OPTS=--track-origins=yes
-UNINIT_OPTS=--undef-value-errors=no
-
-MEMCHECK_OPTS=--leak-check=full \
-	--show-reachable=yes \
-	--vgdb=full \
-	$(UNINIT_OPTS) \
-	--error-exitcode=1 \
-	--suppressions=valgrind.supp \
-	--gen-suppressions=all
-
-MASSIF_OPTS=--tool=massif \
-	--stacks=yes
-
-%.memcheck : %
-	valgrind $(MEMCHECK_OPTS) ./$< && \
-	touch $@
-
-%.massif : %
-	valgrind $(MASSIF_OPTS) --massif-out-file=$@ ./$<
-
-memcheck: $(BINARIES:=.memcheck)
-
-massif: $(BINARIES:=.massif)
-
-GTEST_OBJS = $(GTEST)/src/gtest-all.o tests/gtest_main.o
-
-tests/keymaster_configuration_test: tests/keymaster_configuration_test.o \
-	android_keymaster/authorization_set.o \
-	android_keymaster/serializable.o \
-	android_keymaster/logger.o \
-	android_keymaster/keymaster_configuration.o \
-	$(GTEST_OBJS)
-
-tests/hmac_test: tests/hmac_test.o \
-	tests/android_keymaster_test_utils.o \
-	android_keymaster/android_keymaster_utils.o \
-	android_keymaster/authorization_set.o \
-	km_openssl/hmac.o \
-	android_keymaster/keymaster_tags.o \
-	android_keymaster/logger.o \
-	android_keymaster/serializable.o \
-	$(GTEST_OBJS)
-
-tests/ckdf_test: tests/ckdf_test.o \
-	tests/android_keymaster_test_utils.o \
-	android_keymaster/android_keymaster_utils.o \
-	android_keymaster/authorization_set.o \
-	android_keymaster/keymaster_tags.o \
-	android_keymaster/logger.o \
-	android_keymaster/serializable.o \
-	km_openssl/ckdf.o \
-	km_openssl/openssl_err.o \
-	$(GTEST_OBJS)
-
-tests/hkdf_test: tests/hkdf_test.o \
-	tests/android_keymaster_test_utils.o \
-	android_keymaster/android_keymaster_utils.o \
-	android_keymaster/authorization_set.o \
-	km_openssl/hkdf.o \
-	km_openssl/hmac.o \
-	km_openssl/kdf.o \
-	android_keymaster/keymaster_tags.o \
-	android_keymaster/logger.o \
-	android_keymaster/serializable.o \
-	$(GTEST_OBJS)
-
-tests/kdf_test: tests/kdf_test.o \
-	android_keymaster/android_keymaster_utils.o \
-	km_openssl/kdf.o \
-	android_keymaster/logger.o \
-	android_keymaster/serializable.o \
-	$(GTEST_OBJS)
-
-tests/kdf1_test: tests/kdf1_test.o \
-	tests/android_keymaster_test_utils.o \
-	android_keymaster/android_keymaster_utils.o \
-	android_keymaster/authorization_set.o \
-	km_openssl/iso18033kdf.o \
-	km_openssl/kdf.o \
-	android_keymaster/keymaster_tags.o \
-	android_keymaster/logger.o \
-	android_keymaster/serializable.o \
-	$(GTEST_OBJS)
-
-tests/kdf2_test: tests/kdf2_test.o \
-	tests/android_keymaster_test_utils.o \
-	android_keymaster/android_keymaster_utils.o \
-	android_keymaster/authorization_set.o \
-	km_openssl/iso18033kdf.o \
-	km_openssl/kdf.o \
-	android_keymaster/keymaster_tags.o \
-	android_keymaster/logger.o \
-	android_keymaster/serializable.o \
-	$(GTEST_OBJS)
-
-tests/nist_curve_key_exchange_test: tests/nist_curve_key_exchange_test.o \
-	tests/android_keymaster_test_utils.o \
-	android_keymaster/authorization_set.o \
-	android_keymaster/keymaster_tags.o \
-	android_keymaster/logger.o \
-	km_openssl/nist_curve_key_exchange.o \
-	km_openssl/openssl_err.o \
-	km_openssl/openssl_utils.o \
-	android_keymaster/serializable.o \
-	$(GTEST_OBJS)
-
-tests/ecies_kem_test: tests/ecies_kem_test.o \
-	android_keymaster/android_keymaster_utils.o \
-	tests/android_keymaster_test_utils.o \
-	android_keymaster/authorization_set.o \
-	km_openssl/ecies_kem.o \
-	km_openssl/hkdf.o \
-	km_openssl/hmac.o \
-	km_openssl/kdf.o \
-	android_keymaster/keymaster_tags.o \
-	android_keymaster/logger.o \
-	km_openssl/nist_curve_key_exchange.o \
-	km_openssl/openssl_err.o \
-	km_openssl/openssl_utils.o \
-	android_keymaster/serializable.o \
-	$(GTEST_OBJS)
-
-tests/authorization_set_test: tests/authorization_set_test.o \
-	tests/android_keymaster_test_utils.o \
-	android_keymaster/authorization_set.o \
-	android_keymaster/keymaster_tags.o \
-	android_keymaster/logger.o \
-	android_keymaster/serializable.o \
-	$(GTEST_OBJS)
-
-tests/key_blob_test: tests/key_blob_test.o \
-	tests/android_keymaster_test_utils.o \
-	android_keymaster/android_keymaster_utils.o \
-	key_blob_utils/auth_encrypted_key_blob.o \
-	android_keymaster/authorization_set.o \
-	key_blob_utils/integrity_assured_key_blob.o \
-	android_keymaster/keymaster_tags.o \
-	android_keymaster/logger.o \
-	key_blob_utils/ocb.o \
-	key_blob_utils/ocb_utils.o \
-	km_openssl/openssl_err.o \
-	android_keymaster/serializable.o \
-	$(GTEST_OBJS)
-
-tests/android_keymaster_messages_test: tests/android_keymaster_messages_test.o \
-	android_keymaster/android_keymaster_messages.o \
-	tests/android_keymaster_test_utils.o \
-	android_keymaster/android_keymaster_utils.o \
-	android_keymaster/authorization_set.o \
-	android_keymaster/keymaster_tags.o \
-	android_keymaster/logger.o \
-	android_keymaster/serializable.o \
-	$(GTEST_OBJS)
-
-tests/android_keymaster_test: tests/android_keymaster_test.o \
-	android_keymaster/android_keymaster.o \
-	android_keymaster/android_keymaster_messages.o \
-	android_keymaster/android_keymaster_utils.o \
-	android_keymaster/authorization_set.o \
-	android_keymaster/keymaster_enforcement.o \
-	android_keymaster/keymaster_tags.o \
-	android_keymaster/logger.o \
-	android_keymaster/operation.o \
-	android_keymaster/operation_table.o \
-	android_keymaster/serializable.o \
-	contexts/pure_soft_keymaster_context.o \
-	contexts/soft_attestation_cert.o \
-	contexts/soft_keymaster_context.o \
-	contexts/soft_keymaster_device.o \
-	key_blob_utils/auth_encrypted_key_blob.o \
-	key_blob_utils/integrity_assured_key_blob.o \
-	key_blob_utils/ocb.o \
-	key_blob_utils/ocb_utils.o \
-	key_blob_utils/software_keyblobs.o \
-	km_openssl/aes_key.o \
-	km_openssl/aes_key.o \
-	km_openssl/aes_operation.o \
-	km_openssl/aes_operation.o \
-	km_openssl/asymmetric_key.o \
-	km_openssl/asymmetric_key_factory.o \
-	km_openssl/attestation_record.o \
-	km_openssl/attestation_utils.o \
-	km_openssl/block_cipher_operation.o \
-	km_openssl/ckdf.o \
-	km_openssl/ec_key.o \
-	km_openssl/ec_key_factory.o \
-	km_openssl/ecdsa_operation.o \
-	km_openssl/hmac_key.o \
-	km_openssl/hmac_operation.o \
-	km_openssl/openssl_err.o \
-	km_openssl/openssl_utils.o \
-	km_openssl/rsa_key.o \
-	km_openssl/rsa_key_factory.o \
-	km_openssl/rsa_operation.o \
-	km_openssl/soft_keymaster_enforcement.o \
-	km_openssl/software_random_source.o \
-	km_openssl/symmetric_key.o \
-	km_openssl/triple_des_key.o \
-	km_openssl/triple_des_operation.o \
-	km_openssl/wrapped_key.o \
-	legacy_support/ec_keymaster0_key.o \
-	legacy_support/ec_keymaster1_key.o \
-	legacy_support/ecdsa_keymaster1_operation.o \
-	legacy_support/keymaster0_engine.o \
-	legacy_support/keymaster1_engine.o \
-	legacy_support/rsa_keymaster0_key.o \
-	legacy_support/rsa_keymaster1_key.o \
-	legacy_support/rsa_keymaster1_operation.o \
-	tests/android_keymaster_test_utils.o \
-	$(BASE)/system/security/keystore/keyblob_utils.o \
-	$(GTEST_OBJS)
-
-tests/keymaster_enforcement_test: tests/keymaster_enforcement_test.o \
-	android_keymaster/android_keymaster_messages.o \
-	tests/android_keymaster_test_utils.o \
-	android_keymaster/android_keymaster_utils.o \
-	android_keymaster/authorization_set.o \
-	android_keymaster/keymaster_enforcement.o \
-	km_openssl/ckdf.o \
-	km_openssl/openssl_err.o \
-	km_openssl/soft_keymaster_enforcement.o \
-	android_keymaster/keymaster_tags.o \
-	android_keymaster/logger.o \
-	android_keymaster/serializable.o \
-	$(GTEST_OBJS)
-
-tests/attestation_record_test: tests/attestation_record_test.o \
-	tests/android_keymaster_test_utils.o \
-	android_keymaster/android_keymaster_utils.o \
-	km_openssl/attestation_record.o \
-	android_keymaster/authorization_set.o \
-	android_keymaster/keymaster_tags.o \
-	android_keymaster/logger.o \
-	km_openssl/openssl_err.o \
-	android_keymaster/serializable.o \
-	$(GTEST_OBJS)
-
-tests/wrapped_key_test: tests/wrapped_key_test.o \
-	tests/android_keymaster_test_utils.o \
-	android_keymaster/android_keymaster_utils.o \
-	km_openssl/attestation_record.o \
-	android_keymaster/authorization_set.o \
-	android_keymaster/keymaster_tags.o \
-	android_keymaster/logger.o \
-	km_openssl/openssl_err.o \
-	android_keymaster/serializable.o \
-	km_openssl/wrapped_key.o \
-	$(GTEST_OBJS)
-
-$(GTEST)/src/gtest-all.o: CXXFLAGS:=$(subst -Wmissing-declarations,,$(CXXFLAGS))
-
-clean:
-	rm -f $(OBJS) $(DEPS) $(BINARIES) \
-		$(BINARIES:=.run) $(BINARIES:=.memcheck) $(BINARIES:=.massif) \
-		*gcov *gcno *gcda coverage.info
-	rm -rf coverage
-
--include $(CPPSRCS:.cpp=.d)
--include $(CCSRCS:.cc=.d)
diff --git a/OWNERS b/OWNERS
index c1c7bb8..2b2ad2a 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,4 +1,4 @@
-cbrubaker@google.com
+jbires@google.com
 jdanis@google.com
-kroot@google.com
 swillden@google.com
+zeuthen@google.com
\ No newline at end of file
diff --git a/android_keymaster/android_keymaster.cpp b/android_keymaster/android_keymaster.cpp
index 195a797..00fa837 100644
--- a/android_keymaster/android_keymaster.cpp
+++ b/android_keymaster/android_keymaster.cpp
@@ -16,28 +16,61 @@
 
 #include <keymaster/android_keymaster.h>
 
+#include <vector>
+
 #include <assert.h>
 #include <string.h>
 
 #include <stddef.h>
 
+#include <cppbor.h>
+#include <cppbor_parse.h>
+
 #include <keymaster/UniquePtr.h>
 #include <keymaster/android_keymaster_utils.h>
+#include <keymaster/cppcose/cppcose.h>
 #include <keymaster/key.h>
 #include <keymaster/key_blob_utils/ae.h>
 #include <keymaster/key_factory.h>
 #include <keymaster/keymaster_context.h>
+#include <keymaster/km_date.h>
 #include <keymaster/km_openssl/openssl_err.h>
+#include <keymaster/km_openssl/openssl_utils.h>
+#include <keymaster/logger.h>
 #include <keymaster/operation.h>
 #include <keymaster/operation_table.h>
+#include <keymaster/remote_provisioning_utils.h>
 
 namespace keymaster {
 
 namespace {
 
-const uint8_t MAJOR_VER = 2;
-const uint8_t MINOR_VER = 0;
-const uint8_t SUBMINOR_VER = 0;
+using cppcose::constructCoseEncrypt;
+using cppcose::constructCoseMac0;
+using cppcose::constructCoseSign1;
+using cppcose::CoseKey;
+using cppcose::EC2;
+using cppcose::ES256;
+using cppcose::generateCoseMac0Mac;
+using cppcose::kAesGcmNonceLength;
+using cppcose::P256;
+using cppcose::x25519_HKDF_DeriveKey;
+
+template <keymaster_tag_t T>
+keymaster_error_t CheckPatchLevel(const AuthorizationSet& tee_enforced,
+                                  const AuthorizationSet& sw_enforced, TypedTag<KM_UINT, T> tag,
+                                  uint32_t current_patchlevel) {
+    uint32_t key_patchlevel;
+    if (tee_enforced.GetTagValue(tag, &key_patchlevel) ||
+        sw_enforced.GetTagValue(tag, &key_patchlevel)) {
+        if (key_patchlevel < current_patchlevel) {
+            return KM_ERROR_KEY_REQUIRES_UPGRADE;
+        } else if (key_patchlevel > current_patchlevel) {
+            return KM_ERROR_INVALID_KEY_BLOB;
+        }
+    }
+    return KM_ERROR_OK;
+}
 
 keymaster_error_t CheckVersionInfo(const AuthorizationSet& tee_enforced,
                                    const AuthorizationSet& sw_enforced,
@@ -46,22 +79,61 @@
     uint32_t os_patchlevel;
     context.GetSystemVersion(&os_version, &os_patchlevel);
 
-    uint32_t key_os_patchlevel;
-    if (tee_enforced.GetTagValue(TAG_OS_PATCHLEVEL, &key_os_patchlevel) ||
-        sw_enforced.GetTagValue(TAG_OS_PATCHLEVEL, &key_os_patchlevel)) {
-        if (key_os_patchlevel < os_patchlevel)
-            return KM_ERROR_KEY_REQUIRES_UPGRADE;
-        else if (key_os_patchlevel > os_patchlevel)
-            return KM_ERROR_INVALID_KEY_BLOB;
+    keymaster_error_t err =
+        CheckPatchLevel(tee_enforced, sw_enforced, TAG_OS_PATCHLEVEL, os_patchlevel);
+    if (err != KM_ERROR_OK) return err;
+
+    // Also check the vendor and boot patchlevels if available.
+    auto vendor_patchlevel = context.GetVendorPatchlevel();
+    if (vendor_patchlevel.has_value()) {
+        err = CheckPatchLevel(tee_enforced, sw_enforced, TAG_VENDOR_PATCHLEVEL,
+                              vendor_patchlevel.value());
+        if (err != KM_ERROR_OK) return err;
+    }
+    auto boot_patchlevel = context.GetBootPatchlevel();
+    if (boot_patchlevel.has_value()) {
+        err = CheckPatchLevel(tee_enforced, sw_enforced, TAG_BOOT_PATCHLEVEL,
+                              boot_patchlevel.value());
+        if (err != KM_ERROR_OK) return err;
     }
 
     return KM_ERROR_OK;
 }
 
+const keymaster_key_param_t kKeyMintEcdsaP256Params[] = {
+    Authorization(TAG_PURPOSE, KM_PURPOSE_ATTEST_KEY),
+    Authorization(TAG_ALGORITHM, KM_ALGORITHM_EC), Authorization(TAG_KEY_SIZE, 256),
+    Authorization(TAG_DIGEST, KM_DIGEST_SHA_2_256), Authorization(TAG_EC_CURVE, KM_EC_CURVE_P_256),
+    Authorization(TAG_NO_AUTH_REQUIRED),
+    // The certificate generated by KM will be discarded, these values don't matter.
+    Authorization(TAG_CERTIFICATE_NOT_BEFORE, 0), Authorization(TAG_CERTIFICATE_NOT_AFTER, 0)};
+
+cppcose::HmacSha256Function getMacFunction(bool test_mode,
+                                           RemoteProvisioningContext* rem_prov_ctx) {
+    if (test_mode) {
+        return [](const cppcose::bytevec& input) {
+            const cppcose::bytevec macKey(32);
+            return cppcose::generateHmacSha256(macKey, input);
+        };
+    }
+
+    return [rem_prov_ctx](const cppcose::bytevec& input) -> cppcose::ErrMsgOr<cppcose::HmacSha256> {
+        auto mac = rem_prov_ctx->GenerateHmacSha256(input);
+        if (!mac) {
+            return "Remote provisioning context failed to sign MAC.";
+        }
+        return *mac;
+    };
+}
+
+constexpr int kP256AffinePointSize = 32;
+
 }  // anonymous namespace
 
-AndroidKeymaster::AndroidKeymaster(KeymasterContext* context, size_t operation_table_size)
-    : context_(context), operation_table_(new(std::nothrow) OperationTable(operation_table_size)) {}
+AndroidKeymaster::AndroidKeymaster(KeymasterContext* context, size_t operation_table_size,
+                                   uint32_t message_version)
+    : context_(context), operation_table_(new (std::nothrow) OperationTable(operation_table_size)),
+      message_version_(message_version) {}
 
 AndroidKeymaster::~AndroidKeymaster() {}
 
@@ -85,30 +157,41 @@
 }
 
 void AndroidKeymaster::GetVersion(const GetVersionRequest&, GetVersionResponse* rsp) {
-    if (rsp == nullptr)
-        return;
+    if (rsp == nullptr) return;
 
-    rsp->major_ver = MAJOR_VER;
-    rsp->minor_ver = MINOR_VER;
-    rsp->subminor_ver = SUBMINOR_VER;
+    rsp->major_ver = 2;
+    rsp->minor_ver = 0;
+    rsp->subminor_ver = 0;
     rsp->error = KM_ERROR_OK;
 }
 
+GetVersion2Response AndroidKeymaster::GetVersion2(const GetVersion2Request& req) {
+    GetVersion2Response rsp;
+    rsp.km_version = context_->GetKmVersion();
+    rsp.km_date = kKmDate;
+    rsp.max_message_version = MessageVersion(rsp.km_version, rsp.km_date);
+    rsp.error = KM_ERROR_OK;
+
+    // Determine what message version we should use.
+    message_version_ = NegotiateMessageVersion(req, rsp);
+
+    LOG_D("GetVersion2 results: %d, %d, %d, %d", rsp.km_version, rsp.km_date,
+          rsp.max_message_version, message_version_);
+    return rsp;
+}
+
 void AndroidKeymaster::SupportedAlgorithms(const SupportedAlgorithmsRequest& /* request */,
                                            SupportedAlgorithmsResponse* response) {
-    if (response == nullptr)
-        return;
+    if (response == nullptr) return;
 
     response->error = KM_ERROR_OK;
 
     size_t algorithm_count = 0;
     const keymaster_algorithm_t* algorithms = context_->GetSupportedAlgorithms(&algorithm_count);
-    if (algorithm_count == 0)
-        return;
+    if (algorithm_count == 0) return;
     response->results_length = algorithm_count;
     response->results = dup_array(algorithms, algorithm_count);
-    if (!response->results)
-        response->error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!response->results) response->error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
 }
 
 template <typename T>
@@ -116,8 +199,7 @@
                   keymaster_purpose_t purpose,
                   const T* (OperationFactory::*get_supported_method)(size_t* count) const,
                   SupportedResponse<T>* response) {
-    if (response == nullptr || !check_supported(context, algorithm, response))
-        return;
+    if (response == nullptr || !check_supported(context, algorithm, response)) return;
 
     const OperationFactory* factory = context.GetOperationFactory(algorithm, purpose);
     if (!factory) {
@@ -150,8 +232,7 @@
 
 void AndroidKeymaster::SupportedImportFormats(const SupportedImportFormatsRequest& request,
                                               SupportedImportFormatsResponse* response) {
-    if (response == nullptr || !check_supported(*context_, request.algorithm, response))
-        return;
+    if (response == nullptr || !check_supported(*context_, request.algorithm, response)) return;
 
     size_t count;
     const keymaster_key_format_t* formats =
@@ -161,8 +242,7 @@
 
 void AndroidKeymaster::SupportedExportFormats(const SupportedExportFormatsRequest& request,
                                               SupportedExportFormatsResponse* response) {
-    if (response == nullptr || !check_supported(*context_, request.algorithm, response))
-        return;
+    if (response == nullptr || !check_supported(*context_, request.algorithm, response)) return;
 
     size_t count;
     const keymaster_key_format_t* formats =
@@ -171,7 +251,7 @@
 }
 
 GetHmacSharingParametersResponse AndroidKeymaster::GetHmacSharingParameters() {
-    GetHmacSharingParametersResponse response;
+    GetHmacSharingParametersResponse response(message_version());
     KeymasterEnforcement* policy = context_->enforcement_policy();
     if (!policy) {
         response.error = KM_ERROR_UNIMPLEMENTED;
@@ -184,14 +264,14 @@
 
 ComputeSharedHmacResponse
 AndroidKeymaster::ComputeSharedHmac(const ComputeSharedHmacRequest& request) {
-    ComputeSharedHmacResponse response;
+    ComputeSharedHmacResponse response(message_version());
     KeymasterEnforcement* policy = context_->enforcement_policy();
     if (!policy) {
         response.error = KM_ERROR_UNIMPLEMENTED;
         return response;
     }
-
     response.error = policy->ComputeSharedHmac(request.params_array, &response.sharing_check);
+
     return response;
 }
 
@@ -199,7 +279,7 @@
 AndroidKeymaster::VerifyAuthorization(const VerifyAuthorizationRequest& request) {
     KeymasterEnforcement* policy = context_->enforcement_policy();
     if (!policy) {
-        VerifyAuthorizationResponse response;
+        VerifyAuthorizationResponse response(message_version());
         response.error = KM_ERROR_UNIMPLEMENTED;
         return response;
     }
@@ -207,45 +287,245 @@
     return policy->VerifyAuthorization(request);
 }
 
+void AndroidKeymaster::GenerateTimestampToken(GenerateTimestampTokenRequest& request,
+                                              GenerateTimestampTokenResponse* response) {
+    KeymasterEnforcement* policy = context_->enforcement_policy();
+    if (!policy) {
+        response->error = KM_ERROR_UNIMPLEMENTED;
+    } else {
+        response->token.challenge = request.challenge;
+        response->error = policy->GenerateTimestampToken(&response->token);
+    }
+}
+
 void AndroidKeymaster::AddRngEntropy(const AddEntropyRequest& request,
                                      AddEntropyResponse* response) {
     response->error = context_->AddRngEntropy(request.random_data.peek_read(),
                                               request.random_data.available_read());
 }
 
+const KeyFactory* get_key_factory(const AuthorizationSet& key_description,
+                                  const KeymasterContext& context,  //
+                                  keymaster_error_t* error) {
+    keymaster_algorithm_t algorithm;
+    const KeyFactory* factory{};
+    if (!key_description.GetTagValue(TAG_ALGORITHM, &algorithm) ||
+        !(factory = context.GetKeyFactory(algorithm))) {
+        *error = KM_ERROR_UNSUPPORTED_ALGORITHM;
+    }
+    return factory;
+}
+
 void AndroidKeymaster::GenerateKey(const GenerateKeyRequest& request,
                                    GenerateKeyResponse* response) {
-    if (response == nullptr)
-        return;
+    if (response == nullptr) return;
 
-    keymaster_algorithm_t algorithm;
-    const KeyFactory* factory = nullptr;
-    UniquePtr<Key> key;
-    if (!request.key_description.GetTagValue(TAG_ALGORITHM, &algorithm) ||
-        !(factory = context_->GetKeyFactory(algorithm)))
-        response->error = KM_ERROR_UNSUPPORTED_ALGORITHM;
-    else {
-        KeymasterKeyBlob key_blob;
-        response->enforced.Clear();
-        response->unenforced.Clear();
-        response->error = factory->GenerateKey(request.key_description, &key_blob,
-                                               &response->enforced, &response->unenforced);
-        if (response->error == KM_ERROR_OK)
-            response->key_blob = key_blob.release();
+    const KeyFactory* factory =
+        get_key_factory(request.key_description, *context_, &response->error);
+    if (!factory) return;
+
+    UniquePtr<Key> attest_key;
+    if (request.attestation_signing_key_blob.key_material_size) {
+        attest_key = LoadKey(request.attestation_signing_key_blob, request.attest_key_params,
+                             &response->error);
+        if (response->error != KM_ERROR_OK) return;
     }
+
+    response->enforced.Clear();
+    response->unenforced.Clear();
+    response->error = factory->GenerateKey(request.key_description,
+                                           move(attest_key),  //
+                                           request.issuer_subject,
+                                           &response->key_blob,  //
+                                           &response->enforced,
+                                           &response->unenforced,  //
+                                           &response->certificate_chain);
+}
+
+void AndroidKeymaster::GenerateRkpKey(const GenerateRkpKeyRequest& request,
+                                      GenerateRkpKeyResponse* response) {
+    if (response == nullptr) return;
+
+    auto rem_prov_ctx = context_->GetRemoteProvisioningContext();
+    if (rem_prov_ctx == nullptr) {
+        response->error = static_cast<keymaster_error_t>(kStatusFailed);
+        return;
+    }
+
+    // Generate the keypair that will become the attestation key.
+    GenerateKeyRequest gen_key_request(message_version_);
+    gen_key_request.key_description.Reinitialize(kKeyMintEcdsaP256Params,
+                                                 array_length(kKeyMintEcdsaP256Params));
+    GenerateKeyResponse gen_key_response(message_version_);
+    GenerateKey(gen_key_request, &gen_key_response);
+    if (gen_key_response.error != KM_ERROR_OK) {
+        response->error = static_cast<keymaster_error_t>(kStatusFailed);
+        return;
+    }
+
+    // Retrieve the certificate and parse it to build a COSE_Key
+    if (gen_key_response.certificate_chain.entry_count != 1) {
+        // Error: Need the single non-signed certificate with the public key in it.
+        response->error = static_cast<keymaster_error_t>(kStatusFailed);
+        return;
+    }
+    std::vector<uint8_t> x_coord(kP256AffinePointSize);
+    std::vector<uint8_t> y_coord(kP256AffinePointSize);
+    response->error =
+        GetEcdsa256KeyFromCert(gen_key_response.certificate_chain.begin(), x_coord.data(),
+                               x_coord.size(), y_coord.data(), y_coord.size());
+    if (response->error != KM_ERROR_OK) {
+        response->error = static_cast<keymaster_error_t>(kStatusFailed);
+        return;
+    }
+
+    cppbor::Map cose_public_key_map = cppbor::Map()
+                                          .add(CoseKey::KEY_TYPE, EC2)
+                                          .add(CoseKey::ALGORITHM, ES256)
+                                          .add(CoseKey::CURVE, P256)
+                                          .add(CoseKey::PUBKEY_X, x_coord)
+                                          .add(CoseKey::PUBKEY_Y, y_coord);
+    if (request.test_mode) {
+        cose_public_key_map.add(CoseKey::TEST_KEY, cppbor::Null());
+    }
+
+    std::vector<uint8_t> cosePublicKey = cose_public_key_map.canonicalize().encode();
+
+    auto macFunction = getMacFunction(request.test_mode, rem_prov_ctx);
+    auto macedKey = constructCoseMac0(macFunction, {} /* externalAad */, cosePublicKey);
+    if (!macedKey) {
+        response->error = static_cast<keymaster_error_t>(kStatusFailed);
+        return;
+    }
+    std::vector<uint8_t> enc = macedKey->encode();
+    response->maced_public_key = KeymasterBlob(enc.data(), enc.size());
+    response->key_blob = std::move(gen_key_response.key_blob);
+    response->error = KM_ERROR_OK;
+}
+
+void AndroidKeymaster::GenerateCsr(const GenerateCsrRequest& request,
+                                   GenerateCsrResponse* response) {
+    if (response == nullptr) return;
+
+    auto rem_prov_ctx = context_->GetRemoteProvisioningContext();
+    if (rem_prov_ctx == nullptr) {
+        LOG_E("Couldn't get a pointer to the remote provisioning context, returned null.", 0);
+        response->error = static_cast<keymaster_error_t>(kStatusFailed);
+        return;
+    }
+
+    auto macFunction = getMacFunction(request.test_mode, rem_prov_ctx);
+    auto pubKeysToSign = validateAndExtractPubkeys(request.test_mode, request.num_keys,
+                                                   request.keys_to_sign_array, macFunction);
+    if (!pubKeysToSign.isOk()) {
+        LOG_E("Failed to validate and extract the public keys for the CSR", 0);
+        response->error = static_cast<keymaster_error_t>(pubKeysToSign.moveError());
+        return;
+    }
+
+    std::vector<uint8_t> ephemeral_mac_key(SHA256_DIGEST_LENGTH, 0 /* value */);
+    if (GenerateRandom(ephemeral_mac_key.data(), ephemeral_mac_key.size()) != KM_ERROR_OK) {
+        LOG_E("Failed to generate a random mac key.", 0);
+        response->error = static_cast<keymaster_error_t>(kStatusFailed);
+        return;
+    }
+
+    auto ephemeral_mac_function = [&ephemeral_mac_key](const cppcose::bytevec& input) {
+        return cppcose::generateHmacSha256(ephemeral_mac_key, input);
+    };
+
+    auto pubKeysToSignMac =
+        generateCoseMac0Mac(ephemeral_mac_function, std::vector<uint8_t>{}, *pubKeysToSign);
+    if (!pubKeysToSignMac) {
+        LOG_E("Failed to generate COSE_Mac0 over the public keys to sign.", 0);
+        response->error = static_cast<keymaster_error_t>(kStatusFailed);
+        return;
+    }
+    response->keys_to_sign_mac = KeymasterBlob(pubKeysToSignMac->data(), pubKeysToSignMac->size());
+
+    std::vector<uint8_t> devicePrivKey;
+    cppbor::Array bcc;
+    if (request.test_mode) {
+        std::tie(devicePrivKey, bcc) = rem_prov_ctx->GenerateBcc(/*testMode=*/true);
+    } else {
+        devicePrivKey = rem_prov_ctx->devicePrivKey_;
+        auto clone = rem_prov_ctx->bcc_.clone();
+        if (!clone->asArray()) {
+            LOG_E("The BCC is not an array.", 0);
+            response->error = static_cast<keymaster_error_t>(kStatusFailed);
+            return;
+        }
+        bcc = std::move(*clone->asArray());
+    }
+    std::unique_ptr<cppbor::Map> device_info_map = rem_prov_ctx->CreateDeviceInfo();
+    std::vector<uint8_t> device_info = device_info_map->encode();
+    response->device_info_blob = KeymasterBlob(device_info.data(), device_info.size());
+    auto signedMac =
+        constructCoseSign1(devicePrivKey /* Signing key */,  //
+                           ephemeral_mac_key /* Payload */,
+                           cppbor::Array() /* AAD */
+                               .add(std::pair(request.challenge.begin(),
+                                              request.challenge.end() - request.challenge.begin()))
+                               .add(std::move(device_info_map))
+                               .add(std::pair(pubKeysToSignMac->data(), pubKeysToSignMac->size()))
+                               .encode());
+    if (!signedMac) {
+        LOG_E("Failed to construct COSE_Sign1 over the ephemeral mac key.", 0);
+        response->error = static_cast<keymaster_error_t>(kStatusFailed);
+        return;
+    }
+
+    std::vector<uint8_t> ephemeralPrivKey(X25519_PRIVATE_KEY_LEN);
+    std::vector<uint8_t> ephemeralPubKey(X25519_PUBLIC_VALUE_LEN);
+    X25519_keypair(ephemeralPubKey.data(), ephemeralPrivKey.data());
+
+    auto eek = validateAndExtractEekPubAndId(request.test_mode, request.endpoint_enc_cert_chain);
+    if (!eek.isOk()) {
+        LOG_E("Failed to validate and extract the endpoint encryption key.", 0);
+        response->error = static_cast<keymaster_error_t>(eek.moveError());
+        return;
+    }
+
+    auto sessionKey =
+        x25519_HKDF_DeriveKey(ephemeralPubKey, ephemeralPrivKey, eek->first, true /* senderIsA */);
+    if (!sessionKey) {
+        LOG_E("Failed to derive the session key.", 0);
+        response->error = static_cast<keymaster_error_t>(kStatusFailed);
+        return;
+    }
+
+    std::vector<uint8_t> nonce(kAesGcmNonceLength, 0 /* value */);
+    if (GenerateRandom(nonce.data(), nonce.size()) != KM_ERROR_OK) {
+        LOG_E("Failed to generate a random nonce.", 0);
+        response->error = static_cast<keymaster_error_t>(kStatusFailed);
+        return;
+    }
+    auto coseEncrypted = constructCoseEncrypt(*sessionKey, nonce,
+                                              cppbor::Array()  // payload
+                                                  .add(signedMac.moveValue())
+                                                  .add(std::move(bcc))
+                                                  .encode(),
+                                              {},  // aad
+                                              buildCertReqRecipients(ephemeralPubKey, eek->second));
+
+    if (!coseEncrypted) {
+        LOG_E("Failed to construct a COSE_Encrypt ProtectedData structure", 0);
+        response->error = static_cast<keymaster_error_t>(kStatusFailed);
+        return;
+    }
+    std::vector<uint8_t> payload = coseEncrypted->encode();
+    response->protected_data_blob = KeymasterBlob(payload.data(), payload.size());
+    response->error = KM_ERROR_OK;
 }
 
 void AndroidKeymaster::GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
                                              GetKeyCharacteristicsResponse* response) {
-    if (response == nullptr)
-        return;
+    if (response == nullptr) return;
 
     UniquePtr<Key> key;
     response->error =
-        context_->ParseKeyBlob(KeymasterKeyBlob(request.key_blob), request.additional_params,
-                               &key);
-    if (response->error != KM_ERROR_OK)
-        return;
+        context_->ParseKeyBlob(KeymasterKeyBlob(request.key_blob), request.additional_params, &key);
+    if (response->error != KM_ERROR_OK) return;
 
     // scavenge the key object for the auth lists
     response->enforced = move(key->hw_enforced());
@@ -256,29 +536,31 @@
 
 void AndroidKeymaster::BeginOperation(const BeginOperationRequest& request,
                                       BeginOperationResponse* response) {
-    if (response == nullptr)
-        return;
+    if (response == nullptr) return;
     response->op_handle = 0;
 
-    const KeyFactory* key_factory;
-    UniquePtr<Key> key;
-    response->error = LoadKey(request.key_blob, request.additional_params, &key_factory, &key);
-    if (response->error != KM_ERROR_OK)
-        return;
+    UniquePtr<Key> key = LoadKey(request.key_blob, request.additional_params, &response->error);
+    if (!key) return;
 
     response->error = KM_ERROR_UNKNOWN_ERROR;
     keymaster_algorithm_t key_algorithm;
-    if (!key->authorizations().GetTagValue(TAG_ALGORITHM, &key_algorithm))
-        return;
+    if (!key->authorizations().GetTagValue(TAG_ALGORITHM, &key_algorithm)) return;
 
     response->error = KM_ERROR_UNSUPPORTED_PURPOSE;
-    OperationFactory* factory = key_factory->GetOperationFactory(request.purpose);
+    OperationFactory* factory = key->key_factory()->GetOperationFactory(request.purpose);
     if (!factory) return;
 
     OperationPtr operation(
         factory->CreateOperation(move(*key), request.additional_params, &response->error));
     if (operation.get() == nullptr) return;
 
+    if (operation->authorizations().Contains(TAG_TRUSTED_CONFIRMATION_REQUIRED)) {
+        if (!operation->create_confirmation_verifier_buffer()) {
+            response->error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+            return;
+        }
+    }
+
     if (context_->enforcement_policy()) {
         km_id_t key_id;
         response->error = KM_ERROR_UNKNOWN_ERROR;
@@ -292,8 +574,7 @@
 
     response->output_params.Clear();
     response->error = operation->Begin(request.additional_params, &response->output_params);
-    if (response->error != KM_ERROR_OK)
-        return;
+    if (response->error != KM_ERROR_OK) return;
 
     response->op_handle = operation->operation_handle();
     response->error = operation_table_->Add(move(operation));
@@ -301,13 +582,28 @@
 
 void AndroidKeymaster::UpdateOperation(const UpdateOperationRequest& request,
                                        UpdateOperationResponse* response) {
-    if (response == nullptr)
-        return;
+    if (response == nullptr) return;
 
     response->error = KM_ERROR_INVALID_OPERATION_HANDLE;
     Operation* operation = operation_table_->Find(request.op_handle);
-    if (operation == nullptr)
-        return;
+    if (operation == nullptr) return;
+
+    Buffer* confirmation_verifier_buffer = operation->get_confirmation_verifier_buffer();
+    if (confirmation_verifier_buffer != nullptr) {
+        size_t input_num_bytes = request.input.available_read();
+        if (input_num_bytes + confirmation_verifier_buffer->available_read() >
+            kConfirmationMessageMaxSize + kConfirmationTokenMessageTagSize) {
+            response->error = KM_ERROR_INVALID_ARGUMENT;
+            operation_table_->Delete(request.op_handle);
+            return;
+        }
+        if (!confirmation_verifier_buffer->reserve(input_num_bytes)) {
+            response->error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+            operation_table_->Delete(request.op_handle);
+            return;
+        }
+        confirmation_verifier_buffer->write(request.input.peek_read(), input_num_bytes);
+    }
 
     if (context_->enforcement_policy()) {
         response->error = context_->enforcement_policy()->AuthorizeOperation(
@@ -330,13 +626,28 @@
 
 void AndroidKeymaster::FinishOperation(const FinishOperationRequest& request,
                                        FinishOperationResponse* response) {
-    if (response == nullptr)
-        return;
+    if (response == nullptr) return;
 
     response->error = KM_ERROR_INVALID_OPERATION_HANDLE;
     Operation* operation = operation_table_->Find(request.op_handle);
-    if (operation == nullptr)
-        return;
+    if (operation == nullptr) return;
+
+    Buffer* confirmation_verifier_buffer = operation->get_confirmation_verifier_buffer();
+    if (confirmation_verifier_buffer != nullptr) {
+        size_t input_num_bytes = request.input.available_read();
+        if (input_num_bytes + confirmation_verifier_buffer->available_read() >
+            kConfirmationMessageMaxSize + kConfirmationTokenMessageTagSize) {
+            response->error = KM_ERROR_INVALID_ARGUMENT;
+            operation_table_->Delete(request.op_handle);
+            return;
+        }
+        if (!confirmation_verifier_buffer->reserve(input_num_bytes)) {
+            response->error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+            operation_table_->Delete(request.op_handle);
+            return;
+        }
+        confirmation_verifier_buffer->write(request.input.peek_read(), input_num_bytes);
+    }
 
     if (context_->enforcement_policy()) {
         response->error = context_->enforcement_policy()->AuthorizeOperation(
@@ -350,13 +661,49 @@
 
     response->error = operation->Finish(request.additional_params, request.input, request.signature,
                                         &response->output_params, &response->output);
+    if (response->error != KM_ERROR_OK) {
+        operation_table_->Delete(request.op_handle);
+        return;
+    }
+
+    // Invalidate the single use key from secure storage after finish.
+    if (operation->hw_enforced().Contains(TAG_USAGE_COUNT_LIMIT, 1) &&
+        context_->secure_key_storage() != nullptr) {
+        response->error = context_->secure_key_storage()->DeleteKey(operation->key_id());
+    }
+
+    // If the operation succeeded and TAG_TRUSTED_CONFIRMATION_REQUIRED was
+    // set, the input must be checked against the confirmation token.
+    if (response->error == KM_ERROR_OK && confirmation_verifier_buffer != nullptr) {
+        keymaster_blob_t confirmation_token_blob;
+        if (!request.additional_params.GetTagValue(TAG_CONFIRMATION_TOKEN,
+                                                   &confirmation_token_blob)) {
+            response->error = KM_ERROR_NO_USER_CONFIRMATION;
+            response->output.Clear();
+        } else {
+            if (confirmation_token_blob.data_length != kConfirmationTokenSize) {
+                LOG_E("TAG_CONFIRMATION_TOKEN wrong size, was %zd expected %zd",
+                      confirmation_token_blob.data_length, kConfirmationTokenSize);
+                response->error = KM_ERROR_INVALID_ARGUMENT;
+                response->output.Clear();
+            } else {
+                keymaster_error_t verification_result = context_->CheckConfirmationToken(
+                    confirmation_verifier_buffer->begin(),
+                    confirmation_verifier_buffer->available_read(), confirmation_token_blob.data);
+                if (verification_result != KM_ERROR_OK) {
+                    response->error = verification_result;
+                    response->output.Clear();
+                }
+            }
+        }
+    }
+
     operation_table_->Delete(request.op_handle);
 }
 
 void AndroidKeymaster::AbortOperation(const AbortOperationRequest& request,
                                       AbortOperationResponse* response) {
-    if (!response)
-        return;
+    if (!response) return;
 
     Operation* operation = operation_table_->Find(request.op_handle);
     if (!operation) {
@@ -369,14 +716,12 @@
 }
 
 void AndroidKeymaster::ExportKey(const ExportKeyRequest& request, ExportKeyResponse* response) {
-    if (response == nullptr)
-        return;
+    if (response == nullptr) return;
 
     UniquePtr<Key> key;
     response->error =
         context_->ParseKeyBlob(KeymasterKeyBlob(request.key_blob), request.additional_params, &key);
-    if (response->error != KM_ERROR_OK)
-        return;
+    if (response->error != KM_ERROR_OK) return;
 
     UniquePtr<uint8_t[]> out_key;
     size_t size;
@@ -388,15 +733,10 @@
 }
 
 void AndroidKeymaster::AttestKey(const AttestKeyRequest& request, AttestKeyResponse* response) {
-    if (!response)
-        return;
+    if (!response) return;
 
-    const KeyFactory* key_factory;
-    UniquePtr<Key> key;
-    response->error = LoadKey(request.key_blob, request.attest_params,
-                              &key_factory, &key);
-    if (response->error != KM_ERROR_OK)
-        return;
+    UniquePtr<Key> key = LoadKey(request.key_blob, request.attest_params, &response->error);
+    if (!key) return;
 
     keymaster_blob_t attestation_application_id;
     if (request.attest_params.GetTagValue(TAG_ATTESTATION_APPLICATION_ID,
@@ -404,82 +744,101 @@
         key->sw_enforced().push_back(TAG_ATTESTATION_APPLICATION_ID, attestation_application_id);
     }
 
-    CertChainPtr certchain;
-    response->error = context_->GenerateAttestation(*key, request.attest_params, &certchain);
-    if (response->error == KM_ERROR_OK) {
-        response->certificate_chain = *certchain;
-        // response->certificate_chain took possession of secondary resources. So we shallowly
-        // delete the keymaster_cert_chain_t object, but nothing else.
-        // TODO Can we switch to managed types eventually?
-        delete certchain.release();
-    }
+    response->certificate_chain =
+        context_->GenerateAttestation(*key, request.attest_params, {} /* attestation_signing_key */,
+                                      {} /* issuer_subject */, &response->error);
 }
 
 void AndroidKeymaster::UpgradeKey(const UpgradeKeyRequest& request, UpgradeKeyResponse* response) {
-    if (!response)
-        return;
+    if (!response) return;
 
     KeymasterKeyBlob upgraded_key;
     response->error = context_->UpgradeKeyBlob(KeymasterKeyBlob(request.key_blob),
                                                request.upgrade_params, &upgraded_key);
-    if (response->error != KM_ERROR_OK)
-        return;
+    if (response->error != KM_ERROR_OK) return;
     response->upgraded_key = upgraded_key.release();
 }
 
 void AndroidKeymaster::ImportKey(const ImportKeyRequest& request, ImportKeyResponse* response) {
-    if (response == nullptr)
-        return;
+    if (response == nullptr) return;
 
-    keymaster_algorithm_t algorithm;
-    const KeyFactory* factory = nullptr;
-    UniquePtr<Key> key;
-    if (!request.key_description.GetTagValue(TAG_ALGORITHM, &algorithm) ||
-        !(factory = context_->GetKeyFactory(algorithm)))
-        response->error = KM_ERROR_UNSUPPORTED_ALGORITHM;
-    else {
-        keymaster_key_blob_t key_material = {request.key_data, request.key_data_length};
-        KeymasterKeyBlob key_blob;
-        response->error = factory->ImportKey(request.key_description, request.key_format,
-                                             KeymasterKeyBlob(key_material), &key_blob,
-                                             &response->enforced, &response->unenforced);
-        if (response->error == KM_ERROR_OK)
-            response->key_blob = key_blob.release();
+    const KeyFactory* factory =
+        get_key_factory(request.key_description, *context_, &response->error);
+    if (!factory) return;
+
+    if (context_->enforcement_policy() &&
+        request.key_description.GetTagValue(TAG_EARLY_BOOT_ONLY) &&
+        !context_->enforcement_policy()->in_early_boot()) {
+        response->error = KM_ERROR_EARLY_BOOT_ENDED;
+        return;
     }
+
+    UniquePtr<Key> attest_key;
+    if (request.attestation_signing_key_blob.key_material_size) {
+
+        attest_key =
+            LoadKey(request.attestation_signing_key_blob, {} /* params */, &response->error);
+        if (response->error != KM_ERROR_OK) return;
+    }
+
+    response->error = factory->ImportKey(request.key_description,  //
+                                         request.key_format,       //
+                                         request.key_data,         //
+                                         move(attest_key),         //
+                                         request.issuer_subject,   //
+                                         &response->key_blob,      //
+                                         &response->enforced,      //
+                                         &response->unenforced,    //
+                                         &response->certificate_chain);
 }
 
 void AndroidKeymaster::DeleteKey(const DeleteKeyRequest& request, DeleteKeyResponse* response) {
-    if (!response)
-        return;
+    if (!response) return;
     response->error = context_->DeleteKey(KeymasterKeyBlob(request.key_blob));
 }
 
 void AndroidKeymaster::DeleteAllKeys(const DeleteAllKeysRequest&, DeleteAllKeysResponse* response) {
-    if (!response)
-        return;
+    if (!response) return;
     response->error = context_->DeleteAllKeys();
 }
 
 void AndroidKeymaster::Configure(const ConfigureRequest& request, ConfigureResponse* response) {
-    if (!response)
-        return;
+    if (!response) return;
     response->error = context_->SetSystemVersion(request.os_version, request.os_patchlevel);
 }
 
+ConfigureVendorPatchlevelResponse
+AndroidKeymaster::ConfigureVendorPatchlevel(const ConfigureVendorPatchlevelRequest& request) {
+    ConfigureVendorPatchlevelResponse rsp(message_version());
+    rsp.error = context_->SetVendorPatchlevel(request.vendor_patchlevel);
+    return rsp;
+}
+
+ConfigureBootPatchlevelResponse
+AndroidKeymaster::ConfigureBootPatchlevel(const ConfigureBootPatchlevelRequest& request) {
+    ConfigureBootPatchlevelResponse rsp(message_version());
+    rsp.error = context_->SetBootPatchlevel(request.boot_patchlevel);
+    return rsp;
+}
+
 bool AndroidKeymaster::has_operation(keymaster_operation_handle_t op_handle) const {
     return operation_table_->Find(op_handle) != nullptr;
 }
 
-keymaster_error_t AndroidKeymaster::LoadKey(const keymaster_key_blob_t& key_blob,
-                                            const AuthorizationSet& additional_params,
-                                            const KeyFactory** factory, UniquePtr<Key>* key) {
+UniquePtr<Key> AndroidKeymaster::LoadKey(const keymaster_key_blob_t& key_blob,
+                                         const AuthorizationSet& additional_params,
+                                         keymaster_error_t* error) {
+    if (!error) return {};
+
+    UniquePtr<Key> key;
     KeymasterKeyBlob key_material;
-    keymaster_error_t error = context_->ParseKeyBlob(KeymasterKeyBlob(key_blob), additional_params,
-                                                     key);
-    if (error != KM_ERROR_OK)
-        return error;
-    if (factory) *factory = (*key)->key_factory();
-    return CheckVersionInfo((*key)->hw_enforced(), (*key)->sw_enforced(), *context_);
+    *error = context_->ParseKeyBlob(KeymasterKeyBlob(key_blob), additional_params, &key);
+    if (*error != KM_ERROR_OK) return {};
+
+    *error = CheckVersionInfo(key->hw_enforced(), key->sw_enforced(), *context_);
+    if (*error != KM_ERROR_OK) return {};
+
+    return key;
 }
 
 void AndroidKeymaster::ImportWrappedKey(const ImportWrappedKeyRequest& request,
@@ -511,22 +870,39 @@
         if (sids & HW_AUTH_FINGERPRINT) {
             key_description.push_back(TAG_USER_SECURE_ID, request.biometric_sid);
         }
-    }
 
-    keymaster_algorithm_t algorithm;
-    const KeyFactory* factory = nullptr;
-    if (!key_description.GetTagValue(TAG_ALGORITHM, &algorithm) ||
-        !(factory = context_->GetKeyFactory(algorithm))) {
-        response->error = KM_ERROR_UNSUPPORTED_ALGORITHM;
-    } else {
-        KeymasterKeyBlob key_blob;
-        response->error =
-            factory->ImportKey(key_description, key_format, KeymasterKeyBlob(secret_key), &key_blob,
-                               &response->enforced, &response->unenforced);
-        if (response->error == KM_ERROR_OK) {
-            response->key_blob = key_blob;
+        if (context_->GetKmVersion() >= KmVersion::KEYMINT_1) {
+            key_description.push_back(TAG_CERTIFICATE_NOT_BEFORE, 0);
+            key_description.push_back(TAG_CERTIFICATE_NOT_AFTER, kUndefinedExpirationDateTime);
         }
     }
+
+    const KeyFactory* factory = get_key_factory(key_description, *context_, &response->error);
+    if (!factory) return;
+
+    response->error = factory->ImportKey(key_description,          //
+                                         key_format,               //
+                                         secret_key,               //
+                                         {} /* attest_key */,      //
+                                         {} /* issuer_subject */,  //
+                                         &response->key_blob,      //
+                                         &response->enforced,      //
+                                         &response->unenforced,    //
+                                         &response->certificate_chain);
+}
+
+EarlyBootEndedResponse AndroidKeymaster::EarlyBootEnded() {
+    if (context_->enforcement_policy()) {
+        context_->enforcement_policy()->early_boot_ended();
+    }
+    return EarlyBootEndedResponse(message_version());
+}
+
+DeviceLockedResponse AndroidKeymaster::DeviceLocked(const DeviceLockedRequest& request) {
+    if (context_->enforcement_policy()) {
+        context_->enforcement_policy()->device_locked(request.passwordOnly);
+    }
+    return DeviceLockedResponse(message_version());
 }
 
 }  // namespace keymaster
diff --git a/android_keymaster/android_keymaster_messages.cpp b/android_keymaster/android_keymaster_messages.cpp
index 6eb6a5f..3dfd529 100644
--- a/android_keymaster/android_keymaster_messages.cpp
+++ b/android_keymaster/android_keymaster_messages.cpp
@@ -19,27 +19,29 @@
 
 namespace keymaster {
 
+namespace {
+
 /*
  * Helper functions for working with key blobs.
  */
 
-static void set_key_blob(keymaster_key_blob_t* key_blob, const void* key_material, size_t length) {
+void set_key_blob(keymaster_key_blob_t* key_blob, const void* key_material, size_t length) {
     delete[] key_blob->key_material;
     key_blob->key_material = dup_buffer(key_material, length);
     key_blob->key_material_size = length;
 }
 
-static size_t key_blob_size(const keymaster_key_blob_t& key_blob) {
+size_t key_blob_size(const keymaster_key_blob_t& key_blob) {
     return sizeof(uint32_t) /* key size */ + key_blob.key_material_size;
 }
 
-static uint8_t* serialize_key_blob(const keymaster_key_blob_t& key_blob, uint8_t* buf,
-                                   const uint8_t* end) {
+uint8_t* serialize_key_blob(const keymaster_key_blob_t& key_blob, uint8_t* buf,
+                            const uint8_t* end) {
     return append_size_and_data_to_buf(buf, end, key_blob.key_material, key_blob.key_material_size);
 }
 
-static bool deserialize_key_blob(keymaster_key_blob_t* key_blob, const uint8_t** buf_ptr,
-                                 const uint8_t* end) {
+bool deserialize_key_blob(keymaster_key_blob_t* key_blob, const uint8_t** buf_ptr,
+                          const uint8_t* end) {
     delete[] key_blob->key_material;
     key_blob->key_material = nullptr;
     UniquePtr<uint8_t[]> deserialized_key_material;
@@ -50,15 +52,23 @@
     return true;
 }
 
-static size_t blob_size(const keymaster_blob_t& blob) {
+void set_blob(keymaster_blob_t* blob, const void* data, size_t length) {
+    assert(blob);
+    assert(data);
+    delete[] blob->data;
+    blob->data = dup_buffer(data, length);
+    blob->data_length = length;
+}
+
+size_t blob_size(const keymaster_blob_t& blob) {
     return sizeof(uint32_t) /* data size */ + blob.data_length;
 }
 
-static uint8_t* serialize_blob(const keymaster_blob_t& blob, uint8_t* buf, const uint8_t* end) {
+uint8_t* serialize_blob(const keymaster_blob_t& blob, uint8_t* buf, const uint8_t* end) {
     return append_size_and_data_to_buf(buf, end, blob.data, blob.data_length);
 }
 
-static bool deserialize_blob(keymaster_blob_t* blob, const uint8_t** buf_ptr, const uint8_t* end) {
+bool deserialize_blob(keymaster_blob_t* blob, const uint8_t** buf_ptr, const uint8_t* end) {
     delete[] blob->data;
     *blob = {};
     UniquePtr<uint8_t[]> deserialized_blob;
@@ -68,6 +78,87 @@
     return true;
 }
 
+/*
+ * Helper functions for working with certificate chains.
+ */
+const size_t kMaxChainEntryCount = 10;
+
+size_t chain_size(const keymaster_cert_chain_t& certificate_chain) {
+    size_t result = sizeof(uint32_t); /* certificate_chain.entry_count */
+    for (size_t i = 0; i < certificate_chain.entry_count; ++i) {
+        result += sizeof(uint32_t); /* certificate_chain.entries[i].data_length */
+        result += certificate_chain.entries[i].data_length;
+    }
+    return result;
+}
+
+uint8_t* serialize_chain(const keymaster_cert_chain_t& certificate_chain, uint8_t* buf,
+                         const uint8_t* end) {
+    buf = append_uint32_to_buf(buf, end, certificate_chain.entry_count);
+    for (size_t i = 0; i < certificate_chain.entry_count; ++i) {
+        buf = append_size_and_data_to_buf(buf, end, certificate_chain.entries[i].data,
+                                          certificate_chain.entries[i].data_length);
+    }
+    return buf;
+}
+
+CertificateChain deserialize_chain(const uint8_t** buf_ptr, const uint8_t* end) {
+    size_t entry_count;
+    if (!copy_uint32_from_buf(buf_ptr, end, &entry_count) || entry_count > kMaxChainEntryCount) {
+        return {};
+    }
+
+    CertificateChain certificate_chain(entry_count);
+    if (!certificate_chain.entries) return {};
+
+    for (size_t i = 0; i < certificate_chain.entry_count; ++i) {
+        UniquePtr<uint8_t[]> data;
+        size_t data_length;
+        if (!copy_size_and_data_from_buf(buf_ptr, end, &data_length, &data)) return {};
+        certificate_chain.entries[i].data = data.release();
+        certificate_chain.entries[i].data_length = data_length;
+    }
+
+    return certificate_chain;
+}
+
+}  // namespace
+
+int32_t NegotiateMessageVersion(const GetVersionResponse& response, keymaster_error_t* error) {
+    switch (response.major_ver) {
+    case 1:  // KM1
+        switch (response.minor_ver) {
+        case 0:
+            return MessageVersion(KmVersion::KEYMASTER_1, 0 /* km_date */);
+        case 1:
+            return MessageVersion(KmVersion::KEYMASTER_1_1, 0 /* km_date */);
+        }
+        break;
+    case 2:
+        return MessageVersion(KmVersion::KEYMASTER_2, 0 /* km_date */);
+    case 3:
+        return MessageVersion(KmVersion::KEYMASTER_3, 0 /* km_date */);
+    case 4:
+        switch (response.minor_ver) {
+        case 0:
+            return MessageVersion(KmVersion::KEYMASTER_4, 0 /* km_date */);
+        case 1:
+            return MessageVersion(KmVersion::KEYMASTER_4_1, 0 /* km_date */);
+        }
+        break;
+    }
+
+    *error = KM_ERROR_UNKNOWN_ERROR;
+    return -1;
+}
+
+int32_t NegotiateMessageVersion(const GetVersion2Request& request,
+                                const GetVersion2Response& response) {
+    return request.max_message_version < response.max_message_version
+               ? request.max_message_version
+               : response.max_message_version;
+}
+
 size_t KeymasterResponse::SerializedSize() const {
     if (error != KM_ERROR_OK)
         return sizeof(int32_t);
@@ -77,36 +168,146 @@
 
 uint8_t* KeymasterResponse::Serialize(uint8_t* buf, const uint8_t* end) const {
     buf = append_uint32_to_buf(buf, end, static_cast<uint32_t>(error));
-    if (error == KM_ERROR_OK)
-        buf = NonErrorSerialize(buf, end);
+    if (error == KM_ERROR_OK) buf = NonErrorSerialize(buf, end);
     return buf;
 }
 
 bool KeymasterResponse::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
-    if (!copy_uint32_from_buf(buf_ptr, end, &error))
-        return false;
-    if (error != KM_ERROR_OK)
-        return true;
+    if (!copy_uint32_from_buf(buf_ptr, end, &error)) return false;
+    if (error != KM_ERROR_OK) return true;
     return NonErrorDeserialize(buf_ptr, end);
 }
 
-GenerateKeyResponse::~GenerateKeyResponse() {
-    delete[] key_blob.key_material;
+size_t GenerateKeyRequest::SerializedSize() const {
+    size_t size = key_description.SerializedSize();
+    if (message_version < 4) return size;
+    return size                                           //
+           + key_blob_size(attestation_signing_key_blob)  //
+           + attest_key_params.SerializedSize()           //
+           + blob_size(issuer_subject);
+}
+
+uint8_t* GenerateKeyRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
+    buf = key_description.Serialize(buf, end);
+    if (message_version < 4) return buf;
+    buf = serialize_key_blob(attestation_signing_key_blob, buf, end);
+    buf = attest_key_params.Serialize(buf, end);
+    return serialize_blob(issuer_subject, buf, end);
+}
+
+bool GenerateKeyRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    if (!key_description.Deserialize(buf_ptr, end)) return false;
+    if (message_version < 4) return true;
+    return deserialize_key_blob(&attestation_signing_key_blob, buf_ptr, end)  //
+           && attest_key_params.Deserialize(buf_ptr, end)                     //
+           && deserialize_blob(&issuer_subject, buf_ptr, end);
 }
 
 size_t GenerateKeyResponse::NonErrorSerializedSize() const {
-    return key_blob_size(key_blob) + enforced.SerializedSize() + unenforced.SerializedSize();
+    size_t result =
+        key_blob_size(key_blob) + enforced.SerializedSize() + unenforced.SerializedSize();
+    if (message_version < 4) return result;
+    return result + chain_size(certificate_chain);
 }
 
 uint8_t* GenerateKeyResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
     buf = serialize_key_blob(key_blob, buf, end);
     buf = enforced.Serialize(buf, end);
-    return unenforced.Serialize(buf, end);
+    buf = unenforced.Serialize(buf, end);
+    if (message_version < 4) return buf;
+    return serialize_chain(certificate_chain, buf, end);
 }
 
 bool GenerateKeyResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
-    return deserialize_key_blob(&key_blob, buf_ptr, end) && enforced.Deserialize(buf_ptr, end) &&
-           unenforced.Deserialize(buf_ptr, end);
+    if (!deserialize_key_blob(&key_blob, buf_ptr, end) ||  //
+        !enforced.Deserialize(buf_ptr, end) ||             //
+        !unenforced.Deserialize(buf_ptr, end)) {
+        return false;
+    }
+    if (message_version < 4) return true;
+    certificate_chain = deserialize_chain(buf_ptr, end);
+    return !!certificate_chain.entries;
+}
+
+size_t GenerateRkpKeyResponse::NonErrorSerializedSize() const {
+    return key_blob_size(key_blob) + blob_size(maced_public_key);
+}
+
+uint8_t* GenerateRkpKeyResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
+    buf = serialize_key_blob(key_blob, buf, end);
+    return serialize_blob(maced_public_key, buf, end);
+}
+
+bool GenerateRkpKeyResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    return deserialize_key_blob(&key_blob, buf_ptr, end) &&
+           deserialize_blob(&maced_public_key, buf_ptr, end);
+}
+
+size_t GenerateCsrRequest::SerializedSize() const {
+    size_t size = sizeof(uint8_t); /* test_mode */
+    size += sizeof(uint32_t);      /* num_keys */
+    for (size_t i = 0; i < num_keys; i++) {
+        size += blob_size(keys_to_sign_array[i]);
+    }
+    size += blob_size(endpoint_enc_cert_chain);
+    size += blob_size(challenge);
+    return size;
+}
+
+uint8_t* GenerateCsrRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
+    buf = append_to_buf(buf, end, &test_mode, sizeof(uint8_t));
+    buf = append_uint32_to_buf(buf, end, num_keys);
+    for (size_t i = 0; i < num_keys; i++) {
+        buf = serialize_blob(keys_to_sign_array[i], buf, end);
+    }
+    buf = serialize_blob(endpoint_enc_cert_chain, buf, end);
+    return serialize_blob(challenge, buf, end);
+}
+
+bool GenerateCsrRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    if (!copy_from_buf(buf_ptr, end, &test_mode, sizeof(uint8_t)) ||
+        !copy_from_buf(buf_ptr, end, &num_keys, sizeof(uint32_t))) {
+        return false;
+    }
+    keys_to_sign_array = new (std::nothrow) KeymasterBlob[num_keys];
+    if (!keys_to_sign_array) return false;
+    for (size_t i = 0; i < num_keys; i++) {
+        if (!deserialize_blob(&keys_to_sign_array[i], buf_ptr, end)) return false;
+    }
+    return deserialize_blob(&endpoint_enc_cert_chain, buf_ptr, end) &&
+           deserialize_blob(&challenge, buf_ptr, end);
+}
+
+void GenerateCsrRequest::SetKeyToSign(uint32_t index, const void* data, size_t length) {
+    if (index >= num_keys) {
+        return;
+    }
+    set_blob(&keys_to_sign_array[index], data, length);
+}
+
+void GenerateCsrRequest::SetEndpointEncCertChain(const void* data, size_t length) {
+    set_blob(&endpoint_enc_cert_chain, data, length);
+}
+
+void GenerateCsrRequest::SetChallenge(const void* data, size_t length) {
+    set_blob(&challenge, data, length);
+}
+
+size_t GenerateCsrResponse::NonErrorSerializedSize() const {
+    return blob_size(keys_to_sign_mac) + blob_size(device_info_blob) +
+           blob_size(protected_data_blob);
+}
+
+uint8_t* GenerateCsrResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
+    buf = serialize_blob(keys_to_sign_mac, buf, end);
+    buf = serialize_blob(device_info_blob, buf, end);
+    return serialize_blob(protected_data_blob, buf, end);
+}
+
+bool GenerateCsrResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    return deserialize_blob(&keys_to_sign_mac, buf_ptr, end) &&
+           deserialize_blob(&device_info_blob, buf_ptr, end) &&
+           deserialize_blob(&protected_data_blob, buf_ptr, end);
 }
 
 GetKeyCharacteristicsRequest::~GetKeyCharacteristicsRequest() {
@@ -175,15 +376,13 @@
 
 uint8_t* BeginOperationResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
     buf = append_uint64_to_buf(buf, end, op_handle);
-    if (message_version > 0)
-        buf = output_params.Serialize(buf, end);
+    if (message_version > 0) buf = output_params.Serialize(buf, end);
     return buf;
 }
 
 bool BeginOperationResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
     bool retval = copy_uint64_from_buf(buf_ptr, end, &op_handle);
-    if (retval && message_version > 0)
-        retval = output_params.Deserialize(buf_ptr, end);
+    if (retval && message_version > 0) retval = output_params.Deserialize(buf_ptr, end);
     return retval;
 }
 
@@ -197,21 +396,20 @@
 uint8_t* UpdateOperationRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
     buf = append_uint64_to_buf(buf, end, op_handle);
     buf = input.Serialize(buf, end);
-    if (message_version > 0)
-        buf = additional_params.Serialize(buf, end);
+    if (message_version > 0) buf = additional_params.Serialize(buf, end);
     return buf;
 }
 
 bool UpdateOperationRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
     bool retval = copy_uint64_from_buf(buf_ptr, end, &op_handle) && input.Deserialize(buf_ptr, end);
-    if (retval && message_version > 0)
-        retval = additional_params.Deserialize(buf_ptr, end);
+    if (retval && message_version > 0) retval = additional_params.Deserialize(buf_ptr, end);
     return retval;
 }
 
 size_t UpdateOperationResponse::NonErrorSerializedSize() const {
     size_t size = 0;
     switch (message_version) {
+    case 4:
     case 3:
     case 2:
         size += output_params.SerializedSize();
@@ -232,25 +430,22 @@
 
 uint8_t* UpdateOperationResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
     buf = output.Serialize(buf, end);
-    if (message_version > 0)
-        buf = append_uint32_to_buf(buf, end, input_consumed);
-    if (message_version > 1)
-        buf = output_params.Serialize(buf, end);
+    if (message_version > 0) buf = append_uint32_to_buf(buf, end, input_consumed);
+    if (message_version > 1) buf = output_params.Serialize(buf, end);
     return buf;
 }
 
 bool UpdateOperationResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
     bool retval = output.Deserialize(buf_ptr, end);
-    if (retval && message_version > 0)
-        retval = copy_uint32_from_buf(buf_ptr, end, &input_consumed);
-    if (retval && message_version > 1)
-        retval = output_params.Deserialize(buf_ptr, end);
+    if (retval && message_version > 0) retval = copy_uint32_from_buf(buf_ptr, end, &input_consumed);
+    if (retval && message_version > 1) retval = output_params.Deserialize(buf_ptr, end);
     return retval;
 }
 
 size_t FinishOperationRequest::SerializedSize() const {
     size_t size = 0;
     switch (message_version) {
+    case 4:
     case 3:
         size += input.SerializedSize();
         FALLTHROUGH;
@@ -272,20 +467,16 @@
 uint8_t* FinishOperationRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
     buf = append_uint64_to_buf(buf, end, op_handle);
     buf = signature.Serialize(buf, end);
-    if (message_version > 0)
-        buf = additional_params.Serialize(buf, end);
-    if (message_version > 2)
-        buf = input.Serialize(buf, end);
+    if (message_version > 0) buf = additional_params.Serialize(buf, end);
+    if (message_version > 2) buf = input.Serialize(buf, end);
     return buf;
 }
 
 bool FinishOperationRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
     bool retval =
         copy_uint64_from_buf(buf_ptr, end, &op_handle) && signature.Deserialize(buf_ptr, end);
-    if (retval && message_version > 0)
-        retval = additional_params.Deserialize(buf_ptr, end);
-    if (retval && message_version > 2)
-        retval = input.Deserialize(buf_ptr, end);
+    if (retval && message_version > 0) retval = additional_params.Deserialize(buf_ptr, end);
+    if (retval && message_version > 2) retval = input.Deserialize(buf_ptr, end);
     return retval;
 }
 
@@ -298,15 +489,13 @@
 
 uint8_t* FinishOperationResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
     buf = output.Serialize(buf, end);
-    if (message_version > 1)
-        buf = output_params.Serialize(buf, end);
+    if (message_version > 1) buf = output_params.Serialize(buf, end);
     return buf;
 }
 
 bool FinishOperationResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
     bool retval = output.Deserialize(buf_ptr, end);
-    if (retval && message_version > 1)
-        retval = output_params.Deserialize(buf_ptr, end);
+    if (retval && message_version > 1) retval = output_params.Deserialize(buf_ptr, end);
     return retval;
 }
 
@@ -322,33 +511,38 @@
     return random_data.Deserialize(buf_ptr, end);
 }
 
-void ImportKeyRequest::SetKeyMaterial(const void* key_material, size_t length) {
-    delete[] key_data;
-    key_data = dup_buffer(key_material, length);
-    key_data_length = length;
-}
-
 size_t ImportKeyRequest::SerializedSize() const {
-    return key_description.SerializedSize() + sizeof(uint32_t) /* key_format */ +
-           sizeof(uint32_t) /* key_data_length */ + key_data_length;
+    size_t size = key_description.SerializedSize()     //
+                  + sizeof(uint32_t) /* key_format */  //
+                  + key_blob_size(key_data);
+    if (message_version < 4) return size;
+    return size                                           //
+           + key_blob_size(attestation_signing_key_blob)  //
+           + attest_key_params.SerializedSize()           //
+           + blob_size(issuer_subject);
 }
 
 uint8_t* ImportKeyRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
     buf = key_description.Serialize(buf, end);
     buf = append_uint32_to_buf(buf, end, key_format);
-    return append_size_and_data_to_buf(buf, end, key_data, key_data_length);
+    buf = serialize_key_blob(key_data, buf, end);
+    if (message_version < 4) return buf;
+    buf = serialize_key_blob(attestation_signing_key_blob, buf, end);
+    buf = attest_key_params.Serialize(buf, end);
+    return serialize_blob(issuer_subject, buf, end);
 }
 
 bool ImportKeyRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
-    delete[] key_data;
-    key_data = nullptr;
-    UniquePtr<uint8_t[]> deserialized_key_material;
-    if (!key_description.Deserialize(buf_ptr, end) ||
-        !copy_uint32_from_buf(buf_ptr, end, &key_format) ||
-        !copy_size_and_data_from_buf(buf_ptr, end, &key_data_length, &deserialized_key_material))
+    if (!(key_description.Deserialize(buf_ptr, end) &&
+          copy_uint32_from_buf(buf_ptr, end, &key_format) &&
+          deserialize_key_blob(&key_data, buf_ptr, end))) {
         return false;
-    key_data = deserialized_key_material.release();
-    return true;
+    }
+    if (message_version < 4) return true;
+
+    return deserialize_key_blob(&attestation_signing_key_blob, buf_ptr, end)  //
+           && attest_key_params.Deserialize(buf_ptr, end)                     //
+           && deserialize_blob(&issuer_subject, buf_ptr, end);
 }
 
 void ImportKeyResponse::SetKeyMaterial(const void* key_material, size_t length) {
@@ -356,18 +550,29 @@
 }
 
 size_t ImportKeyResponse::NonErrorSerializedSize() const {
-    return key_blob_size(key_blob) + enforced.SerializedSize() + unenforced.SerializedSize();
+    size_t result =
+        key_blob_size(key_blob) + enforced.SerializedSize() + unenforced.SerializedSize();
+    if (message_version < 4) return result;
+    return result + chain_size(certificate_chain);
 }
 
 uint8_t* ImportKeyResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
     buf = serialize_key_blob(key_blob, buf, end);
     buf = enforced.Serialize(buf, end);
-    return unenforced.Serialize(buf, end);
+    buf = unenforced.Serialize(buf, end);
+    if (message_version < 4) return buf;
+    return serialize_chain(certificate_chain, buf, end);
 }
 
 bool ImportKeyResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
-    return deserialize_key_blob(&key_blob, buf_ptr, end) && enforced.Deserialize(buf_ptr, end) &&
-           unenforced.Deserialize(buf_ptr, end);
+    if (!deserialize_key_blob(&key_blob, buf_ptr, end) ||  //
+        !enforced.Deserialize(buf_ptr, end) ||             //
+        !unenforced.Deserialize(buf_ptr, end)) {
+        return false;
+    }
+    if (message_version < 4) return true;
+    certificate_chain = deserialize_chain(buf_ptr, end);
+    return !!certificate_chain.entries;
 }
 
 void ExportKeyRequest::SetKeyMaterial(const void* key_material, size_t length) {
@@ -447,8 +652,7 @@
 }
 
 bool GetVersionResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
-    if (*buf_ptr + NonErrorSerializedSize() > end)
-        return false;
+    if (*buf_ptr + NonErrorSerializedSize() > end) return false;
     const uint8_t* tmp = *buf_ptr;
     major_ver = *tmp++;
     minor_ver = *tmp++;
@@ -478,67 +682,17 @@
     return deserialize_key_blob(&key_blob, buf_ptr, end) && attest_params.Deserialize(buf_ptr, end);
 }
 
-AttestKeyResponse::~AttestKeyResponse() {
-    for (size_t i = 0; i < certificate_chain.entry_count; ++i)
-        delete[] certificate_chain.entries[i].data;
-    delete[] certificate_chain.entries;
-}
-
-const size_t kMaxChainEntryCount = 10;
-bool AttestKeyResponse::AllocateChain(size_t entry_count) {
-    if (entry_count > kMaxChainEntryCount)
-        return false;
-
-    if (certificate_chain.entries) {
-        for (size_t i = 0; i < certificate_chain.entry_count; ++i)
-            delete[] certificate_chain.entries[i].data;
-        delete[] certificate_chain.entries;
-    }
-
-    certificate_chain.entry_count = entry_count;
-    certificate_chain.entries = new (std::nothrow) keymaster_blob_t[entry_count];
-    if (!certificate_chain.entries) {
-        certificate_chain.entry_count = 0;
-        return false;
-    }
-
-    memset(certificate_chain.entries, 0, sizeof(certificate_chain.entries[0]) * entry_count);
-    return true;
-}
-
 size_t AttestKeyResponse::NonErrorSerializedSize() const {
-    size_t result = sizeof(uint32_t); /* certificate_chain.entry_count */
-    for (size_t i = 0; i < certificate_chain.entry_count; ++i) {
-        result += sizeof(uint32_t); /* certificate_chain.entries[i].data_length */
-        result += certificate_chain.entries[i].data_length;
-    }
-    return result;
+    return chain_size(certificate_chain);
 }
 
 uint8_t* AttestKeyResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
-    buf = append_uint32_to_buf(buf, end, certificate_chain.entry_count);
-    for (size_t i = 0; i < certificate_chain.entry_count; ++i) {
-        buf = append_size_and_data_to_buf(buf, end, certificate_chain.entries[i].data,
-                                          certificate_chain.entries[i].data_length);
-    }
-    return buf;
+    return serialize_chain(certificate_chain, buf, end);
 }
 
 bool AttestKeyResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
-    size_t entry_count;
-    if (!copy_uint32_from_buf(buf_ptr, end, &entry_count) || !AllocateChain(entry_count))
-        return false;
-
-    for (size_t i = 0; i < certificate_chain.entry_count; ++i) {
-        UniquePtr<uint8_t[]> data;
-        size_t data_length;
-        if (!copy_size_and_data_from_buf(buf_ptr, end, &data_length, &data))
-            return false;
-        certificate_chain.entries[i].data = data.release();
-        certificate_chain.entries[i].data_length = data_length;
-    }
-
-    return true;
+    certificate_chain = deserialize_chain(buf_ptr, end);
+    return !!certificate_chain.entries;
 }
 
 UpgradeKeyRequest::~UpgradeKeyRequest() {
@@ -632,11 +786,9 @@
 }
 
 size_t ImportWrappedKeyRequest::SerializedSize() const {
-    return sizeof(uint32_t) /* wrapped_key_data_length */ + wrapped_key.key_material_size +
-           sizeof(uint32_t) /* wrapping_key_data_length */ + wrapping_key.key_material_size +
-           sizeof(uint32_t) /* masking_key_data_length */ + masking_key.key_material_size +
-           additional_params.SerializedSize() + sizeof(uint64_t) /* password_sid */ +
-           sizeof(uint64_t) /* biometric_sid */;
+    return key_blob_size(wrapped_key) + key_blob_size(wrapping_key) + key_blob_size(masking_key) +
+           additional_params.SerializedSize() + sizeof(uint64_t)  // password_sid
+           + sizeof(uint64_t);                                    // biometric_sid
 }
 
 uint8_t* ImportWrappedKeyRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
@@ -674,18 +826,29 @@
 }
 
 size_t ImportWrappedKeyResponse::NonErrorSerializedSize() const {
-    return key_blob_size(key_blob) + enforced.SerializedSize() + unenforced.SerializedSize();
+    size_t result =
+        key_blob_size(key_blob) + enforced.SerializedSize() + unenforced.SerializedSize();
+    if (message_version < 4) return result;
+    return result + chain_size(certificate_chain);
 }
 
 uint8_t* ImportWrappedKeyResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
     buf = serialize_key_blob(key_blob, buf, end);
     buf = enforced.Serialize(buf, end);
-    return unenforced.Serialize(buf, end);
+    buf = unenforced.Serialize(buf, end);
+    if (message_version < 4) return buf;
+    return serialize_chain(certificate_chain, buf, end);
 }
 
 bool ImportWrappedKeyResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
-    return deserialize_key_blob(&key_blob, buf_ptr, end) && enforced.Deserialize(buf_ptr, end) &&
-           unenforced.Deserialize(buf_ptr, end);
+    if (!deserialize_key_blob(&key_blob, buf_ptr, end) ||  //
+        !enforced.Deserialize(buf_ptr, end) ||             //
+        !unenforced.Deserialize(buf_ptr, end)) {
+        return false;
+    }
+    if (message_version < 4) return true;
+    certificate_chain = deserialize_chain(buf_ptr, end);
+    return !!certificate_chain.entries;
 }
 
 size_t HardwareAuthToken::SerializedSize() const {
@@ -732,4 +895,22 @@
            deserialize_blob(&mac, buf_ptr, end);
 }
 
+size_t GetVersion2Response::NonErrorSerializedSize() const {
+    return sizeof(max_message_version) +  //
+           sizeof(km_version) +           //
+           sizeof(km_date);
+}
+
+uint8_t* GetVersion2Response::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
+    buf = append_uint32_to_buf(buf, end, max_message_version);
+    buf = append_uint32_to_buf(buf, end, km_version);
+    return append_uint32_to_buf(buf, end, km_date);
+}
+
+bool GetVersion2Response::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    return copy_uint32_from_buf(buf_ptr, end, &max_message_version) &&
+           copy_uint32_from_buf(buf_ptr, end, &km_version) &&
+           copy_uint32_from_buf(buf_ptr, end, &km_date);
+}
+
 }  // namespace keymaster
diff --git a/android_keymaster/android_keymaster_utils.cpp b/android_keymaster/android_keymaster_utils.cpp
index fb45fc9..b966a61 100644
--- a/android_keymaster/android_keymaster_utils.cpp
+++ b/android_keymaster/android_keymaster_utils.cpp
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-#include <keymaster/android_keymaster_utils.h>
+#include <new>
 
-#include <keymaster/new.h>
+#include <keymaster/android_keymaster_utils.h>
 
 namespace keymaster {
 
@@ -25,11 +25,9 @@
 const size_t kMaxDupBufferSize = 16 * 1024 * 1024;
 
 uint8_t* dup_buffer(const void* buf, size_t size) {
-    if (size >= kMaxDupBufferSize)
-        return nullptr;
+    if (size >= kMaxDupBufferSize) return nullptr;
     uint8_t* retval = new (std::nothrow) uint8_t[size];
-    if (retval)
-        memcpy(retval, buf, size);
+    if (retval) memcpy(retval, buf, size);
     return retval;
 }
 
diff --git a/android_keymaster/authorization_set.cpp b/android_keymaster/authorization_set.cpp
index e09b73c..2d76cad 100644
--- a/android_keymaster/authorization_set.cpp
+++ b/android_keymaster/authorization_set.cpp
@@ -21,8 +21,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <keymaster/new.h>
-
 #include <keymaster/android_keymaster_utils.h>
 #include <keymaster/logger.h>
 
@@ -62,8 +60,7 @@
 }
 
 bool AuthorizationSet::reserve_elems(size_t count) {
-    if (is_valid() != OK)
-        return false;
+    if (is_valid() != OK) return false;
 
     if (count > elems_capacity_) {
         keymaster_key_param_t* new_elems = new (std::nothrow) keymaster_key_param_t[count];
@@ -80,8 +77,7 @@
 }
 
 bool AuthorizationSet::reserve_indirect(size_t length) {
-    if (is_valid() != OK)
-        return false;
+    if (is_valid() != OK) return false;
 
     if (length > indirect_data_capacity_) {
         uint8_t* new_data = new (std::nothrow) uint8_t[length];
@@ -128,11 +124,9 @@
         return true;
     }
 
-    if (!reserve_elems(count))
-        return false;
+    if (!reserve_elems(count)) return false;
 
-    if (!reserve_indirect(ComputeIndirectDataSize(elems, count)))
-        return false;
+    if (!reserve_indirect(ComputeIndirectDataSize(elems, count))) return false;
 
     memcpy(elems_, elems, sizeof(keymaster_key_param_t) * count);
     elems_size_ = count;
@@ -166,11 +160,9 @@
             ++invalid_count;
         }
     }
-    if (size() > 0 && elems_[size() - 1].tag == KM_TAG_INVALID)
-        ++invalid_count;
+    if (size() > 0 && elems_[size() - 1].tag == KM_TAG_INVALID) ++invalid_count;
 
-    if (invalid_count == 0)
-        return;
+    if (invalid_count == 0) return;
 
     Sort();
 
@@ -180,16 +172,14 @@
 }
 
 void AuthorizationSet::Union(const keymaster_key_param_set_t& set) {
-    if (set.length == 0)
-        return;
+    if (set.length == 0) return;
 
     push_back(set);
     Deduplicate();
 }
 
 void AuthorizationSet::Difference(const keymaster_key_param_set_t& set) {
-    if (set.length == 0)
-        return;
+    if (set.length == 0) return;
 
     Deduplicate();
 
@@ -227,8 +217,7 @@
 }
 
 int AuthorizationSet::find(keymaster_tag_t tag, int begin) const {
-    if (is_valid() != OK)
-        return -1;
+    if (is_valid() != OK) return -1;
 
     int i = ++begin;
     while (i < (int)elems_size_ && elems_[i].tag != tag)
@@ -240,8 +229,7 @@
 }
 
 bool AuthorizationSet::erase(int index) {
-    if (index < 0 || index >= static_cast<int>(size()))
-        return false;
+    if (index < 0 || index >= static_cast<int>(size())) return false;
 
     --elems_size_;
     for (size_t i = index; i < elems_size_; ++i)
@@ -267,25 +255,21 @@
 }
 
 bool AuthorizationSet::push_back(const keymaster_key_param_set_t& set) {
-    if (is_valid() != OK)
-        return false;
+    if (is_valid() != OK) return false;
 
-    if (!reserve_elems(elems_size_ + set.length))
-        return false;
+    if (!reserve_elems(elems_size_ + set.length)) return false;
 
     if (!reserve_indirect(indirect_data_size_ + ComputeIndirectDataSize(set.params, set.length)))
         return false;
 
     for (size_t i = 0; i < set.length; ++i)
-        if (!push_back(set.params[i]))
-            return false;
+        if (!push_back(set.params[i])) return false;
 
     return true;
 }
 
 bool AuthorizationSet::push_back(keymaster_key_param_t elem) {
-    if (is_valid() != OK)
-        return false;
+    if (is_valid() != OK) return false;
 
     if (elems_size_ >= elems_capacity_)
         if (!reserve_elems(elems_capacity_ ? elems_capacity_ * 2 : STARTING_ELEMS_CAPACITY))
@@ -350,8 +334,7 @@
         buf = append_uint64_to_buf(buf, end, param.date_time);
         break;
     case KM_BOOL:
-        if (buf < end)
-            *buf = static_cast<uint8_t>(param.boolean);
+        if (buf < end) *buf = static_cast<uint8_t>(param.boolean);
         buf++;
         break;
     case KM_BIGNUM:
@@ -365,8 +348,7 @@
 
 static bool deserialize(keymaster_key_param_t* param, const uint8_t** buf_ptr, const uint8_t* end,
                         const uint8_t* indirect_base, const uint8_t* indirect_end) {
-    if (!copy_uint32_from_buf(buf_ptr, end, &param->tag))
-        return false;
+    if (!copy_uint32_from_buf(buf_ptr, end, &param->tag)) return false;
 
     switch (keymaster_tag_get_type(param->tag)) {
     case KM_INVALID:
@@ -465,11 +447,11 @@
     // elems_ arrays which are clearly too large to be reasonable.
     size_t elems_refs_size;
     size_t elems_alloc_size;
-    bool refs_size_overflow = __builtin_mul_overflow(elements_count, sizeof(uint32_t),
-                                                     &elems_refs_size);
-    bool alloc_size_overflow = __builtin_mul_overflow(elements_count, sizeof(*elems_),
-                                                      &elems_alloc_size);
-        /* elements_size must fit in the buffer */
+    bool refs_size_overflow =
+        __builtin_mul_overflow(elements_count, sizeof(uint32_t), &elems_refs_size);
+    bool alloc_size_overflow =
+        __builtin_mul_overflow(elements_count, sizeof(*elems_), &elems_alloc_size);
+    /* elements_size must fit in the buffer */
     if (static_cast<ptrdiff_t>(elements_size) > end - *buf_ptr ||
         /* The element refs must all fit within elements_size */
         elems_refs_size > elements_size ||
@@ -482,8 +464,7 @@
         return false;
     }
 
-    if (!reserve_elems(elements_count))
-        return false;
+    if (!reserve_elems(elements_count)) return false;
 
     uint8_t* indirect_end = indirect_data_ + indirect_data_size_;
     const uint8_t* elements_end = *buf_ptr + elements_size;
@@ -677,15 +658,13 @@
 
 bool AuthorizationSet::ContainsEnumValue(keymaster_tag_t tag, uint32_t value) const {
     for (auto& entry : *this)
-        if (entry.tag == tag && entry.enumerated == value)
-            return true;
+        if (entry.tag == tag && entry.enumerated == value) return true;
     return false;
 }
 
 bool AuthorizationSet::ContainsIntValue(keymaster_tag_t tag, uint32_t value) const {
     for (auto& entry : *this)
-        if (entry.tag == tag && entry.integer == value)
-            return true;
+        if (entry.tag == tag && entry.integer == value) return true;
     return false;
 }
 
diff --git a/android_keymaster/keymaster_configuration.cpp b/android_keymaster/keymaster_configuration.cpp
index 0bcf6f9..ca78863 100644
--- a/android_keymaster/keymaster_configuration.cpp
+++ b/android_keymaster/keymaster_configuration.cpp
@@ -40,14 +40,15 @@
 constexpr size_t kPlatformVersionMatchCount = kSubminorVersionMatch + 1;
 
 constexpr char kPlatformPatchlevelProp[] = "ro.build.version.security_patch";
-constexpr char kPlatformPatchlevelRegex[] = "^([0-9]{4})-([0-9]{2})-[0-9]{2}$";
+constexpr char kVendorPatchlevelProp[] = "ro.vendor.build.security_patch";
+constexpr char kPatchlevelRegex[] = "^([0-9]{4})-([0-9]{2})-([0-9]{2})$";
 constexpr size_t kYearMatch = 1;
 constexpr size_t kMonthMatch = 2;
-constexpr size_t kPlatformPatchlevelMatchCount = kMonthMatch + 1;
+constexpr size_t kDayMatch = 3;
+constexpr size_t kPatchlevelMatchCount = kDayMatch + 1;
 
 uint32_t match_to_uint32(const char* expression, const regmatch_t& match) {
-    if (match.rm_so == -1)
-        return 0;
+    if (match.rm_so == -1) return 0;
 
     size_t len = match.rm_eo - match.rm_so;
     std::string s(expression + match.rm_so, len);
@@ -65,6 +66,46 @@
     return prop_value;
 }
 
+enum class PatchlevelOutput { kYearMonthDay, kYearMonth };
+
+uint32_t GetPatchlevel(const char* patchlevel_str, PatchlevelOutput detail) {
+    regex_t regex;
+    if (regcomp(&regex, kPatchlevelRegex, REG_EXTENDED) != 0) {
+        ALOGE("Failed to compile platform patchlevel regex! (%s)", kPatchlevelRegex);
+        return 0;
+    }
+
+    regmatch_t matches[kPatchlevelMatchCount];
+    int not_match = regexec(&regex, patchlevel_str, kPatchlevelMatchCount, matches, 0 /* flags */);
+    regfree(&regex);
+    if (not_match) {
+        ALOGI(" patchlevel string does not match expected format.  Using patchlevel 0");
+        return 0;
+    }
+
+    uint32_t year = match_to_uint32(patchlevel_str, matches[kYearMatch]);
+    uint32_t month = match_to_uint32(patchlevel_str, matches[kMonthMatch]);
+
+    if (month < 1 || month > 12) {
+        ALOGE("Invalid patch month %d", month);
+        return 0;
+    }
+
+    switch (detail) {
+    case PatchlevelOutput::kYearMonthDay: {
+        uint32_t day = match_to_uint32(patchlevel_str, matches[kDayMatch]);
+        if (day < 1 || day > 31) {
+            ALOGE("Invalid patch day %d", day);
+            return 0;
+        }
+        return year * 10000 + month * 100 + day;
+    }
+    case PatchlevelOutput::kYearMonth:
+        return year * 100 + month;
+    }
+    return 0;
+}
+
 }  // anonymous namespace
 
 keymaster_error_t ConfigureDevice(keymaster2_device_t* dev, uint32_t os_version,
@@ -91,7 +132,8 @@
         regexec(&regex, version_str, kPlatformVersionMatchCount, matches, 0 /* flags */);
     regfree(&regex);
     if (not_match) {
-        ALOGI("Platform version string does not match expected format.  Using version 0.");
+        ALOGI("Platform version string \"%s\" does not match expected format.  Using version 0.",
+              version_str);
         return 0;
     }
 
@@ -108,29 +150,7 @@
 }
 
 uint32_t GetOsPatchlevel(const char* patchlevel_str) {
-    regex_t regex;
-    if (regcomp(&regex, kPlatformPatchlevelRegex, REG_EXTENDED) != 0) {
-        ALOGE("Failed to compile platform patchlevel regex! (%s)", kPlatformPatchlevelRegex);
-        return 0;
-    }
-
-    regmatch_t matches[kPlatformPatchlevelMatchCount];
-    int not_match =
-        regexec(&regex, patchlevel_str, kPlatformPatchlevelMatchCount, matches, 0 /* flags */);
-    regfree(&regex);
-    if (not_match) {
-        ALOGI("Platform patchlevel string does not match expected format.  Using patchlevel 0");
-        return 0;
-    }
-
-    uint32_t year = match_to_uint32(patchlevel_str, matches[kYearMatch]);
-    uint32_t month = match_to_uint32(patchlevel_str, matches[kMonthMatch]);
-
-    if (month < 1 || month > 12) {
-        ALOGE("Invalid patch month %d", month);
-        return 0;
-    }
-    return year * 100 + month;
+    return GetPatchlevel(patchlevel_str, PatchlevelOutput::kYearMonth);
 }
 
 uint32_t GetOsPatchlevel() {
@@ -138,4 +158,9 @@
     return GetOsPatchlevel(patchlevel.c_str());
 }
 
+uint32_t GetVendorPatchlevel() {
+    std::string patchlevel = wait_and_get_property(kVendorPatchlevelProp);
+    return GetPatchlevel(patchlevel.c_str(), PatchlevelOutput::kYearMonthDay);
+}
+
 }  // namespace keymaster
diff --git a/android_keymaster/keymaster_enforcement.cpp b/android_keymaster/keymaster_enforcement.cpp
index 8f07cbf..de768cb 100644
--- a/android_keymaster/keymaster_enforcement.cpp
+++ b/android_keymaster/keymaster_enforcement.cpp
@@ -23,9 +23,9 @@
 #include <openssl/evp.h>
 
 #include <hardware/hw_auth_token.h>
+#include <keymaster/List.h>
 #include <keymaster/android_keymaster_utils.h>
 #include <keymaster/logger.h>
-#include <keymaster/List.h>
 
 namespace keymaster {
 
@@ -86,8 +86,8 @@
     case KM_PURPOSE_SIGN:
     case KM_PURPOSE_DECRYPT:
     case KM_PURPOSE_WRAP:
-        if (auth_set.Contains(TAG_PURPOSE, purpose))
-            return KM_ERROR_OK;
+    case KM_PURPOSE_AGREE_KEY:
+        if (auth_set.Contains(TAG_PURPOSE, purpose)) return KM_ERROR_OK;
         return KM_ERROR_INCOMPATIBLE_PURPOSE;
 
     default:
@@ -130,6 +130,8 @@
         case KM_PURPOSE_SIGN:
         case KM_PURPOSE_DERIVE_KEY:
         case KM_PURPOSE_WRAP:
+        case KM_PURPOSE_AGREE_KEY:
+        case KM_PURPOSE_ATTEST_KEY:
             break;
         };
     };
@@ -147,7 +149,6 @@
                                               const AuthorizationSet& operation_params,
                                               keymaster_operation_handle_t op_handle) {
     int auth_type_index = -1;
-    int trusted_confirmation_index = -1;
     bool no_auth_required = false;
     for (size_t pos = 0; pos < auth_set.size(); ++pos) {
         switch (auth_set[pos].tag) {
@@ -155,9 +156,6 @@
             auth_type_index = pos;
             break;
 
-        case KM_TAG_TRUSTED_CONFIRMATION_REQUIRED:
-            trusted_confirmation_index = pos;
-            break;
         case KM_TAG_NO_AUTH_REQUIRED:
         case KM_TAG_AUTH_TIMEOUT:
             // If no auth is required or if auth is timeout-based, we have nothing to check.
@@ -168,12 +166,6 @@
         }
     }
 
-    // TODO verify trusted confirmation mac once we have a shared secret established
-    // For now, since we do not have such a service, any token offered here must be invalid.
-    if (trusted_confirmation_index != -1) {
-        return KM_ERROR_NO_USER_CONFIRMATION;
-    }
-
     // If NO_AUTH_REQUIRED or AUTH_TIMEOUT was set, we need not check an auth token.
     if (no_auth_required) {
         return KM_ERROR_OK;
@@ -230,8 +222,7 @@
     }
 
     keymaster_error_t error = authorized_purpose(purpose, auth_set);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     // If successful, and if key has a min time between ops, this will be set to the time limit
     uint32_t min_ops_timeout = UINT32_MAX;
@@ -245,14 +236,12 @@
 
         // KM_TAG_PADDING_OLD and KM_TAG_DIGEST_OLD aren't actually members of the enum, so we can't
         // switch on them.  There's nothing to validate for them, though, so just ignore them.
-        if (param.tag == KM_TAG_PADDING_OLD || param.tag == KM_TAG_DIGEST_OLD)
-            continue;
+        if (param.tag == KM_TAG_PADDING_OLD || param.tag == KM_TAG_DIGEST_OLD) continue;
 
         switch (param.tag) {
 
         case KM_TAG_ACTIVE_DATETIME:
-            if (!activation_date_valid(param.date_time))
-                return KM_ERROR_KEY_NOT_YET_VALID;
+            if (!activation_date_valid(param.date_time)) return KM_ERROR_KEY_NOT_YET_VALID;
             break;
 
         case KM_TAG_ORIGINATION_EXPIRE_DATETIME:
@@ -292,6 +281,22 @@
             }
             break;
 
+        case KM_TAG_UNLOCKED_DEVICE_REQUIRED:
+            if (device_locked_at_ > 0) {
+                const hw_auth_token_t* auth_token;
+                uint32_t token_auth_type;
+                if (!GetAndValidateAuthToken(operation_params, &auth_token, &token_auth_type)) {
+                    return KM_ERROR_DEVICE_LOCKED;
+                }
+
+                uint64_t token_timestamp_millis = ntoh(auth_token->timestamp);
+                if (token_timestamp_millis <= device_locked_at_ ||
+                    (password_unlock_only_ && !(token_auth_type & HW_AUTH_PASSWORD))) {
+                    return KM_ERROR_DEVICE_LOCKED;
+                }
+            }
+            break;
+
         case KM_TAG_CALLER_NONCE:
             caller_nonce_authorized_by_key = true;
             break;
@@ -311,6 +316,11 @@
         case KM_TAG_ATTESTATION_ID_MEID:
         case KM_TAG_ATTESTATION_ID_MANUFACTURER:
         case KM_TAG_ATTESTATION_ID_MODEL:
+        case KM_TAG_DEVICE_UNIQUE_ATTESTATION:
+        case KM_TAG_CERTIFICATE_SUBJECT:
+        case KM_TAG_CERTIFICATE_SERIAL:
+        case KM_TAG_CERTIFICATE_NOT_AFTER:
+        case KM_TAG_CERTIFICATE_NOT_BEFORE:
             return KM_ERROR_INVALID_KEY_BLOB;
 
         /* Tags used for cryptographic parameters in keygen.  Nothing to enforce. */
@@ -333,12 +343,14 @@
         /* Algorithm specific parameters not used for access control. */
         case KM_TAG_RSA_PUBLIC_EXPONENT:
         case KM_TAG_ECIES_SINGLE_HASH_MODE:
+        case KM_TAG_RSA_OAEP_MGF_DIGEST:
 
         /* Informational tags. */
         case KM_TAG_CREATION_DATETIME:
         case KM_TAG_ORIGIN:
         case KM_TAG_ROLLBACK_RESISTANCE:
         case KM_TAG_ROLLBACK_RESISTANT:
+        case KM_TAG_USER_ID:
 
         /* Tags handled when KM_TAG_USER_SECURE_ID is handled */
         case KM_TAG_NO_AUTH_REQUIRED:
@@ -353,26 +365,32 @@
         case KM_TAG_APPLICATION_ID:
         case KM_TAG_OS_VERSION:
         case KM_TAG_OS_PATCHLEVEL:
+        case KM_TAG_BOOT_PATCHLEVEL:
+        case KM_TAG_VENDOR_PATCHLEVEL:
+        case KM_TAG_STORAGE_KEY:
 
         /* Ignored pending removal */
         case KM_TAG_ALL_USERS:
 
-        /* TODO(swillden): Handle these */
+        /* Tags that are not enforced by begin */
         case KM_TAG_INCLUDE_UNIQUE_ID:
         case KM_TAG_UNIQUE_ID:
         case KM_TAG_RESET_SINCE_ID_ROTATION:
         case KM_TAG_ALLOW_WHILE_ON_BODY:
         case KM_TAG_TRUSTED_CONFIRMATION_REQUIRED:
+        case KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED:
+        case KM_TAG_CONFIRMATION_TOKEN:
+        case KM_TAG_USAGE_COUNT_LIMIT:
+        case KM_TAG_MAX_BOOT_LEVEL:
             break;
 
-        /* TODO(bcyoung): This is currently handled in keystore, but may move to keymaster in the
-         * future */
-        case KM_TAG_USER_ID:
-        case KM_TAG_UNLOCKED_DEVICE_REQUIRED:
-            break;
-
+        case KM_TAG_IDENTITY_CREDENTIAL_KEY:
         case KM_TAG_BOOTLOADER_ONLY:
             return KM_ERROR_INVALID_KEY_BLOB;
+
+        case KM_TAG_EARLY_BOOT_ONLY:
+            if (!in_early_boot()) return KM_ERROR_EARLY_BOOT_ENDED;
+            break;
         }
     }
 
@@ -399,7 +417,7 @@
 
     if (update_access_count) {
         if (!access_count_map_) {
-            LOG_S("Usage-count limited keys tabel not allocated.  Count-limited keys disabled", 0);
+            LOG_S("Usage-count limited keys table not allocated.  Count-limited keys disabled", 0);
             return KM_ERROR_MEMORY_ALLOCATION_FAILED;
         }
 
@@ -413,25 +431,53 @@
 }
 
 bool KeymasterEnforcement::MinTimeBetweenOpsPassed(uint32_t min_time_between, const km_id_t keyid) {
-    if (!access_time_map_)
-        return false;
+    if (!access_time_map_) return false;
 
     uint32_t last_access_time;
-    if (!access_time_map_->LastKeyAccessTime(keyid, &last_access_time))
-        return true;
+    if (!access_time_map_->LastKeyAccessTime(keyid, &last_access_time)) return true;
     return min_time_between <= static_cast<int64_t>(get_current_time()) - last_access_time;
 }
 
 bool KeymasterEnforcement::MaxUsesPerBootNotExceeded(const km_id_t keyid, uint32_t max_uses) {
-    if (!access_count_map_)
-        return false;
+    if (!access_count_map_) return false;
 
     uint32_t key_access_count;
-    if (!access_count_map_->KeyAccessCount(keyid, &key_access_count))
-        return true;
+    if (!access_count_map_->KeyAccessCount(keyid, &key_access_count)) return true;
     return key_access_count < max_uses;
 }
 
+bool KeymasterEnforcement::GetAndValidateAuthToken(const AuthorizationSet& operation_params,
+                                                   const hw_auth_token_t** auth_token,
+                                                   uint32_t* token_auth_type) const {
+    keymaster_blob_t auth_token_blob;
+    if (!operation_params.GetTagValue(TAG_AUTH_TOKEN, &auth_token_blob)) {
+        LOG_E("Authentication required, but auth token not provided", 0);
+        return false;
+    }
+
+    if (auth_token_blob.data_length != sizeof(**auth_token)) {
+        LOG_E("Bug: Auth token is the wrong size (%d expected, %d found)", sizeof(hw_auth_token_t),
+              auth_token_blob.data_length);
+        return false;
+    }
+
+    *auth_token = reinterpret_cast<const hw_auth_token_t*>(auth_token_blob.data);
+    if ((*auth_token)->version != HW_AUTH_TOKEN_VERSION) {
+        LOG_E("Bug: Auth token is the version %d (or is not an auth token). Expected %d",
+              (*auth_token)->version, HW_AUTH_TOKEN_VERSION);
+        return false;
+    }
+
+    if (!ValidateTokenSignature(**auth_token)) {
+        LOG_E("Auth token signature invalid", 0);
+        return false;
+    }
+
+    *token_auth_type = ntoh((*auth_token)->authenticator_type);
+
+    return true;
+}
+
 bool KeymasterEnforcement::AuthTokenMatches(const AuthProxy& auth_set,
                                             const AuthorizationSet& operation_params,
                                             const uint64_t user_secure_id,
@@ -441,39 +487,18 @@
     assert(auth_type_index < static_cast<int>(auth_set.size()));
     assert(auth_timeout_index < static_cast<int>(auth_set.size()));
 
-    keymaster_blob_t auth_token_blob;
-    if (!operation_params.GetTagValue(TAG_AUTH_TOKEN, &auth_token_blob)) {
-        LOG_E("Authentication required, but auth token not provided", 0);
+    const hw_auth_token_t* auth_token;
+    uint32_t token_auth_type;
+    if (!GetAndValidateAuthToken(operation_params, &auth_token, &token_auth_type)) return false;
+
+    if (auth_timeout_index == -1 && op_handle && op_handle != auth_token->challenge) {
+        LOG_E("Auth token has the challenge %llu, need %llu", auth_token->challenge, op_handle);
         return false;
     }
 
-    if (auth_token_blob.data_length != sizeof(hw_auth_token_t)) {
-        LOG_E("Bug: Auth token is the wrong size (%d expected, %d found)", sizeof(hw_auth_token_t),
-              auth_token_blob.data_length);
-        return false;
-    }
-
-    hw_auth_token_t auth_token;
-    memcpy(&auth_token, auth_token_blob.data, sizeof(hw_auth_token_t));
-    if (auth_token.version != HW_AUTH_TOKEN_VERSION) {
-        LOG_E("Bug: Auth token is the version %d (or is not an auth token). Expected %d",
-              auth_token.version, HW_AUTH_TOKEN_VERSION);
-        return false;
-    }
-
-    if (!ValidateTokenSignature(auth_token)) {
-        LOG_E("Auth token signature invalid", 0);
-        return false;
-    }
-
-    if (auth_timeout_index == -1 && op_handle && op_handle != auth_token.challenge) {
-        LOG_E("Auth token has the challenge %llu, need %llu", auth_token.challenge, op_handle);
-        return false;
-    }
-
-    if (user_secure_id != auth_token.user_id && user_secure_id != auth_token.authenticator_id) {
-        LOG_I("Auth token SIDs %llu and %llu do not match key SID %llu", auth_token.user_id,
-              auth_token.authenticator_id, user_secure_id);
+    if (user_secure_id != auth_token->user_id && user_secure_id != auth_token->authenticator_id) {
+        LOG_I("Auth token SIDs %llu and %llu do not match key SID %llu", auth_token->user_id,
+              auth_token->authenticator_id, user_secure_id);
         return false;
     }
 
@@ -483,11 +508,9 @@
     }
 
     assert(auth_set[auth_type_index].tag == KM_TAG_USER_AUTH_TYPE);
-    if (auth_set[auth_type_index].tag != KM_TAG_USER_AUTH_TYPE)
-        return false;
+    if (auth_set[auth_type_index].tag != KM_TAG_USER_AUTH_TYPE) return false;
 
     uint32_t key_auth_type_mask = auth_set[auth_type_index].integer;
-    uint32_t token_auth_type = ntoh(auth_token.authenticator_type);
     if ((key_auth_type_mask & token_auth_type) == 0) {
         LOG_E("Key requires match of auth type mask 0%uo, but token contained 0%uo",
               key_auth_type_mask, token_auth_type);
@@ -496,10 +519,9 @@
 
     if (auth_timeout_index != -1 && is_begin_operation) {
         assert(auth_set[auth_timeout_index].tag == KM_TAG_AUTH_TIMEOUT);
-        if (auth_set[auth_timeout_index].tag != KM_TAG_AUTH_TIMEOUT)
-            return false;
+        if (auth_set[auth_timeout_index].tag != KM_TAG_AUTH_TIMEOUT) return false;
 
-        if (auth_token_timed_out(auth_token, auth_set[auth_timeout_index].integer)) {
+        if (auth_token_timed_out(*auth_token, auth_set[auth_timeout_index].integer)) {
             LOG_E("Auth token has timed out", 0);
             return false;
         }
@@ -509,6 +531,10 @@
     return true;
 }
 
+keymaster_error_t KeymasterEnforcement::GenerateTimestampToken(TimestampToken* /*token*/) {
+    return KM_ERROR_UNIMPLEMENTED;
+}
+
 bool AccessTimeMap::LastKeyAccessTime(km_id_t keyid, uint32_t* last_access_time) const {
     for (auto& entry : last_access_list_)
         if (entry.keyid == keyid) {
@@ -534,8 +560,7 @@
             ++iter;
     }
 
-    if (last_access_list_.size() >= max_size_)
-        return false;
+    if (last_access_list_.size() >= max_size_) return false;
 
     AccessTime new_entry;
     new_entry.keyid = keyid;
@@ -562,13 +587,11 @@
             // operation requests will be rejected and access_count won't be incremented any more.
             // And, besides, UINT64_MAX is huge.  But we ensure that it doesn't wrap anyway, out of
             // an abundance of caution.
-            if (entry.access_count < UINT64_MAX)
-                ++entry.access_count;
+            if (entry.access_count < UINT64_MAX) ++entry.access_count;
             return true;
         }
 
-    if (access_count_list_.size() >= max_size_)
-        return false;
+    if (access_count_list_.size() >= max_size_) return false;
 
     AccessCount new_entry;
     new_entry.keyid = keyid;
diff --git a/android_keymaster/keymaster_stl.cpp b/android_keymaster/keymaster_stl.cpp
deleted file mode 100644
index 62c486c..0000000
--- a/android_keymaster/keymaster_stl.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
-**
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <keymaster/new.h>
-#include <stdlib.h>
-
-namespace std {
-struct nothrow_t {};
-}
-
-extern const std::nothrow_t __attribute__((weak)) std::nothrow = {};
-
-void* __attribute__((weak)) operator new(size_t __sz, const std::nothrow_t&) {
-    return malloc(__sz);
-}
-void* __attribute__((weak)) operator new[](size_t __sz, const std::nothrow_t&) {
-    return malloc(__sz);
-}
-
-void __attribute__((weak)) operator delete(void* ptr) {
-    if (ptr)
-        free(ptr);
-}
-
-void __attribute__((weak)) operator delete[](void* ptr) {
-    if (ptr)
-        free(ptr);
-}
-
-extern "C" {
-void __attribute__((weak)) __cxa_pure_virtual() {
-    abort();
-}
-}
diff --git a/android_keymaster/keymaster_tags.cpp b/android_keymaster/keymaster_tags.cpp
index 8716c1f..dc42061 100644
--- a/android_keymaster/keymaster_tags.cpp
+++ b/android_keymaster/keymaster_tags.cpp
@@ -55,6 +55,8 @@
         return "KM_TAG_MIN_SECONDS_BETWEEN_OPS";
     case KM_TAG_MAX_USES_PER_BOOT:
         return "KM_TAG_MAX_USES_PER_BOOT";
+    case KM_TAG_USAGE_COUNT_LIMIT:
+        return "KM_TAG_USAGE_COUNT_LIMIT";
     case KM_TAG_ALL_USERS:
         return "KM_TAG_ALL_USERS";
     case KM_TAG_USER_ID:
@@ -135,6 +137,34 @@
         return "KM_TAG_ATTESTATION_ID_MANUFACTURER";
     case KM_TAG_ATTESTATION_ID_MODEL:
         return "KM_TAG_ATTESTATION_ID_MODEL";
+    case KM_TAG_EARLY_BOOT_ONLY:
+        return "KM_TAG_EARLY_BOOT_ONLY";
+    case KM_TAG_DEVICE_UNIQUE_ATTESTATION:
+        return "KM_TAG_DEVICE_UNIQUE_ATTESTATION";
+    case KM_TAG_IDENTITY_CREDENTIAL_KEY:
+        return "KM_TAG_IDENTITY_CREDENTIAL_KEY";
+    case KM_TAG_CONFIRMATION_TOKEN:
+        return "KM_TAG_CONFIRMATION_TOKEN";
+    case KM_TAG_CERTIFICATE_SERIAL:
+        return "KM_TAG_CERTIFICATE_SERIAL";
+    case KM_TAG_CERTIFICATE_SUBJECT:
+        return "KM_TAG_CERTIFICATE_SUBJECT";
+    case KM_TAG_CERTIFICATE_NOT_BEFORE:
+        return "KM_TAG_CERTIFICATE_NOT_BEFORE";
+    case KM_TAG_CERTIFICATE_NOT_AFTER:
+        return "KM_TAG_CERTIFICATE_NOT_AFTER";
+    case KM_TAG_STORAGE_KEY:
+        return "KM_TAG_STORAGE_KEY";
+    case KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED:
+        return "KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED";
+    case KM_TAG_BOOT_PATCHLEVEL:
+        return "KM_TAG_BOOT_PATCHLEVEL";
+    case KM_TAG_VENDOR_PATCHLEVEL:
+        return "KM_TAG_VENDOR_PATCHLEVEL";
+    case KM_TAG_RSA_OAEP_MGF_DIGEST:
+        return "KM_TAG_RSA_OAEP_MGF_DIGEST";
+    case KM_TAG_MAX_BOOT_LEVEL:
+        return "KM_TAG_MAX_BOOT_LEVEL";
     }
     return "<Unknown>";
 }
@@ -156,6 +186,7 @@
 DEFINE_KEYMASTER_TAG(KM_DATE, TAG_USAGE_EXPIRE_DATETIME);
 DEFINE_KEYMASTER_TAG(KM_UINT, TAG_MIN_SECONDS_BETWEEN_OPS);
 DEFINE_KEYMASTER_TAG(KM_UINT, TAG_MAX_USES_PER_BOOT);
+DEFINE_KEYMASTER_TAG(KM_UINT, TAG_USAGE_COUNT_LIMIT);
 DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_ALL_USERS);
 DEFINE_KEYMASTER_TAG(KM_UINT, TAG_USER_ID);
 DEFINE_KEYMASTER_TAG(KM_ULONG_REP, TAG_USER_SECURE_ID);
@@ -176,6 +207,7 @@
 DEFINE_KEYMASTER_TAG(KM_UINT, TAG_OS_VERSION);
 DEFINE_KEYMASTER_TAG(KM_UINT, TAG_OS_PATCHLEVEL);
 DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_UNIQUE_ID);
+DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_ATTESTATION_CHALLENGE);
 DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_ATTESTATION_APPLICATION_ID);
 DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_ATTESTATION_ID_BRAND);
 DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_ATTESTATION_ID_DEVICE);
@@ -187,6 +219,19 @@
 DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_ATTESTATION_ID_MODEL);
 DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_UNLOCKED_DEVICE_REQUIRED);
 DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_TRUSTED_CONFIRMATION_REQUIRED);
+DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_EARLY_BOOT_ONLY);
+DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_DEVICE_UNIQUE_ATTESTATION);
+DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_IDENTITY_CREDENTIAL_KEY);
+DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_TRUSTED_USER_PRESENCE_REQUIRED);
+DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_CONFIRMATION_TOKEN);
+DEFINE_KEYMASTER_TAG(KM_BIGNUM, TAG_CERTIFICATE_SERIAL);
+DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_CERTIFICATE_SUBJECT);
+DEFINE_KEYMASTER_TAG(KM_DATE, TAG_CERTIFICATE_NOT_BEFORE);
+DEFINE_KEYMASTER_TAG(KM_DATE, TAG_CERTIFICATE_NOT_AFTER);
+DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_STORAGE_KEY);
+DEFINE_KEYMASTER_TAG(KM_UINT, TAG_BOOT_PATCHLEVEL);
+DEFINE_KEYMASTER_TAG(KM_UINT, TAG_VENDOR_PATCHLEVEL);
+DEFINE_KEYMASTER_TAG(KM_UINT, TAG_MAX_BOOT_LEVEL);
 
 // DEFINE_KEYMASTER_ENUM_TAG is used to create TypedEnumTag instances for each enum keymaster tag.
 
@@ -205,5 +250,6 @@
 DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_USER_AUTH_TYPE, hw_authenticator_type_t);
 DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_KDF, keymaster_kdf_t);
 DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_EC_CURVE, keymaster_ec_curve_t);
+DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_RSA_OAEP_MGF_DIGEST, keymaster_digest_t);
 
 }  // namespace keymaster
diff --git a/android_keymaster/logger.cpp b/android_keymaster/logger.cpp
index 0d1d4af..fdee6a0 100644
--- a/android_keymaster/logger.cpp
+++ b/android_keymaster/logger.cpp
@@ -21,13 +21,14 @@
 Logger* Logger::instance_ = nullptr;
 
 /* static */
+// NOLINTNEXTLINE(cert-dcl50-cpp)
 int Logger::Log(LogLevel level, const char* fmt, va_list args) {
-    if (!instance_)
-        return 0;
+    if (!instance_) return 0;
     return instance_->log_msg(level, fmt, args);
 }
 
 /* static */
+// NOLINTNEXTLINE(cert-dcl50-cpp)
 int Logger::Log(LogLevel level, const char* fmt, ...) {
     va_list args;
     va_start(args, fmt);
@@ -37,6 +38,7 @@
 }
 
 /* static */
+// NOLINTNEXTLINE(cert-dcl50-cpp)
 int Logger::Debug(const char* fmt, ...) {
     va_list args;
     va_start(args, fmt);
@@ -46,6 +48,7 @@
 }
 
 /* static */
+// NOLINTNEXTLINE(cert-dcl50-cpp)
 int Logger::Info(const char* fmt, ...) {
     va_list args;
     va_start(args, fmt);
@@ -53,7 +56,9 @@
     va_end(args);
     return result;
 }
+
 /* static */
+// NOLINTNEXTLINE(cert-dcl50-cpp)
 int Logger::Warning(const char* fmt, ...) {
     va_list args;
     va_start(args, fmt);
@@ -61,7 +66,9 @@
     va_end(args);
     return result;
 }
+
 /* static */
+// NOLINTNEXTLINE(cert-dcl50-cpp)
 int Logger::Error(const char* fmt, ...) {
     va_list args;
     va_start(args, fmt);
@@ -69,7 +76,9 @@
     va_end(args);
     return result;
 }
+
 /* static */
+// NOLINTNEXTLINE(cert-dcl50-cpp)
 int Logger::Severe(const char* fmt, ...) {
     va_list args;
     va_start(args, fmt);
@@ -78,5 +87,4 @@
     return result;
 }
 
-
 }  // namespace keymaster
diff --git a/android_keymaster/operation.cpp b/android_keymaster/operation.cpp
index 3180ab0..8d94b3c 100644
--- a/android_keymaster/operation.cpp
+++ b/android_keymaster/operation.cpp
@@ -18,15 +18,13 @@
 #include <keymaster/key.h>
 #include <keymaster/operation.h>
 
-
 namespace keymaster {
 
 bool OperationFactory::supported(keymaster_padding_t padding) const {
     size_t padding_count;
     const keymaster_padding_t* supported_paddings = SupportedPaddingModes(&padding_count);
     for (size_t i = 0; i < padding_count; ++i)
-        if (padding == supported_paddings[i])
-            return true;
+        if (padding == supported_paddings[i]) return true;
     return false;
 }
 
@@ -34,8 +32,7 @@
     size_t block_mode_count;
     const keymaster_block_mode_t* supported_block_modes = SupportedBlockModes(&block_mode_count);
     for (size_t i = 0; i < block_mode_count; ++i)
-        if (block_mode == supported_block_modes[i])
-            return true;
+        if (block_mode == supported_block_modes[i]) return true;
     return false;
 }
 
@@ -43,8 +40,7 @@
     size_t digest_count;
     const keymaster_digest_t* supported_digests = SupportedDigests(&digest_count);
     for (size_t i = 0; i < digest_count; ++i)
-        if (digest == supported_digests[i])
-            return true;
+        if (digest == supported_digests[i]) return true;
     return false;
 }
 
@@ -67,8 +63,7 @@
 bool OperationFactory::is_public_key_operation() const {
     KeyType key_type = registry_key();
 
-    if (!is_public_key_algorithm(key_type.algorithm))
-        return false;
+    if (!is_public_key_algorithm(key_type.algorithm)) return false;
 
     switch (key_type.purpose) {
     case KM_PURPOSE_VERIFY:
@@ -78,6 +73,8 @@
     case KM_PURPOSE_SIGN:
     case KM_PURPOSE_DECRYPT:
     case KM_PURPOSE_DERIVE_KEY:
+    case KM_PURPOSE_AGREE_KEY:
+    case KM_PURPOSE_ATTEST_KEY:
         return false;
     };
 
@@ -129,7 +126,7 @@
             *digest = KM_DIGEST_NONE;
         } else {
             LOG_E("%d digests specified in begin params and NONE not authorized",
-                    begin_params.GetTagCount(TAG_DIGEST));
+                  begin_params.GetTagCount(TAG_DIGEST));
             return false;
         }
     } else if (!supported(*digest)) {
@@ -157,8 +154,7 @@
         AuthorizationSet output_params;
         keymaster_error_t error =
             Update(input_params, input, &output_params, &output, &input_consumed);
-        if (error != KM_ERROR_OK)
-            return error;
+        if (error != KM_ERROR_OK) return error;
         assert(input_consumed == input.available_read());
         assert(output_params.empty());
         assert(output.available_read() == 0);
diff --git a/android_keymaster/operation_table.cpp b/android_keymaster/operation_table.cpp
index ff9d2bb..50d47f5 100644
--- a/android_keymaster/operation_table.cpp
+++ b/android_keymaster/operation_table.cpp
@@ -14,19 +14,16 @@
  * limitations under the License.
  */
 
-#include <keymaster/operation_table.h>
-#include <keymaster/operation.h>
 #include <keymaster/android_keymaster_utils.h>
-
-#include <keymaster/new.h>
+#include <keymaster/operation.h>
+#include <keymaster/operation_table.h>
 
 namespace keymaster {
 
 keymaster_error_t OperationTable::Add(OperationPtr&& operation) {
     if (!table_) {
         table_.reset(new (std::nothrow) OperationPtr[table_size_]);
-        if (!table_)
-            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        if (!table_) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
     }
     for (size_t i = 0; i < table_size_; ++i) {
         if (!table_[i]) {
@@ -38,22 +35,18 @@
 }
 
 Operation* OperationTable::Find(keymaster_operation_handle_t op_handle) {
-    if (op_handle == 0)
-        return nullptr;
+    if (op_handle == 0) return nullptr;
 
-    if (!table_.get())
-        return nullptr;
+    if (!table_.get()) return nullptr;
 
     for (size_t i = 0; i < table_size_; ++i) {
-        if (table_[i] && table_[i]->operation_handle() == op_handle)
-            return table_[i].get();
+        if (table_[i] && table_[i]->operation_handle() == op_handle) return table_[i].get();
     }
     return nullptr;
 }
 
 bool OperationTable::Delete(keymaster_operation_handle_t op_handle) {
-    if (!table_.get())
-        return false;
+    if (!table_.get()) return false;
 
     for (size_t i = 0; i < table_size_; ++i) {
         if (table_[i] && table_[i]->operation_handle() == op_handle) {
diff --git a/android_keymaster/pure_soft_secure_key_storage.cpp b/android_keymaster/pure_soft_secure_key_storage.cpp
new file mode 100644
index 0000000..2c0a739
--- /dev/null
+++ b/android_keymaster/pure_soft_secure_key_storage.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <keymaster/pure_soft_secure_key_storage.h>
+
+#include <vector>
+
+#include <keymaster/logger.h>
+
+namespace keymaster {
+
+class PureSoftSecureStorageMap {
+  public:
+    explicit PureSoftSecureStorageMap(uint32_t max_size) : max_size_(max_size) {}
+
+    /* Writes key id into pure software secure storage. Returns false if the list has
+     * already reached maximum size. */
+    bool WriteKey(km_id_t keyid);
+
+    /* Checks if the key id exists in the list. */
+    bool KeyExists(km_id_t keyid) const;
+
+    /* Deletes the key id from the list, if it is not existed then do nothing. */
+    void DeleteKey(km_id_t keyid);
+
+    /* Deletes all key ids from the list. */
+    void DeleteAllKeys();
+
+    /* Checks if there is still available slot to write key. */
+    bool HasSlot() const;
+
+  private:
+    std::vector<km_id_t> keyid_list_;
+    const uint32_t max_size_;
+};
+
+bool PureSoftSecureStorageMap::WriteKey(km_id_t keyid) {
+    if (keyid_list_.size() >= max_size_) return false;
+    keyid_list_.push_back(keyid);
+    return true;
+}
+
+bool PureSoftSecureStorageMap::KeyExists(km_id_t keyid) const {
+    for (km_id_t key_id : keyid_list_)
+        if (key_id == keyid) return true;
+    return false;
+}
+
+void PureSoftSecureStorageMap::DeleteKey(km_id_t keyid) {
+    std::vector<km_id_t>::iterator iter;
+    for (iter = keyid_list_.begin(); iter != keyid_list_.end();) {
+        if (*iter == keyid)
+            iter = keyid_list_.erase(iter);
+        else
+            ++iter;
+    }
+}
+
+void PureSoftSecureStorageMap::DeleteAllKeys() {
+    keyid_list_.clear();
+}
+
+bool PureSoftSecureStorageMap::HasSlot() const {
+    return keyid_list_.size() < max_size_;
+}
+
+PureSoftSecureKeyStorage::PureSoftSecureKeyStorage(uint32_t max_slot)
+    : pure_soft_secure_storage_map_(new (std::nothrow) PureSoftSecureStorageMap(max_slot)) {}
+
+PureSoftSecureKeyStorage::~PureSoftSecureKeyStorage() {
+    delete pure_soft_secure_storage_map_;
+}
+
+keymaster_error_t PureSoftSecureKeyStorage::WriteKey(const km_id_t keyid,
+                                                     const KeymasterKeyBlob& /* blob */) {
+    if (!pure_soft_secure_storage_map_) {
+        LOG_S("Pure software secure key storage table not allocated.", 0);
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    if (!pure_soft_secure_storage_map_->WriteKey(keyid)) {
+        LOG_E("Pure software secure key storage slot full.", 0);
+        return KM_ERROR_UNKNOWN_ERROR;
+    }
+
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t PureSoftSecureKeyStorage::KeyExists(const km_id_t keyid, bool* exists) {
+    if (!pure_soft_secure_storage_map_) {
+        LOG_S("Pure software secure key storage table not allocated.", 0);
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    *exists = pure_soft_secure_storage_map_->KeyExists(keyid);
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t PureSoftSecureKeyStorage::DeleteKey(const km_id_t keyid) {
+    if (!pure_soft_secure_storage_map_) {
+        LOG_S("Pure software secure key storage table not allocated.", 0);
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    pure_soft_secure_storage_map_->DeleteKey(keyid);
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t PureSoftSecureKeyStorage::DeleteAllKeys() {
+    if (!pure_soft_secure_storage_map_) {
+        LOG_S("Pure software secure key storage table not allocated.", 0);
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    pure_soft_secure_storage_map_->DeleteAllKeys();
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t PureSoftSecureKeyStorage::HasSlot(bool* has_slot) {
+    if (!pure_soft_secure_storage_map_) {
+        LOG_S("Pure software secure key storage table not allocated.", 0);
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    *has_slot = pure_soft_secure_storage_map_->HasSlot();
+    return KM_ERROR_OK;
+}
+
+}  // namespace keymaster
diff --git a/android_keymaster/remote_provisioning_utils.cpp b/android_keymaster/remote_provisioning_utils.cpp
new file mode 100644
index 0000000..8cb635b
--- /dev/null
+++ b/android_keymaster/remote_provisioning_utils.cpp
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "keymaster/cppcose/cppcose.h"
+#include <keymaster/logger.h>
+#include <keymaster/remote_provisioning_utils.h>
+#include <string_view>
+
+namespace keymaster {
+
+using cppcose::ALGORITHM;
+using cppcose::COSE_KEY;
+using cppcose::CoseKey;
+using cppcose::CoseKeyCurve;
+using cppcose::EC2;
+using cppcose::ECDH_ES_HKDF_256;
+using cppcose::ES256;
+using cppcose::generateCoseMac0Mac;
+using cppcose::HMAC_256;
+using cppcose::kCoseMac0EntryCount;
+using cppcose::kCoseMac0Payload;
+using cppcose::kCoseMac0ProtectedParams;
+using cppcose::kCoseMac0Tag;
+using cppcose::kCoseMac0UnprotectedParams;
+using cppcose::KEY_ID;
+using cppcose::OCTET_KEY_PAIR;
+using cppcose::P256;
+using cppcose::verifyAndParseCoseSign1;
+
+using byte_view = std::basic_string_view<uint8_t>;
+
+struct KeyInfo {
+    CoseKeyCurve curve;
+    byte_view pubkey;
+    // Note: There's no need to include algorithm here, since it is assumed
+    //       that all root keys are EDDSA.
+
+    bool operator==(const KeyInfo& other) const {
+        return curve == other.curve && pubkey == other.pubkey;
+    }
+};
+
+// The production root signing key for Google Endpoint Encryption Key cert chains.
+inline constexpr uint8_t kGeekRoot[] = {
+    0x99, 0xB9, 0xEE, 0xDD, 0x5E, 0xE4, 0x52, 0xF6, 0x85, 0xC6, 0x4C, 0x62, 0xDC, 0x3E, 0x61, 0xAB,
+    0x57, 0x48, 0x7D, 0x75, 0x37, 0x29, 0xAD, 0x76, 0x80, 0x32, 0xD2, 0xB3, 0xCB, 0x63, 0x58, 0xD9};
+
+// Hard-coded set of acceptable public COSE_Keys that can act as roots of EEK chains.
+inline constexpr KeyInfo kAuthorizedEekRoots[] = {
+    {CoseKeyCurve::ED25519, byte_view(kGeekRoot, sizeof(kGeekRoot))},
+};
+
+StatusOr<std::pair<std::vector<uint8_t> /* EEK pub */, std::vector<uint8_t> /* EEK ID */>>
+validateAndExtractEekPubAndId(bool testMode, const KeymasterBlob& endpointEncryptionCertChain) {
+    auto [item, newPos, errMsg] =
+        cppbor::parse(endpointEncryptionCertChain.begin(), endpointEncryptionCertChain.end());
+
+    if (!item || !item->asArray()) {
+        LOG_E("Error parsing EEK chain: %s", errMsg.c_str());
+        return kStatusFailed;
+    }
+
+    const cppbor::Array* certArr = item->asArray();
+    std::vector<uint8_t> lastPubKey;
+    for (size_t i = 0; i < certArr->size(); ++i) {
+        auto cosePubKey =
+            verifyAndParseCoseSign1(certArr->get(i)->asArray(), lastPubKey, {} /* AAD */);
+        if (!cosePubKey) {
+            LOG_E("Failed to validate EEK chain: %s", cosePubKey.moveMessage().c_str());
+            return kStatusInvalidEek;
+        }
+        lastPubKey = *std::move(cosePubKey);
+
+        // In prod mode the first pubkey should match a well-known Google public key.
+        if (!testMode && i == 0) {
+            auto parsedPubKey = CoseKey::parse(lastPubKey);
+            if (!parsedPubKey) {
+                LOG_E("%s", parsedPubKey.moveMessage().c_str());
+                return kStatusFailed;
+            }
+
+            auto curve = parsedPubKey->getIntValue(CoseKey::CURVE);
+            if (!curve) {
+                LOG_E("Key is missing required label 'CURVE'", 0);
+                return kStatusInvalidEek;
+            }
+
+            auto rawPubKey = parsedPubKey->getBstrValue(CoseKey::PUBKEY_X);
+            if (!rawPubKey) {
+                LOG_E("Key is missing required label 'PUBKEY_X'", 0);
+                return kStatusInvalidEek;
+            }
+
+            KeyInfo matcher = {static_cast<CoseKeyCurve>(*curve),
+                               byte_view(rawPubKey->data(), rawPubKey->size())};
+            if (std::find(std::begin(kAuthorizedEekRoots), std::end(kAuthorizedEekRoots),
+                          matcher) == std::end(kAuthorizedEekRoots)) {
+                LOG_E("Unrecognized root of EEK chain", 0);
+                return kStatusInvalidEek;
+            }
+        }
+    }
+
+    auto eek = CoseKey::parseX25519(lastPubKey, true /* requireKid */);
+    if (!eek) {
+        LOG_E("Failed to get EEK: %s", eek.moveMessage().c_str());
+        return kStatusInvalidEek;
+    }
+
+    return std::make_pair(eek->getBstrValue(CoseKey::PUBKEY_X).value(),
+                          eek->getBstrValue(CoseKey::KEY_ID).value());
+}
+
+StatusOr<std::vector<uint8_t> /* pubkeys */>
+validateAndExtractPubkeys(bool testMode, uint32_t numKeys, KeymasterBlob* keysToSign,
+                          cppcose::HmacSha256Function macFunction) {
+    auto pubKeysToMac = cppbor::Array();
+    for (size_t i = 0; i < numKeys; i++) {
+        auto [macedKeyItem, _, coseMacErrMsg] =
+            cppbor::parse(keysToSign[i].begin(), keysToSign[i].end());
+        if (!macedKeyItem || !macedKeyItem->asArray() ||
+            macedKeyItem->asArray()->size() != kCoseMac0EntryCount) {
+            LOG_E("Invalid COSE_Mac0 structure", 0);
+            return kStatusFailed;
+        }
+
+        auto protectedParms = macedKeyItem->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
+        auto unprotectedParms = macedKeyItem->asArray()->get(kCoseMac0UnprotectedParams)->asMap();
+        auto payload = macedKeyItem->asArray()->get(kCoseMac0Payload)->asBstr();
+        auto tag = macedKeyItem->asArray()->get(kCoseMac0Tag)->asBstr();
+        if (!protectedParms || !unprotectedParms || !payload || !tag) {
+            LOG_E("Invalid COSE_Mac0 contents", 0);
+            return kStatusFailed;
+        }
+
+        auto [protectedMap, __, errMsg] = cppbor::parse(protectedParms);
+        if (!protectedMap || !protectedMap->asMap()) {
+            LOG_E("Invalid Mac0 protected: %s", errMsg.c_str());
+            return kStatusFailed;
+        }
+        auto& algo = protectedMap->asMap()->get(ALGORITHM);
+        if (!algo || !algo->asInt() || algo->asInt()->value() != HMAC_256) {
+            LOG_E("Unsupported Mac0 algorithm", 0);
+            return kStatusFailed;
+        }
+
+        auto pubKey = CoseKey::parse(payload->value(), EC2, ES256, P256);
+        if (!pubKey) {
+            LOG_E("%s", pubKey.moveMessage().c_str());
+            return kStatusFailed;
+        }
+
+        bool testKey = static_cast<bool>(pubKey->getMap().get(CoseKey::TEST_KEY));
+        if (testMode && !testKey) {
+            LOG_E("Production key in test request", 0);
+            return kStatusProductionKeyInTestRequest;
+        } else if (!testMode && testKey) {
+            LOG_E("Test key in production request", 0);
+            return kStatusTestKeyInProductionRequest;
+        }
+
+        auto macTag = generateCoseMac0Mac(macFunction, {} /* external_aad */, payload->value());
+        if (!macTag) {
+            LOG_E("%s", macTag.moveMessage().c_str());
+            return kStatusInvalidMac;
+        }
+        if (macTag->size() != tag->value().size() ||
+            CRYPTO_memcmp(macTag->data(), tag->value().data(), macTag->size()) != 0) {
+            LOG_E("MAC tag mismatch", 0);
+            return kStatusInvalidMac;
+        }
+
+        pubKeysToMac.add(pubKey->moveMap());
+    }
+
+    return pubKeysToMac.encode();
+}
+
+cppbor::Array buildCertReqRecipients(const std::vector<uint8_t>& pubkey,
+                                     const std::vector<uint8_t>& kid) {
+    return cppbor::Array()           // Array of recipients
+        .add(cppbor::Array()         // Recipient
+                 .add(cppbor::Map()  // Protected
+                          .add(ALGORITHM, ECDH_ES_HKDF_256)
+                          .canonicalize()
+                          .encode())
+                 .add(cppbor::Map()  // Unprotected
+                          .add(COSE_KEY, cppbor::Map()
+                                             .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
+                                             .add(CoseKey::CURVE, cppcose::X25519)
+                                             .add(CoseKey::PUBKEY_X, pubkey)
+                                             .canonicalize())
+                          .add(KEY_ID, kid)
+                          .canonicalize())
+                 .add(cppbor::Null()));  // No ciphertext
+}
+
+}  // namespace keymaster
diff --git a/android_keymaster/serializable.cpp b/android_keymaster/serializable.cpp
index 1f795e2..b1f1e31 100644
--- a/android_keymaster/serializable.cpp
+++ b/android_keymaster/serializable.cpp
@@ -18,8 +18,6 @@
 
 #include <assert.h>
 
-#include <keymaster/new.h>
-
 #include <keymaster/android_keymaster_utils.h>
 
 namespace keymaster {
@@ -33,7 +31,7 @@
     return (!overflow_occurred) && (buf_next <= __pval(end));
 }
 
-}
+}  // namespace
 
 uint8_t* append_to_buf(uint8_t* buf, const uint8_t* end, const void* data, size_t data_len) {
     if (buffer_bound_check(buf, end, data_len)) {
@@ -56,8 +54,7 @@
 
 bool copy_size_and_data_from_buf(const uint8_t** buf_ptr, const uint8_t* end, size_t* size,
                                  UniquePtr<uint8_t[]>* dest) {
-    if (!copy_uint32_from_buf(buf_ptr, end, size))
-        return false;
+    if (!copy_uint32_from_buf(buf_ptr, end, size)) return false;
 
     if (*size == 0) {
         dest->reset();
@@ -79,8 +76,7 @@
     if (available_write() < size) {
         size_t new_size = buffer_size_ + size - available_write();
         uint8_t* new_buffer = new (std::nothrow) uint8_t[new_size];
-        if (!new_buffer)
-            return false;
+        if (!new_buffer) return false;
         memcpy(new_buffer, buffer_.get() + read_position_, available_read());
         memset_s(buffer_.get(), 0, buffer_size_);
         buffer_.reset(new_buffer);
@@ -94,8 +90,7 @@
 bool Buffer::Reinitialize(size_t size) {
     Clear();
     buffer_.reset(new (std::nothrow) uint8_t[size]);
-    if (!buffer_.get())
-        return false;
+    if (!buffer_.get()) return false;
     buffer_size_ = size;
     read_position_ = 0;
     write_position_ = 0;
@@ -107,8 +102,7 @@
     if (__pval(data) + data_len < __pval(data))  // Pointer wrap check
         return false;
     buffer_.reset(new (std::nothrow) uint8_t[data_len]);
-    if (!buffer_.get())
-        return false;
+    if (!buffer_.get()) return false;
     buffer_size_ = data_len;
     memcpy(buffer_.get(), data, data_len);
     read_position_ = 0;
@@ -128,16 +122,14 @@
 }
 
 bool Buffer::write(const uint8_t* src, size_t write_length) {
-    if (available_write() < write_length)
-        return false;
+    if (available_write() < write_length) return false;
     memcpy(buffer_.get() + write_position_, src, write_length);
     write_position_ += write_length;
     return true;
 }
 
 bool Buffer::read(uint8_t* dest, size_t read_length) {
-    if (available_read() < read_length)
-        return false;
+    if (available_read() < read_length) return false;
     memcpy(dest, buffer_.get() + read_position_, read_length);
     read_position_ += read_length;
     return true;
diff --git a/contexts/keymaster1_passthrough_context.cpp b/contexts/keymaster1_passthrough_context.cpp
index dab8f37..b15cdb3 100644
--- a/contexts/keymaster1_passthrough_context.cpp
+++ b/contexts/keymaster1_passthrough_context.cpp
@@ -17,37 +17,38 @@
 
 #include <keymaster/contexts/keymaster1_passthrough_context.h>
 
-#include <keymaster/legacy_support/keymaster_passthrough_key.h>
-#include <keymaster/legacy_support/keymaster_passthrough_engine.h>
-#include <keymaster/legacy_support/keymaster1_legacy_support.h>
-#include <keymaster/legacy_support/keymaster1_engine.h>
-#include <keymaster/legacy_support/rsa_keymaster1_key.h>
-#include <keymaster/legacy_support/ec_keymaster1_key.h>
-#include <keymaster/key_blob_utils/software_keyblobs.h>
+#include <keymaster/contexts/soft_attestation_cert.h>
 #include <keymaster/key_blob_utils/integrity_assured_key_blob.h>
 #include <keymaster/key_blob_utils/ocb_utils.h>
+#include <keymaster/key_blob_utils/software_keyblobs.h>
 #include <keymaster/km_openssl/aes_key.h>
-#include <keymaster/km_openssl/hmac_key.h>
 #include <keymaster/km_openssl/attestation_utils.h>
-#include "soft_attestation_cert.h"
+#include <keymaster/km_openssl/hmac_key.h>
+#include <keymaster/km_version.h>
+#include <keymaster/legacy_support/ec_keymaster1_key.h>
+#include <keymaster/legacy_support/keymaster1_engine.h>
+#include <keymaster/legacy_support/keymaster1_legacy_support.h>
+#include <keymaster/legacy_support/keymaster_passthrough_engine.h>
+#include <keymaster/legacy_support/keymaster_passthrough_key.h>
+#include <keymaster/legacy_support/rsa_keymaster1_key.h>
 
 namespace keymaster {
 
-Keymaster1PassthroughContext::Keymaster1PassthroughContext(keymaster1_device_t* dev)
-        : device_(dev), pt_engine_(KeymasterPassthroughEngine::createInstance(dev)),
-          km1_engine_(new Keymaster1Engine(dev)) {
-
-}
+Keymaster1PassthroughContext::Keymaster1PassthroughContext(KmVersion version,
+                                                           keymaster1_device_t* dev)
+    : SoftAttestationContext(version), device_(dev),
+      pt_engine_(KeymasterPassthroughEngine::createInstance(dev)),
+      km1_engine_(new Keymaster1Engine(dev)) {}
 
 keymaster_error_t Keymaster1PassthroughContext::SetSystemVersion(uint32_t os_version,
-        uint32_t os_patchlevel) {
+                                                                 uint32_t os_patchlevel) {
     os_version_ = os_version;
     os_patchlevel_ = os_patchlevel;
     return KM_ERROR_OK;
 }
 
 void Keymaster1PassthroughContext::GetSystemVersion(uint32_t* os_version,
-        uint32_t* os_patchlevel) const {
+                                                    uint32_t* os_patchlevel) const {
     if (os_version) *os_version = os_version_;
     if (os_patchlevel) *os_patchlevel = os_patchlevel_;
 }
@@ -55,22 +56,26 @@
 KeyFactory* Keymaster1PassthroughContext::GetKeyFactory(keymaster_algorithm_t algorithm) const {
     auto& result = factories_[algorithm];
     if (!result) {
-        switch(algorithm) {
+        switch (algorithm) {
         case KM_ALGORITHM_RSA:
-            result.reset(new Keymaster1ArbitrationFactory<RsaKeymaster1KeyFactory>(pt_engine_.get(),
-                    KM_ALGORITHM_RSA, device_, this, km1_engine_.get()));
+            result.reset(new Keymaster1ArbitrationFactory<RsaKeymaster1KeyFactory>(
+                pt_engine_.get(), KM_ALGORITHM_RSA, device_, *this /* blob_maker */,
+                *this /* context */, km1_engine_.get()));
             break;
         case KM_ALGORITHM_EC:
-            result.reset(new Keymaster1ArbitrationFactory<EcdsaKeymaster1KeyFactory>(pt_engine_.get(),
-                    KM_ALGORITHM_EC, device_, this, km1_engine_.get()));
+            result.reset(new Keymaster1ArbitrationFactory<EcdsaKeymaster1KeyFactory>(
+                pt_engine_.get(), KM_ALGORITHM_EC, device_, *this /* blob_maker */,
+                *this /* context */, km1_engine_.get()));
             break;
         case KM_ALGORITHM_AES:
-            result.reset(new Keymaster1ArbitrationFactory<AesKeyFactory>(pt_engine_.get(),
-                    KM_ALGORITHM_AES, device_, this, this));
+            result.reset(new Keymaster1ArbitrationFactory<AesKeyFactory>(
+                pt_engine_.get(), KM_ALGORITHM_AES, device_, *this /* blob_maker */,
+                *this /* random_source */));
             break;
         case KM_ALGORITHM_HMAC:
-            result.reset(new Keymaster1ArbitrationFactory<HmacKeyFactory>(pt_engine_.get(),
-                    KM_ALGORITHM_HMAC, device_, this, this));
+            result.reset(new Keymaster1ArbitrationFactory<HmacKeyFactory>(
+                pt_engine_.get(), KM_ALGORITHM_HMAC, device_, *this /* blob_maker */,
+                *this /* random_source */));
             break;
         case KM_ALGORITHM_TRIPLE_DES:
             // Not supported by KM1.
@@ -79,55 +84,51 @@
     }
     return result.get();
 }
-OperationFactory* Keymaster1PassthroughContext::GetOperationFactory(keymaster_algorithm_t algorithm,
-        keymaster_purpose_t purpose) const {
+OperationFactory*
+Keymaster1PassthroughContext::GetOperationFactory(keymaster_algorithm_t algorithm,
+                                                  keymaster_purpose_t purpose) const {
     auto keyfactory = GetKeyFactory(algorithm);
     return keyfactory->GetOperationFactory(purpose);
 }
-keymaster_algorithm_t* Keymaster1PassthroughContext::GetSupportedAlgorithms(
-        size_t* algorithms_count) const {
+keymaster_algorithm_t*
+Keymaster1PassthroughContext::GetSupportedAlgorithms(size_t* algorithms_count) const {
     if (algorithms_count) *algorithms_count = 0;
     return nullptr;
 }
 
-keymaster_error_t Keymaster1PassthroughContext::UpgradeKeyBlob(
-        const KeymasterKeyBlob& key_to_upgrade, const AuthorizationSet& upgrade_params,
-        KeymasterKeyBlob* upgraded_key) const {
+keymaster_error_t
+Keymaster1PassthroughContext::UpgradeKeyBlob(const KeymasterKeyBlob& key_to_upgrade,
+                                             const AuthorizationSet& upgrade_params,
+                                             KeymasterKeyBlob* upgraded_key) const {
 
     UniquePtr<Key> key;
     keymaster_error_t error = ParseKeyBlob(key_to_upgrade, upgrade_params, &key);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     if (key->hw_enforced().Contains(TAG_PURPOSE) &&
-            !key->hw_enforced().Contains(TAG_OS_PATCHLEVEL)) {
+        !key->hw_enforced().Contains(TAG_OS_PATCHLEVEL)) {
         return KM_ERROR_INVALID_ARGUMENT;
     }
 
     return UpgradeSoftKeyBlob(key, os_version_, os_patchlevel_, upgrade_params, upgraded_key);
 }
 
-static keymaster_error_t parseKeymaster1HwBlob(const keymaster1_device_t* device,
-                                               const KeymasterKeyBlob& blob,
-                                               const AuthorizationSet& additional_params,
-                                               KeymasterKeyBlob* key_material,
-                                               AuthorizationSet* hw_enforced,
-                                               AuthorizationSet* sw_enforced) {
+static keymaster_error_t
+parseKeymaster1HwBlob(const keymaster1_device_t* device, const KeymasterKeyBlob& blob,
+                      const AuthorizationSet& additional_params, KeymasterKeyBlob* key_material,
+                      AuthorizationSet* hw_enforced, AuthorizationSet* sw_enforced) {
     keymaster_blob_t client_id = {nullptr, 0};
     keymaster_blob_t app_data = {nullptr, 0};
     keymaster_blob_t* client_id_ptr = nullptr;
     keymaster_blob_t* app_data_ptr = nullptr;
-    if (additional_params.GetTagValue(TAG_APPLICATION_ID, &client_id))
-        client_id_ptr = &client_id;
-    if (additional_params.GetTagValue(TAG_APPLICATION_DATA, &app_data))
-        app_data_ptr = &app_data;
+    if (additional_params.GetTagValue(TAG_APPLICATION_ID, &client_id)) client_id_ptr = &client_id;
+    if (additional_params.GetTagValue(TAG_APPLICATION_DATA, &app_data)) app_data_ptr = &app_data;
 
     // Get key characteristics, which incidentally verifies that the HW recognizes the key.
     keymaster_key_characteristics_t* characteristics;
     keymaster_error_t error = device->get_key_characteristics(device, &blob, client_id_ptr,
-                                                                app_data_ptr, &characteristics);
-    if (error != KM_ERROR_OK)
-        return error;
+                                                              app_data_ptr, &characteristics);
+    if (error != KM_ERROR_OK) return error;
 
     UniquePtr<keymaster_key_characteristics_t, Characteristics_Delete> characteristics_deleter(
         characteristics);
@@ -138,26 +139,27 @@
     return KM_ERROR_OK;
 }
 
-keymaster_error_t Keymaster1PassthroughContext::ParseKeyBlob(const KeymasterKeyBlob& blob,
-        const AuthorizationSet& additional_params, UniquePtr<Key>* key) const {
+keymaster_error_t
+Keymaster1PassthroughContext::ParseKeyBlob(const KeymasterKeyBlob& blob,
+                                           const AuthorizationSet& additional_params,
+                                           UniquePtr<Key>* key) const {
     AuthorizationSet hw_enforced;
     AuthorizationSet sw_enforced;
     KeymasterKeyBlob key_material;
 
     AuthorizationSet hidden;
-    keymaster_error_t error = BuildHiddenAuthorizations(additional_params, &hidden,
-                                                        softwareRootOfTrust);
-    if (error != KM_ERROR_OK)
-        return error;
+    keymaster_error_t error =
+        BuildHiddenAuthorizations(additional_params, &hidden, softwareRootOfTrust);
+    if (error != KM_ERROR_OK) return error;
 
     // Assume it's an integrity-assured blob (new software-only blob
-    error = DeserializeIntegrityAssuredBlob(blob, hidden, &key_material, &hw_enforced, &sw_enforced);
-    if (error != KM_ERROR_INVALID_KEY_BLOB && error != KM_ERROR_OK)
-        return error;
+    error =
+        DeserializeIntegrityAssuredBlob(blob, hidden, &key_material, &hw_enforced, &sw_enforced);
+    if (error != KM_ERROR_INVALID_KEY_BLOB && error != KM_ERROR_OK) return error;
 
     if (error == KM_ERROR_INVALID_KEY_BLOB) {
-        error = parseKeymaster1HwBlob(km1_engine_->device(), blob, additional_params,
-                                      &key_material, &hw_enforced, &sw_enforced);
+        error = parseKeymaster1HwBlob(km1_engine_->device(), blob, additional_params, &key_material,
+                                      &hw_enforced, &sw_enforced);
         if (error != KM_ERROR_OK) return error;
     }
 
@@ -174,26 +176,26 @@
 }
 
 keymaster_error_t Keymaster1PassthroughContext::DeleteKey(const KeymasterKeyBlob& blob) const {
-     // HACK. Due to a bug with Qualcomm's Keymaster implementation, which causes the device to
-     // reboot if we pass it a key blob it doesn't understand, we need to check for software
-     // keys.  If it looks like a software key there's nothing to do so we just return.
-     // Can be removed once b/33385206 is fixed
-     KeymasterKeyBlob key_material;
-     AuthorizationSet hw_enforced, sw_enforced;
-     keymaster_error_t error = DeserializeIntegrityAssuredBlob_NoHmacCheck(
-         blob, &key_material, &hw_enforced, &sw_enforced);
-     if (error == KM_ERROR_OK) {
-         return KM_ERROR_OK;
-     }
+    // HACK. Due to a bug with Qualcomm's Keymaster implementation, which causes the device to
+    // reboot if we pass it a key blob it doesn't understand, we need to check for software
+    // keys.  If it looks like a software key there's nothing to do so we just return.
+    // Can be removed once b/33385206 is fixed
+    KeymasterKeyBlob key_material;
+    AuthorizationSet hw_enforced, sw_enforced;
+    keymaster_error_t error = DeserializeIntegrityAssuredBlob_NoHmacCheck(
+        blob, &key_material, &hw_enforced, &sw_enforced);
+    if (error == KM_ERROR_OK) {
+        return KM_ERROR_OK;
+    }
 
-     error = km1_engine_->DeleteKey(blob);
-     if (error == KM_ERROR_INVALID_KEY_BLOB) {
-         // Some implementations diagnose invalid keys.
-         // However, all care we about is that the key blob, as supplied, is not usable after the
-         // call.
-         return KM_ERROR_OK;
-     }
-     return error;
+    error = km1_engine_->DeleteKey(blob);
+    if (error == KM_ERROR_INVALID_KEY_BLOB) {
+        // Some implementations diagnose invalid keys.
+        // However, all care we about is that the key blob, as supplied, is not usable after the
+        // call.
+        return KM_ERROR_OK;
+    }
+    return error;
 }
 
 keymaster_error_t Keymaster1PassthroughContext::DeleteAllKeys() const {
@@ -201,57 +203,49 @@
 }
 
 keymaster_error_t Keymaster1PassthroughContext::AddRngEntropy(const uint8_t* buf,
-        size_t length) const {
+                                                              size_t length) const {
     return device_->add_rng_entropy(device_, buf, length);
 }
 
-
 KeymasterEnforcement* Keymaster1PassthroughContext::enforcement_policy() {
     return nullptr;
 }
 
-keymaster_error_t Keymaster1PassthroughContext::CreateKeyBlob(const AuthorizationSet& key_description,
-                                                      const keymaster_key_origin_t origin,
-                                                      const KeymasterKeyBlob& key_material,
-                                                      KeymasterKeyBlob* blob,
-                                                      AuthorizationSet* hw_enforced,
-                                                      AuthorizationSet* sw_enforced) const {
+keymaster_error_t Keymaster1PassthroughContext::CreateKeyBlob(
+    const AuthorizationSet& key_description, const keymaster_key_origin_t origin,
+    const KeymasterKeyBlob& key_material, KeymasterKeyBlob* blob, AuthorizationSet* hw_enforced,
+    AuthorizationSet* sw_enforced) const {
     keymaster_error_t error = SetKeyBlobAuthorizations(key_description, origin, os_version_,
                                                        os_patchlevel_, hw_enforced, sw_enforced);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     AuthorizationSet hidden;
     error = BuildHiddenAuthorizations(key_description, &hidden, softwareRootOfTrust);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     return SerializeIntegrityAssuredBlob(key_material, hidden, *hw_enforced, *sw_enforced, blob);
 }
 
-keymaster_error_t Keymaster1PassthroughContext::GenerateAttestation(const Key& key,
-        const AuthorizationSet& attest_params, CertChainPtr* cert_chain) const {
-    keymaster_error_t error = KM_ERROR_OK;
+CertificateChain Keymaster1PassthroughContext::GenerateAttestation(
+    const Key& key, const AuthorizationSet& attest_params, UniquePtr<Key> /* attest_key */,
+    const KeymasterBlob& /* issuer_subject */, keymaster_error_t* error) const {
     keymaster_algorithm_t key_algorithm;
     if (!key.authorizations().GetTagValue(TAG_ALGORITHM, &key_algorithm)) {
-        return KM_ERROR_UNKNOWN_ERROR;
+        *error = KM_ERROR_UNKNOWN_ERROR;
+        return {};
     }
 
-    if ((key_algorithm != KM_ALGORITHM_RSA && key_algorithm != KM_ALGORITHM_EC))
-        return KM_ERROR_INCOMPATIBLE_ALGORITHM;
+    if ((key_algorithm != KM_ALGORITHM_RSA && key_algorithm != KM_ALGORITHM_EC)) {
+        *error = KM_ERROR_INCOMPATIBLE_ALGORITHM;
+        return {};
+    }
 
     // We have established that the given key has the correct algorithm, and because this is the
     // SoftKeymasterContext we can assume that the Key is an AsymmetricKey. So we can downcast.
     const AsymmetricKey& asymmetric_key = static_cast<const AsymmetricKey&>(key);
 
-    auto attestation_chain = getAttestationChain(key_algorithm, &error);
-    if (error != KM_ERROR_OK) return error;
-
-    auto attestation_key = getAttestationKey(key_algorithm, &error);
-    if (error != KM_ERROR_OK) return error;
-
-    return generate_attestation(asymmetric_key, attest_params,
-            *attestation_chain, *attestation_key, *this, cert_chain);
+    return generate_attestation(asymmetric_key, attest_params, {} /* attest_key */,
+                                *this /* AttestationContext */, error);
 }
 
 keymaster_error_t Keymaster1PassthroughContext::UnwrapKey(
@@ -260,4 +254,4 @@
     return KM_ERROR_UNIMPLEMENTED;
 }
 
-} // namespace keymaster
+}  // namespace keymaster
diff --git a/contexts/keymaster2_passthrough_context.cpp b/contexts/keymaster2_passthrough_context.cpp
index 678eaaa..fe83de8 100644
--- a/contexts/keymaster2_passthrough_context.cpp
+++ b/contexts/keymaster2_passthrough_context.cpp
@@ -17,25 +17,24 @@
 
 #include <keymaster/contexts/keymaster2_passthrough_context.h>
 
-#include <keymaster/legacy_support/keymaster_passthrough_key.h>
 #include <keymaster/legacy_support/keymaster_passthrough_engine.h>
+#include <keymaster/legacy_support/keymaster_passthrough_key.h>
 
 namespace keymaster {
 
-Keymaster2PassthroughContext::Keymaster2PassthroughContext(keymaster2_device_t* dev)
-        : device_(dev), engine_(KeymasterPassthroughEngine::createInstance(dev)) {
-
-}
+Keymaster2PassthroughContext::Keymaster2PassthroughContext(KmVersion version,
+                                                           keymaster2_device_t* dev)
+    : device_(dev), engine_(KeymasterPassthroughEngine::createInstance(dev)), version_(version) {}
 
 keymaster_error_t Keymaster2PassthroughContext::SetSystemVersion(uint32_t os_version,
-        uint32_t os_patchlevel) {
+                                                                 uint32_t os_patchlevel) {
     os_version_ = os_version;
     os_patchlevel_ = os_patchlevel;
     return KM_ERROR_OK;
 }
 
 void Keymaster2PassthroughContext::GetSystemVersion(uint32_t* os_version,
-        uint32_t* os_patchlevel) const {
+                                                    uint32_t* os_patchlevel) const {
     if (os_version) *os_version = os_version_;
     if (os_patchlevel) *os_patchlevel = os_patchlevel_;
 }
@@ -47,27 +46,31 @@
     }
     return result.get();
 }
-OperationFactory* Keymaster2PassthroughContext::GetOperationFactory(keymaster_algorithm_t algorithm,
-        keymaster_purpose_t purpose) const {
+OperationFactory*
+Keymaster2PassthroughContext::GetOperationFactory(keymaster_algorithm_t algorithm,
+                                                  keymaster_purpose_t purpose) const {
     auto keyfactory = GetKeyFactory(algorithm);
     return keyfactory->GetOperationFactory(purpose);
 }
-keymaster_algorithm_t* Keymaster2PassthroughContext::GetSupportedAlgorithms(
-        size_t* algorithms_count) const {
+keymaster_algorithm_t*
+Keymaster2PassthroughContext::GetSupportedAlgorithms(size_t* algorithms_count) const {
     if (algorithms_count) *algorithms_count = 0;
     return nullptr;
 }
 
-keymaster_error_t Keymaster2PassthroughContext::UpgradeKeyBlob(
-        const KeymasterKeyBlob& key_to_upgrade, const AuthorizationSet& upgrade_params,
-        KeymasterKeyBlob* upgraded_key) const {
+keymaster_error_t
+Keymaster2PassthroughContext::UpgradeKeyBlob(const KeymasterKeyBlob& key_to_upgrade,
+                                             const AuthorizationSet& upgrade_params,
+                                             KeymasterKeyBlob* upgraded_key) const {
     if (!upgraded_key) return KM_ERROR_UNEXPECTED_NULL_POINTER;
     *upgraded_key = {};
     return device_->upgrade_key(device_, &key_to_upgrade, &upgrade_params, upgraded_key);
 }
 
-keymaster_error_t Keymaster2PassthroughContext::ParseKeyBlob(const KeymasterKeyBlob& blob,
-        const AuthorizationSet& additional_params, UniquePtr<Key>* key) const {
+keymaster_error_t
+Keymaster2PassthroughContext::ParseKeyBlob(const KeymasterKeyBlob& blob,
+                                           const AuthorizationSet& additional_params,
+                                           UniquePtr<Key>* key) const {
     keymaster_key_characteristics_t characteristics = {};
     keymaster_blob_t clientId;
     keymaster_blob_t applicationData;
@@ -115,34 +118,27 @@
 }
 
 keymaster_error_t Keymaster2PassthroughContext::AddRngEntropy(const uint8_t* buf,
-        size_t length) const {
+                                                              size_t length) const {
     return device_->add_rng_entropy(device_, buf, length);
 }
 
-
 KeymasterEnforcement* Keymaster2PassthroughContext::enforcement_policy() {
     return nullptr;
 }
 
-keymaster_error_t Keymaster2PassthroughContext::GenerateAttestation(const Key& key,
-        const AuthorizationSet& attest_params, CertChainPtr* cert_chain) const {
-    if (!cert_chain) return KM_ERROR_UNEXPECTED_NULL_POINTER;
-
+CertificateChain Keymaster2PassthroughContext::GenerateAttestation(
+    const Key& key, const AuthorizationSet& attest_params, UniquePtr<Key> /* attest_key */,
+    const KeymasterBlob& /* issuer_subject */, keymaster_error_t* error) const {
     keymaster_cert_chain_t cchain{};
-
     auto rc = device_->attest_key(device_, &key.key_material(), &attest_params, &cchain);
-    if (rc == KM_ERROR_OK) {
-        cert_chain->reset(new keymaster_cert_chain_t);
-        **cert_chain = { new keymaster_blob_t[cchain.entry_count], cchain.entry_count };
-        for (size_t i = 0; i < cchain.entry_count; ++i) {
-            (*cert_chain)->entries[i] = { dup_array(cchain.entries[i].data,
-                                              cchain.entries[i].data_length),
-                                          cchain.entries[i].data_length };
-            free(const_cast<uint8_t*>(cchain.entries[i].data));
-        }
-        free(cchain.entries);
+    if (rc != KM_ERROR_OK) {
+        *error = rc;
+        return {};
     }
-    return rc;
+
+    CertificateChain retval = CertificateChain::clone(cchain);
+    keymaster_free_cert_chain(&cchain);
+    return retval;
 }
 
 keymaster_error_t Keymaster2PassthroughContext::UnwrapKey(
@@ -151,4 +147,4 @@
     return KM_ERROR_UNIMPLEMENTED;
 }
 
-} // namespace keymaster
+}  // namespace keymaster
diff --git a/contexts/pure_soft_keymaster_context.cpp b/contexts/pure_soft_keymaster_context.cpp
index d52fe2e..bfa92a4 100644
--- a/contexts/pure_soft_keymaster_context.cpp
+++ b/contexts/pure_soft_keymaster_context.cpp
@@ -16,6 +16,7 @@
 
 #include <keymaster/contexts/pure_soft_keymaster_context.h>
 
+#include <assert.h>
 #include <memory>
 
 #include <openssl/aes.h>
@@ -33,6 +34,7 @@
 #include <keymaster/km_openssl/aes_key.h>
 #include <keymaster/km_openssl/asymmetric_key.h>
 #include <keymaster/km_openssl/attestation_utils.h>
+#include <keymaster/km_openssl/certificate_utils.h>
 #include <keymaster/km_openssl/ec_key_factory.h>
 #include <keymaster/km_openssl/hmac_key.h>
 #include <keymaster/km_openssl/openssl_err.h>
@@ -44,29 +46,43 @@
 #include <keymaster/operation.h>
 #include <keymaster/wrapped_key.h>
 
-#include "soft_attestation_cert.h"
-
-using std::unique_ptr;
+#include <keymaster/contexts/soft_attestation_cert.h>
 
 namespace keymaster {
 
-PureSoftKeymasterContext::PureSoftKeymasterContext(keymaster_security_level_t security_level)
-    : rsa_factory_(new RsaKeyFactory(this)), ec_factory_(new EcKeyFactory(this)),
-      aes_factory_(new AesKeyFactory(this, this)),
-      tdes_factory_(new TripleDesKeyFactory(this, this)),
-      hmac_factory_(new HmacKeyFactory(this, this)), os_version_(0), os_patchlevel_(0),
-      soft_keymaster_enforcement_(64, 64), security_level_(security_level) {}
+PureSoftKeymasterContext::PureSoftKeymasterContext(KmVersion version,
+                                                   keymaster_security_level_t security_level)
+
+    : SoftAttestationContext(version),
+      rsa_factory_(new RsaKeyFactory(*this /* blob_maker */, *this /* context */)),
+      ec_factory_(new EcKeyFactory(*this /* blob_maker */, *this /* context */)),
+      aes_factory_(new AesKeyFactory(*this /* blob_maker */, *this /* random_source */)),
+      tdes_factory_(new TripleDesKeyFactory(*this /* blob_maker */, *this /* random_source */)),
+      hmac_factory_(new HmacKeyFactory(*this /* blob_maker */, *this /* random_source */)),
+      os_version_(0), os_patchlevel_(0), soft_keymaster_enforcement_(64, 64),
+      security_level_(security_level) {
+    // We're pretending to be some sort of secure hardware which supports secure key storage,
+    // this must only be used for testing.
+    if (security_level != KM_SECURITY_LEVEL_SOFTWARE) {
+        pure_soft_secure_key_storage_ = std::make_unique<PureSoftSecureKeyStorage>(64);
+    }
+    if (version >= KmVersion::KEYMINT_1) {
+        pure_soft_remote_provisioning_context_ =
+            std::make_unique<PureSoftRemoteProvisioningContext>();
+    }
+}
 
 PureSoftKeymasterContext::~PureSoftKeymasterContext() {}
 
 keymaster_error_t PureSoftKeymasterContext::SetSystemVersion(uint32_t os_version,
-                                                         uint32_t os_patchlevel) {
+                                                             uint32_t os_patchlevel) {
     os_version_ = os_version;
     os_patchlevel_ = os_patchlevel;
     return KM_ERROR_OK;
 }
 
-void PureSoftKeymasterContext::GetSystemVersion(uint32_t* os_version, uint32_t* os_patchlevel) const {
+void PureSoftKeymasterContext::GetSystemVersion(uint32_t* os_version,
+                                                uint32_t* os_patchlevel) const {
     *os_version = os_version_;
     *os_patchlevel = os_patchlevel_;
 }
@@ -98,10 +114,9 @@
 }
 
 OperationFactory* PureSoftKeymasterContext::GetOperationFactory(keymaster_algorithm_t algorithm,
-                                                            keymaster_purpose_t purpose) const {
+                                                                keymaster_purpose_t purpose) const {
     KeyFactory* key_factory = GetKeyFactory(algorithm);
-    if (!key_factory)
-        return nullptr;
+    if (!key_factory) return nullptr;
     return key_factory->GetOperationFactory(purpose);
 }
 
@@ -111,8 +126,17 @@
                                                           KeymasterKeyBlob* blob,
                                                           AuthorizationSet* hw_enforced,
                                                           AuthorizationSet* sw_enforced) const {
+    // Check whether the key blob can be securely stored by pure software secure key storage.
+    bool canStoreBySecureKeyStorageIfRequired = false;
+    if (GetSecurityLevel() != KM_SECURITY_LEVEL_SOFTWARE &&
+        pure_soft_secure_key_storage_ != nullptr) {
+        pure_soft_secure_key_storage_->HasSlot(&canStoreBySecureKeyStorageIfRequired);
+    }
+
+    bool needStoreBySecureKeyStorage = false;
     if (key_description.GetTagValue(TAG_ROLLBACK_RESISTANCE)) {
-        return KM_ERROR_ROLLBACK_RESISTANCE_UNAVAILABLE;
+        needStoreBySecureKeyStorage = true;
+        if (!canStoreBySecureKeyStorageIfRequired) return KM_ERROR_ROLLBACK_RESISTANCE_UNAVAILABLE;
     }
 
     if (GetSecurityLevel() != KM_SECURITY_LEVEL_SOFTWARE) {
@@ -141,8 +165,19 @@
             case KM_TAG_ORIGIN:
             case KM_TAG_OS_VERSION:
             case KM_TAG_OS_PATCHLEVEL:
+            case KM_TAG_EARLY_BOOT_ONLY:
+            case KM_TAG_UNLOCKED_DEVICE_REQUIRED:
+            case KM_TAG_RSA_OAEP_MGF_DIGEST:
+            case KM_TAG_ROLLBACK_RESISTANCE:
                 hw_enforced->push_back(entry);
                 break;
+            case KM_TAG_USAGE_COUNT_LIMIT:
+                // Enforce single use key with usage count limit = 1 into secure key storage.
+                if (canStoreBySecureKeyStorageIfRequired && entry.integer == 1) {
+                    needStoreBySecureKeyStorage = true;
+                    hw_enforced->push_back(entry);
+                }
+                break;
             default:
                 break;
             }
@@ -152,23 +187,34 @@
     keymaster_error_t error = SetKeyBlobAuthorizations(key_description, origin, os_version_,
                                                        os_patchlevel_, hw_enforced, sw_enforced);
     if (error != KM_ERROR_OK) return error;
+    error =
+        ExtendKeyBlobAuthorizations(hw_enforced, sw_enforced, vendor_patchlevel_, boot_patchlevel_);
+    if (error != KM_ERROR_OK) return error;
 
     AuthorizationSet hidden;
     error = BuildHiddenAuthorizations(key_description, &hidden, softwareRootOfTrust);
     if (error != KM_ERROR_OK) return error;
 
-    return SerializeIntegrityAssuredBlob(key_material, hidden, *hw_enforced, *sw_enforced, blob);
+    error = SerializeIntegrityAssuredBlob(key_material, hidden, *hw_enforced, *sw_enforced, blob);
+    if (error != KM_ERROR_OK) return error;
+
+    // Pretend to be some sort of secure hardware that can securely store the key blob.
+    if (!needStoreBySecureKeyStorage) return KM_ERROR_OK;
+    km_id_t keyid;
+    if (!soft_keymaster_enforcement_.CreateKeyId(*blob, &keyid)) return KM_ERROR_UNKNOWN_ERROR;
+    assert(needStoreBySecureKeyStorage && canStoreBySecureKeyStorageIfRequired);
+    return pure_soft_secure_key_storage_->WriteKey(keyid, *blob);
 }
 
 keymaster_error_t PureSoftKeymasterContext::UpgradeKeyBlob(const KeymasterKeyBlob& key_to_upgrade,
-                                                       const AuthorizationSet& upgrade_params,
-                                                       KeymasterKeyBlob* upgraded_key) const {
+                                                           const AuthorizationSet& upgrade_params,
+                                                           KeymasterKeyBlob* upgraded_key) const {
     UniquePtr<Key> key;
     keymaster_error_t error = ParseKeyBlob(key_to_upgrade, upgrade_params, &key);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
-    return UpgradeSoftKeyBlob(key, os_version_, os_patchlevel_, upgrade_params, upgraded_key);
+    return FullUpgradeSoftKeyBlob(key, os_version_, os_patchlevel_, vendor_patchlevel_,
+                                  boot_patchlevel_, upgrade_params, upgraded_key);
 }
 
 keymaster_error_t PureSoftKeymasterContext::ParseKeyBlob(const KeymasterKeyBlob& blob,
@@ -201,7 +247,7 @@
     KeymasterKeyBlob key_material;
     keymaster_error_t error;
 
-    auto constructKey = [&, this] () mutable -> keymaster_error_t {
+    auto constructKey = [&, this]() mutable -> keymaster_error_t {
         // GetKeyFactory
         if (error != KM_ERROR_OK) return error;
         keymaster_algorithm_t algorithm;
@@ -209,6 +255,20 @@
             !sw_enforced.GetTagValue(TAG_ALGORITHM, &algorithm)) {
             return KM_ERROR_INVALID_ARGUMENT;
         }
+
+        // Pretend to be some sort of secure hardware that can securely store
+        // the key blob. Check the key blob is still securely stored now.
+        if (hw_enforced.Contains(KM_TAG_ROLLBACK_RESISTANCE) ||
+            hw_enforced.Contains(KM_TAG_USAGE_COUNT_LIMIT)) {
+            if (pure_soft_secure_key_storage_ == nullptr) return KM_ERROR_INVALID_KEY_BLOB;
+            km_id_t keyid;
+            bool exists;
+            if (!soft_keymaster_enforcement_.CreateKeyId(blob, &keyid))
+                return KM_ERROR_INVALID_KEY_BLOB;
+            error = pure_soft_secure_key_storage_->KeyExists(keyid, &exists);
+            if (error != KM_ERROR_OK || !exists) return KM_ERROR_INVALID_KEY_BLOB;
+        }
+
         auto factory = GetKeyFactory(algorithm);
         return factory->LoadKey(move(key_material), additional_params, move(hw_enforced),
                                 move(sw_enforced), key);
@@ -216,71 +276,114 @@
 
     AuthorizationSet hidden;
     error = BuildHiddenAuthorizations(additional_params, &hidden, softwareRootOfTrust);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     // Assume it's an integrity-assured blob (new software-only blob, or new keymaster0-backed
     // blob).
-    error = DeserializeIntegrityAssuredBlob(blob, hidden, &key_material, &hw_enforced, &sw_enforced);
-    if (error != KM_ERROR_INVALID_KEY_BLOB)
-        return constructKey();
+    error =
+        DeserializeIntegrityAssuredBlob(blob, hidden, &key_material, &hw_enforced, &sw_enforced);
+    if (error != KM_ERROR_INVALID_KEY_BLOB) return constructKey();
 
-    // Wasn't an integrity-assured blob.  Maybe it's an OCB-encrypted blob.
-    error = ParseOcbAuthEncryptedBlob(blob, hidden, &key_material, &hw_enforced, &sw_enforced);
-    if (error == KM_ERROR_OK)
-        LOG_D("Parsed an old keymaster1 software key", 0);
-    if (error != KM_ERROR_INVALID_KEY_BLOB)
-        return constructKey();
+    // Wasn't an integrity-assured blob.  Maybe it's an auth-encrypted blob.
+    error = ParseAuthEncryptedBlob(blob, hidden, &key_material, &hw_enforced, &sw_enforced);
+    if (error == KM_ERROR_OK) LOG_D("Parsed an old keymaster1 software key", 0);
+    if (error != KM_ERROR_INVALID_KEY_BLOB) return constructKey();
 
-    // Wasn't an OCB-encrypted blob.  Maybe it's an old softkeymaster blob.
+    // Wasn't an auth-encrypted blob.  Maybe it's an old softkeymaster blob.
     error = ParseOldSoftkeymasterBlob(blob, &key_material, &hw_enforced, &sw_enforced);
-    if (error == KM_ERROR_OK)
-        LOG_D("Parsed an old sofkeymaster key", 0);
+    if (error == KM_ERROR_OK) LOG_D("Parsed an old sofkeymaster key", 0);
 
     return constructKey();
 }
 
-keymaster_error_t PureSoftKeymasterContext::DeleteKey(const KeymasterKeyBlob& /* blob */) const {
-    // Nothing to do for software-only contexts.
+keymaster_error_t PureSoftKeymasterContext::DeleteKey(const KeymasterKeyBlob& blob) const {
+    // Pretend to be some secure hardware with secure storage.
+    if (GetSecurityLevel() != KM_SECURITY_LEVEL_SOFTWARE &&
+        pure_soft_secure_key_storage_ != nullptr) {
+        km_id_t keyid;
+        if (!soft_keymaster_enforcement_.CreateKeyId(blob, &keyid)) return KM_ERROR_UNKNOWN_ERROR;
+        return pure_soft_secure_key_storage_->DeleteKey(keyid);
+    }
+
+    // Otherwise, nothing to do for software-only contexts.
     return KM_ERROR_OK;
 }
 
 keymaster_error_t PureSoftKeymasterContext::DeleteAllKeys() const {
+    // Pretend to be some secure hardware with secure storage.
+    if (GetSecurityLevel() != KM_SECURITY_LEVEL_SOFTWARE &&
+        pure_soft_secure_key_storage_ != nullptr) {
+        return pure_soft_secure_key_storage_->DeleteAllKeys();
+    }
+
+    // Otherwise, nothing to do for software-only contexts.
     return KM_ERROR_OK;
 }
 
 keymaster_error_t PureSoftKeymasterContext::AddRngEntropy(const uint8_t* buf, size_t length) const {
+    if (length > 2 * 1024) {
+        // At most 2KiB is allowed to be added at once.
+        return KM_ERROR_INVALID_INPUT_LENGTH;
+    }
     // XXX TODO according to boringssl openssl/rand.h RAND_add is deprecated and does
     // nothing
     RAND_add(buf, length, 0 /* Don't assume any entropy is added to the pool. */);
     return KM_ERROR_OK;
 }
 
-keymaster_error_t PureSoftKeymasterContext::GenerateAttestation(const Key& key,
-                                      const AuthorizationSet& attest_params,
-                                      CertChainPtr* cert_chain) const {
+CertificateChain
+PureSoftKeymasterContext::GenerateAttestation(const Key& key,                         //
+                                              const AuthorizationSet& attest_params,  //
+                                              UniquePtr<Key> attest_key,
+                                              const KeymasterBlob& issuer_subject,
+                                              keymaster_error_t* error) const {
+    if (!error) return {};
+    *error = KM_ERROR_OK;
 
-    keymaster_error_t error = KM_ERROR_OK;
     keymaster_algorithm_t key_algorithm;
     if (!key.authorizations().GetTagValue(TAG_ALGORITHM, &key_algorithm)) {
-        return KM_ERROR_UNKNOWN_ERROR;
+        *error = KM_ERROR_UNKNOWN_ERROR;
+        return {};
     }
 
-    if ((key_algorithm != KM_ALGORITHM_RSA && key_algorithm != KM_ALGORITHM_EC))
-        return KM_ERROR_INCOMPATIBLE_ALGORITHM;
+    if ((key_algorithm != KM_ALGORITHM_RSA && key_algorithm != KM_ALGORITHM_EC)) {
+        *error = KM_ERROR_INCOMPATIBLE_ALGORITHM;
+        return {};
+    }
+
+    if (attest_params.GetTagValue(TAG_DEVICE_UNIQUE_ATTESTATION)) {
+        *error = KM_ERROR_UNIMPLEMENTED;
+        return {};
+    }
+    // We have established that the given key has the correct algorithm, and because this is the
+    // SoftKeymasterContext we can assume that the Key is an AsymmetricKey. So we can downcast.
+    const AsymmetricKey& asymmetric_key = static_cast<const AsymmetricKey&>(key);
+
+    AttestKeyInfo attest_key_info(attest_key, &issuer_subject, error);
+    if (*error != KM_ERROR_OK) return {};
+
+    return generate_attestation(asymmetric_key, attest_params, move(attest_key_info), *this, error);
+}
+
+CertificateChain PureSoftKeymasterContext::GenerateSelfSignedCertificate(
+    const Key& key, const AuthorizationSet& cert_params, bool fake_signature,
+    keymaster_error_t* error) const {
+    keymaster_algorithm_t key_algorithm;
+    if (!key.authorizations().GetTagValue(TAG_ALGORITHM, &key_algorithm)) {
+        *error = KM_ERROR_UNKNOWN_ERROR;
+        return {};
+    }
+
+    if ((key_algorithm != KM_ALGORITHM_RSA && key_algorithm != KM_ALGORITHM_EC)) {
+        *error = KM_ERROR_INCOMPATIBLE_ALGORITHM;
+        return {};
+    }
 
     // We have established that the given key has the correct algorithm, and because this is the
     // SoftKeymasterContext we can assume that the Key is an AsymmetricKey. So we can downcast.
     const AsymmetricKey& asymmetric_key = static_cast<const AsymmetricKey&>(key);
 
-    auto attestation_chain = getAttestationChain(key_algorithm, &error);
-    if (error != KM_ERROR_OK) return error;
-
-    auto attestation_key = getAttestationKey(key_algorithm, &error);
-    if (error != KM_ERROR_OK) return error;
-
-    return generate_attestation(asymmetric_key, attest_params,
-            *attestation_chain, *attestation_key, *this, cert_chain);
+    return generate_self_signed_cert(asymmetric_key, cert_params, fake_signature, error);
 }
 
 static keymaster_error_t TranslateAuthorizationSetError(AuthorizationSet::Error err) {
@@ -421,7 +524,7 @@
                                             wrapped_key_description.data_length)
                              .build();
     if (update_params.is_valid() != AuthorizationSet::Error::OK) {
-        return TranslateAuthorizationSetError(transit_key_authorizations.is_valid());
+        return TranslateAuthorizationSetError(update_params.is_valid());
     }
 
     error = aes_operation->Update(update_params, encrypted_key, &update_outparams, &plaintext,
@@ -442,16 +545,17 @@
     return error;
 }
 
-keymaster_error_t PureSoftKeymasterContext::GetVerifiedBootParams(
-    keymaster_blob_t* verified_boot_key, keymaster_blob_t* verified_boot_hash,
-    keymaster_verified_boot_t* verified_boot_state, bool* device_locked) const {
-    // TODO(swillden): See if there might be some sort of vbmeta data in goldfish/cuttlefish.
-    static std::string fake_vb_key = "12345678901234567890123456789012";
-    *verified_boot_key = {reinterpret_cast<uint8_t*>(fake_vb_key.data()), fake_vb_key.size()};
-    *verified_boot_hash = {reinterpret_cast<uint8_t*>(fake_vb_key.data()), fake_vb_key.size()};
-    *verified_boot_state = KM_VERIFIED_BOOT_UNVERIFIED;
-    *device_locked = false;
-    return KM_ERROR_OK;
+const AttestationContext::VerifiedBootParams*
+PureSoftKeymasterContext::GetVerifiedBootParams(keymaster_error_t* error) const {
+    static VerifiedBootParams params;
+    static std::string fake_vb_key(32, 0);
+    params.verified_boot_key = {reinterpret_cast<uint8_t*>(fake_vb_key.data()), fake_vb_key.size()};
+    params.verified_boot_hash = {reinterpret_cast<uint8_t*>(fake_vb_key.data()),
+                                 fake_vb_key.size()};
+    params.verified_boot_state = KM_VERIFIED_BOOT_UNVERIFIED;
+    params.device_locked = false;
+    *error = KM_ERROR_OK;
+    return &params;
 }
 
 }  // namespace keymaster
diff --git a/contexts/pure_soft_remote_provisioning_context.cpp b/contexts/pure_soft_remote_provisioning_context.cpp
new file mode 100644
index 0000000..a943f42
--- /dev/null
+++ b/contexts/pure_soft_remote_provisioning_context.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <keymaster/contexts/pure_soft_remote_provisioning_context.h>
+
+#include <algorithm>
+#include <assert.h>
+
+#include <keymaster/cppcose/cppcose.h>
+#include <keymaster/logger.h>
+
+#include <openssl/bn.h>
+#include <openssl/ec.h>
+#include <openssl/hkdf.h>
+#include <openssl/rand.h>
+
+namespace keymaster {
+
+using cppcose::constructCoseSign1;
+using cppcose::CoseKey;
+using cppcose::ED25519;
+using cppcose::EDDSA;
+using cppcose::OCTET_KEY_PAIR;
+using cppcose::VERIFY;
+
+constexpr uint32_t kMacKeyLength = 32;
+
+PureSoftRemoteProvisioningContext::PureSoftRemoteProvisioningContext() {
+    std::tie(devicePrivKey_, bcc_) = GenerateBcc(/*testMode=*/false);
+}
+
+PureSoftRemoteProvisioningContext::~PureSoftRemoteProvisioningContext() {}
+
+std::vector<uint8_t>
+PureSoftRemoteProvisioningContext::DeriveBytesFromHbk(const std::string& context,
+                                                      size_t num_bytes) const {
+    // bytevec fakeHbk(32, 0);
+    // bytevec result(numBytes);
+    // is it safe to revert the call below back to the call above?
+    std::vector<uint8_t> fakeHbk(32);
+    std::vector<uint8_t> result(num_bytes);
+
+    // TODO: Figure out if HKDF can fail.  It doesn't seem like it should be able to,
+    // but the function does return an error code.
+    HKDF(result.data(), num_bytes,              //
+         EVP_sha256(),                          //
+         fakeHbk.data(), fakeHbk.size(),        //
+         nullptr /* salt */, 0 /* salt len */,  //
+         reinterpret_cast<const uint8_t*>(context.data()), context.size());
+
+    return result;
+}
+
+std::unique_ptr<cppbor::Map> PureSoftRemoteProvisioningContext::CreateDeviceInfo() const {
+    auto result = std::make_unique<cppbor::Map>(cppbor::Map());
+
+    // The following placeholders show how the DeviceInfo map would be populated.
+    // result->add(cppbor::Tstr("brand"), cppbor::Tstr("Google"));
+    // result->add(cppbor::Tstr("manufacturer"), cppbor::Tstr("Google"));
+    // result->add(cppbor::Tstr("product"), cppbor::Tstr("Fake"));
+    // result->add(cppbor::Tstr("model"), cppbor::Tstr("Imaginary"));
+    // result->add(cppbor::Tstr("board"), cppbor::Tstr("Chess"));
+    // result->add(cppbor::Tstr("vb_state"), cppbor::Tstr("orange"));
+    // result->add(cppbor::Tstr("bootloader_state"), cppbor::Tstr("unlocked"));
+    // result->add(cppbor::Tstr("os_version"), cppbor::Tstr("SC"));
+    // result->add(cppbor::Tstr("system_patch_level"), cppbor::Uint(20210331));
+    // result->add(cppbor::Tstr("boot_patch_level"), cppbor::Uint(20210331));
+    // result->add(cppbor::Tstr("vendor_patch_level"), cppbor::Uint(20210331));
+
+    result->canonicalize();
+    return result;
+}
+
+std::pair<std::vector<uint8_t> /* privKey */, cppbor::Array /* BCC */>
+PureSoftRemoteProvisioningContext::GenerateBcc(bool testMode) const {
+    std::vector<uint8_t> privKey(ED25519_PRIVATE_KEY_LEN);
+    std::vector<uint8_t> pubKey(ED25519_PUBLIC_KEY_LEN);
+
+    uint8_t seed[32];  // Length is hard-coded in the BoringCrypto API
+    if (testMode) {
+        RAND_bytes(seed, sizeof(seed));
+    } else {
+        auto seed_vector = DeriveBytesFromHbk("Device Key Seed", sizeof(seed));
+        std::copy(seed_vector.begin(), seed_vector.end(), seed);
+    }
+    ED25519_keypair_from_seed(pubKey.data(), privKey.data(), seed);
+
+    auto coseKey = cppbor::Map()
+                       .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
+                       .add(CoseKey::ALGORITHM, EDDSA)
+                       .add(CoseKey::CURVE, ED25519)
+                       .add(CoseKey::KEY_OPS, VERIFY)
+                       .add(CoseKey::PUBKEY_X, pubKey)
+                       .canonicalize();
+    auto sign1Payload = cppbor::Map()
+                            .add(1 /* Issuer */, "Issuer")
+                            .add(2 /* Subject */, "Subject")
+                            .add(-4670552 /* Subject Pub Key */, coseKey.encode())
+                            .add(-4670553 /* Key Usage (little-endian order) */,
+                                 std::vector<uint8_t>{0x20} /* keyCertSign = 1<<5 */)
+                            .canonicalize()
+                            .encode();
+    auto coseSign1 = constructCoseSign1(privKey,       /* signing key */
+                                        cppbor::Map(), /* extra protected */
+                                        sign1Payload, {} /* AAD */);
+    assert(coseSign1);
+
+    return {privKey, cppbor::Array().add(std::move(coseKey)).add(coseSign1.moveValue())};
+}
+
+std::optional<cppcose::HmacSha256>
+PureSoftRemoteProvisioningContext::GenerateHmacSha256(const cppcose::bytevec& input) const {
+    auto key = DeriveBytesFromHbk("Key to MAC public keys", kMacKeyLength);
+    auto result = cppcose::generateHmacSha256(key, input);
+    if (!result) {
+        LOG_E("Error signing MAC: %s", result.message().c_str());
+        return std::nullopt;
+    }
+    return *result;
+}
+
+}  // namespace keymaster
diff --git a/contexts/soft_attestation_cert.cpp b/contexts/soft_attestation_cert.cpp
index cc9d104..87110a6 100644
--- a/contexts/soft_attestation_cert.cpp
+++ b/contexts/soft_attestation_cert.cpp
@@ -15,12 +15,11 @@
 ** limitations under the License.
 */
 
-#include "soft_attestation_cert.h"
+#include <keymaster/contexts/soft_attestation_cert.h>
 
-#include <stdint.h>
 #include <hardware/keymaster_defs.h>
 #include <keymaster/android_keymaster_utils.h>
-#include <openssl/aes.h>
+#include <stdint.h>
 
 namespace keymaster {
 
@@ -68,9 +67,8 @@
     0x25,
 };
 
-static const keymaster_key_blob_t kRsaAttestKeyBlob = {
-        (const uint8_t*)&kRsaAttestKey, sizeof(kRsaAttestKey)
-};
+static const keymaster_key_blob_t kRsaAttestKeyBlob = {(const uint8_t*)&kRsaAttestKey,
+                                                       sizeof(kRsaAttestKey)};
 
 static const uint8_t kRsaAttestCert[] = {
     0x30, 0x82, 0x02, 0xb6, 0x30, 0x82, 0x02, 0x1f, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x10,
@@ -166,12 +164,10 @@
 };
 
 static keymaster_blob_t kRsaAttestChainBlobs[] = {
-        {(const uint8_t*)&kRsaAttestCert, sizeof(kRsaAttestCert)},
-        {(const uint8_t*)&kRsaAttestRootCert, sizeof(kRsaAttestRootCert)}
-};
+    {(const uint8_t*)&kRsaAttestCert, sizeof(kRsaAttestCert)},
+    {(const uint8_t*)&kRsaAttestRootCert, sizeof(kRsaAttestRootCert)}};
 
-static const keymaster_cert_chain_t kRsaAttestChain = { (keymaster_blob_t*)&kRsaAttestChainBlobs, 2 };
-
+static const keymaster_cert_chain_t kRsaAttestChain = {(keymaster_blob_t*)&kRsaAttestChainBlobs, 2};
 
 static const uint8_t kEcAttestKey[] = {
     0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x21, 0xe0, 0x86, 0x43, 0x2a, 0x15, 0x19, 0x84, 0x59,
@@ -184,9 +180,8 @@
     0x71, 0x58, 0x3e, 0xdb, 0x3e, 0x11, 0xae, 0x10, 0x14,
 };
 
-static const keymaster_key_blob_t kEcAttestKeyBlob = {
-        (const uint8_t*)&kEcAttestKey, sizeof(kEcAttestKey)
-};
+static const keymaster_key_blob_t kEcAttestKeyBlob = {(const uint8_t*)&kEcAttestKey,
+                                                      sizeof(kEcAttestKey)};
 
 static const uint8_t kEcAttestCert[] = {
     0x30, 0x82, 0x02, 0x78, 0x30, 0x82, 0x02, 0x1e, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x10,
@@ -276,15 +271,15 @@
 };
 
 static keymaster_blob_t kEcAttestChainBlobs[] = {
-        {(const uint8_t*)&kEcAttestCert, sizeof(kEcAttestCert)},
-        {(const uint8_t*)&kEcAttestRootCert, sizeof(kEcAttestRootCert)}
-};
+    {(const uint8_t*)&kEcAttestCert, sizeof(kEcAttestCert)},
+    {(const uint8_t*)&kEcAttestRootCert, sizeof(kEcAttestRootCert)}};
 
-static const keymaster_cert_chain_t kEcAttestChain = { (keymaster_blob_t*)&kEcAttestChainBlobs, 2 };
+static const keymaster_cert_chain_t kEcAttestChain = {(keymaster_blob_t*)&kEcAttestChainBlobs, 2};
 
-}
+}  // namespace
 
-const keymaster_key_blob_t* getAttestationKey(keymaster_algorithm_t algorithm, keymaster_error_t* error) {
+const keymaster_key_blob_t* getAttestationKey(keymaster_algorithm_t algorithm,
+                                              keymaster_error_t* error) {
 
     if (error) *error = KM_ERROR_OK;
 
@@ -301,24 +296,26 @@
     }
 }
 
-
-const keymaster_cert_chain_t* getAttestationChain(
-        keymaster_algorithm_t algorithm, keymaster_error_t* error) {
-
+CertificateChain getAttestationChain(keymaster_algorithm_t algorithm, keymaster_error_t* error) {
     if (error) *error = KM_ERROR_OK;
 
-    switch(algorithm) {
+    CertificateChain retval;
+
+    switch (algorithm) {
     case KM_ALGORITHM_RSA:
-        return &kRsaAttestChain;
+        retval = CertificateChain::clone(kRsaAttestChain);
+        if (!retval.entries && error) *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
         break;
     case KM_ALGORITHM_EC:
-        return &kEcAttestChain;
+        retval = CertificateChain::clone(kEcAttestChain);
+        if (!retval.entries && error) *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
         break;
     default:
         if (error) *error = KM_ERROR_UNSUPPORTED_ALGORITHM;
+        break;
     }
-    return nullptr;
+
+    return retval;
 }
 
-} // namespace keymaster
-
+}  // namespace keymaster
diff --git a/contexts/soft_attestation_context.cpp b/contexts/soft_attestation_context.cpp
new file mode 100644
index 0000000..4a2ba9f
--- /dev/null
+++ b/contexts/soft_attestation_context.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <keymaster/contexts/soft_attestation_context.h>
+
+#include <string>
+
+#include <keymaster/km_openssl/asymmetric_key.h>
+#include <keymaster/km_openssl/attestation_utils.h>
+
+namespace keymaster {
+
+const AttestationContext::VerifiedBootParams*
+SoftAttestationContext::GetVerifiedBootParams(keymaster_error_t* error) const {
+    static AttestationContext::VerifiedBootParams params;
+    static std::string fake_vb_key(32, 0);
+
+    params.verified_boot_key = {reinterpret_cast<uint8_t*>(fake_vb_key.data()), fake_vb_key.size()};
+    params.verified_boot_hash = {reinterpret_cast<uint8_t*>(fake_vb_key.data()),
+                                 fake_vb_key.size()};
+    params.verified_boot_state = KM_VERIFIED_BOOT_UNVERIFIED;
+    params.device_locked = false;
+    *error = KM_ERROR_OK;
+    return &params;
+}
+
+}  // namespace keymaster
diff --git a/contexts/soft_keymaster_context.cpp b/contexts/soft_keymaster_context.cpp
index a0a42d3..86bdd3f 100644
--- a/contexts/soft_keymaster_context.cpp
+++ b/contexts/soft_keymaster_context.cpp
@@ -28,17 +28,15 @@
 #include <keymaster/km_openssl/aes_key.h>
 #include <keymaster/km_openssl/asymmetric_key.h>
 #include <keymaster/km_openssl/attestation_utils.h>
+#include <keymaster/km_openssl/certificate_utils.h>
 #include <keymaster/km_openssl/hmac_key.h>
 #include <keymaster/km_openssl/openssl_err.h>
 #include <keymaster/km_openssl/triple_des_key.h>
-#include <keymaster/legacy_support/ec_keymaster0_key.h>
 #include <keymaster/legacy_support/ec_keymaster1_key.h>
-#include <keymaster/legacy_support/keymaster0_engine.h>
-#include <keymaster/legacy_support/rsa_keymaster0_key.h>
 #include <keymaster/legacy_support/rsa_keymaster1_key.h>
 #include <keymaster/logger.h>
 
-#include "soft_attestation_cert.h"
+#include <keymaster/contexts/soft_attestation_cert.h>
 
 using std::unique_ptr;
 
@@ -52,41 +50,28 @@
 
 }  // anonymous namespace
 
-SoftKeymasterContext::SoftKeymasterContext(const std::string& root_of_trust)
-    : rsa_factory_(new RsaKeyFactory(this)), ec_factory_(new EcKeyFactory(this)),
-      aes_factory_(new AesKeyFactory(this, this)),
-      tdes_factory_(new TripleDesKeyFactory(this, this)),
-      hmac_factory_(new HmacKeyFactory(this, this)), km1_dev_(nullptr),
-      root_of_trust_(string2Blob(root_of_trust)), os_version_(0), os_patchlevel_(0) {}
+SoftKeymasterContext::SoftKeymasterContext(KmVersion version, const std::string& root_of_trust)
+    : SoftAttestationContext(version),  //
+      rsa_factory_(new RsaKeyFactory(*this /* blob_maker */, *this /* context */)),
+      ec_factory_(new EcKeyFactory(*this /* blob_maker */, *this /* context */)),
+      aes_factory_(new AesKeyFactory(*this /* blob_maker */, *this /* random_source */)),
+      tdes_factory_(new TripleDesKeyFactory(*this /* blob_maker */, *this /* random_source */)),
+      hmac_factory_(new HmacKeyFactory(*this /* blob_maker */, *this /* random_source */)),
+      km1_dev_(nullptr), root_of_trust_(string2Blob(root_of_trust)), os_version_(0),
+      os_patchlevel_(0) {}
 
 SoftKeymasterContext::~SoftKeymasterContext() {}
 
-keymaster_error_t SoftKeymasterContext::SetHardwareDevice(keymaster0_device_t* keymaster0_device) {
-    if (!keymaster0_device)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
-
-    if ((keymaster0_device->flags & KEYMASTER_SOFTWARE_ONLY) != 0) {
-        LOG_E("SoftKeymasterContext only wraps hardware keymaster0 devices", 0);
-        return KM_ERROR_INVALID_ARGUMENT;
-    }
-
-    km0_engine_.reset(new Keymaster0Engine(keymaster0_device));
-    rsa_factory_.reset(new RsaKeymaster0KeyFactory(this, km0_engine_.get()));
-    ec_factory_.reset(new EcdsaKeymaster0KeyFactory(this, km0_engine_.get()));
-    // Keep AES and HMAC factories.
-
-    return KM_ERROR_OK;
-}
-
 keymaster_error_t SoftKeymasterContext::SetHardwareDevice(keymaster1_device_t* keymaster1_device) {
-    if (!keymaster1_device)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!keymaster1_device) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
     km1_dev_ = keymaster1_device;
 
     km1_engine_.reset(new Keymaster1Engine(keymaster1_device));
-    rsa_factory_.reset(new RsaKeymaster1KeyFactory(this, km1_engine_.get()));
-    ec_factory_.reset(new EcdsaKeymaster1KeyFactory(this, km1_engine_.get()));
+    rsa_factory_.reset(new RsaKeymaster1KeyFactory(
+        *this /* blob_maker */, *this /* attestation_context */, km1_engine_.get()));
+    ec_factory_.reset(new EcdsaKeymaster1KeyFactory(
+        *this /* blob_maker */, *this /* attestation_context */, km1_engine_.get()));
 
     // Use default HMAC and AES key factories. Higher layers will pass HMAC/AES keys/ops that are
     // supported by the hardware to it and other ones to the software-only factory.
@@ -135,8 +120,7 @@
 OperationFactory* SoftKeymasterContext::GetOperationFactory(keymaster_algorithm_t algorithm,
                                                             keymaster_purpose_t purpose) const {
     KeyFactory* key_factory = GetKeyFactory(algorithm);
-    if (!key_factory)
-        return nullptr;
+    if (!key_factory) return nullptr;
     return key_factory->GetOperationFactory(purpose);
 }
 
@@ -179,8 +163,7 @@
         // Everything else we just copy into sw_enforced, unless the KeyFactory has placed it in
         // hw_enforced, in which case we defer to its decision.
         default:
-            if (hw_enforced->GetTagCount(entry.tag) == 0)
-                sw_enforced->push_back(entry);
+            if (hw_enforced->GetTagCount(entry.tag) == 0) sw_enforced->push_back(entry);
             break;
         }
     }
@@ -201,13 +184,11 @@
                                                       AuthorizationSet* sw_enforced) const {
     keymaster_error_t error = SetAuthorizations(key_description, origin, os_version_,
                                                 os_patchlevel_, hw_enforced, sw_enforced);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     AuthorizationSet hidden;
     error = BuildHiddenAuthorizations(key_description, &hidden, root_of_trust_);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     return SerializeIntegrityAssuredBlob(key_material, hidden, *hw_enforced, *sw_enforced, blob);
 }
@@ -217,8 +198,7 @@
                                                        KeymasterKeyBlob* upgraded_key) const {
     UniquePtr<Key> key;
     keymaster_error_t error = ParseKeyBlob(key_to_upgrade, upgrade_params, &key);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     // Three cases here:
     //
@@ -233,7 +213,7 @@
 
     // Handle case 3.
     if (km1_dev_ && key->hw_enforced().Contains(TAG_PURPOSE) &&
-            !key->hw_enforced().Contains(TAG_OS_PATCHLEVEL))
+        !key->hw_enforced().Contains(TAG_OS_PATCHLEVEL))
         return KM_ERROR_INVALID_ARGUMENT;
 
     // Handle case 1 and 2
@@ -281,7 +261,7 @@
     AuthorizationSet hidden;
     keymaster_error_t error;
 
-    auto constructKey = [&, this] () mutable -> keymaster_error_t {
+    auto constructKey = [&, this]() mutable -> keymaster_error_t {
         // GetKeyFactory
         if (error != KM_ERROR_OK) return error;
         keymaster_algorithm_t algorithm;
@@ -295,34 +275,27 @@
     };
 
     error = BuildHiddenAuthorizations(additional_params, &hidden, root_of_trust_);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     // Assume it's an integrity-assured blob (new software-only blob, or new keymaster0-backed
     // blob).
-    error = DeserializeIntegrityAssuredBlob(blob, hidden, &key_material, &hw_enforced, &sw_enforced);
-    if (error != KM_ERROR_INVALID_KEY_BLOB)
-        return constructKey();
+    error =
+        DeserializeIntegrityAssuredBlob(blob, hidden, &key_material, &hw_enforced, &sw_enforced);
+    if (error != KM_ERROR_INVALID_KEY_BLOB) return constructKey();
 
-    // Wasn't an integrity-assured blob.  Maybe it's an OCB-encrypted blob.
-    error = ParseOcbAuthEncryptedBlob(blob, hidden, &key_material, &hw_enforced, &sw_enforced);
-    if (error == KM_ERROR_OK)
-        LOG_D("Parsed an old keymaster1 software key", 0);
-    if (error != KM_ERROR_INVALID_KEY_BLOB)
-        return constructKey();
+    // Wasn't an integrity-assured blob.  Maybe it's an Auth-encrypted blob.
+    error = ParseAuthEncryptedBlob(blob, hidden, &key_material, &hw_enforced, &sw_enforced);
+    if (error == KM_ERROR_OK) LOG_D("Parsed an old keymaster1 software key", 0);
+    if (error != KM_ERROR_INVALID_KEY_BLOB) return constructKey();
 
     // Wasn't an OCB-encrypted blob.  Maybe it's an old softkeymaster blob.
     error = ParseOldSoftkeymasterBlob(blob, &key_material, &hw_enforced, &sw_enforced);
-    if (error == KM_ERROR_OK)
-        LOG_D("Parsed an old sofkeymaster key", 0);
-    if (error != KM_ERROR_INVALID_KEY_BLOB)
-        return constructKey();
+    if (error == KM_ERROR_OK) LOG_D("Parsed an old sofkeymaster key", 0);
+    if (error != KM_ERROR_INVALID_KEY_BLOB) return constructKey();
 
     if (km1_dev_) {
         error = ParseKeymaster1HwBlob(blob, additional_params, &key_material, &hw_enforced,
                                       &sw_enforced);
-    } else if (km0_engine_) {
-        error = ParseKeymaster0HwBlob(blob, &key_material, &hw_enforced, &sw_enforced);
     } else {
         return KM_ERROR_INVALID_KEY_BLOB;
     }
@@ -345,45 +318,12 @@
         return km1_engine_->DeleteKey(blob);
     }
 
-    if (km0_engine_) {
-        // This could be a keymaster0 hardware key, and it could be either raw or encapsulated in an
-        // integrity-assured blob.  If it's integrity-assured, we can't validate it strongly,
-        // because we don't have the necessary additional_params data.  However, the probability
-        // that anything other than an integrity-assured blob would have all of the structure
-        // required to decode as a valid blob is low -- unless it's maliciously-constructed, but the
-        // deserializer should be proof against bad data, as should the keymaster0 hardware.
-        //
-        // Thus, we first try to parse it as integrity-assured.  If that works, we pass the result
-        // to the underlying hardware.  If not, we pass blob unmodified to the underlying hardware.
-        KeymasterKeyBlob key_material;
-        AuthorizationSet hw_enforced, sw_enforced;
-        keymaster_error_t error = DeserializeIntegrityAssuredBlob_NoHmacCheck(
-            blob, &key_material, &hw_enforced, &sw_enforced);
-        if (error == KM_ERROR_OK && km0_engine_->DeleteKey(key_material))
-            return KM_ERROR_OK;
-
-        km0_engine_->DeleteKey(blob);
-
-        // We succeed unconditionally at this point, even if delete failed.  Failure indicates that
-        // either the blob is a software blob (which we can't distinguish with certainty without
-        // additional_params) or because it is a hardware blob and the hardware failed.  In the
-        // first case, there is no error.  In the second case, the client can't do anything to fix
-        // it anyway, so it's not too harmful to simply swallow the error.  This is not ideal, but
-        // it's the least-bad alternative.
-        return KM_ERROR_OK;
-    }
-
     // Nothing to do for software-only contexts.
     return KM_ERROR_OK;
 }
 
 keymaster_error_t SoftKeymasterContext::DeleteAllKeys() const {
-    if (km1_engine_)
-        return km1_engine_->DeleteAllKeys();
-
-    if (km0_engine_ && !km0_engine_->DeleteAllKeys())
-        return KM_ERROR_UNKNOWN_ERROR;
-
+    if (km1_engine_) return km1_engine_->DeleteAllKeys();
     return KM_ERROR_OK;
 }
 
@@ -402,17 +342,14 @@
     keymaster_blob_t app_data = {nullptr, 0};
     keymaster_blob_t* client_id_ptr = nullptr;
     keymaster_blob_t* app_data_ptr = nullptr;
-    if (additional_params.GetTagValue(TAG_APPLICATION_ID, &client_id))
-        client_id_ptr = &client_id;
-    if (additional_params.GetTagValue(TAG_APPLICATION_DATA, &app_data))
-        app_data_ptr = &app_data;
+    if (additional_params.GetTagValue(TAG_APPLICATION_ID, &client_id)) client_id_ptr = &client_id;
+    if (additional_params.GetTagValue(TAG_APPLICATION_DATA, &app_data)) app_data_ptr = &app_data;
 
     // Get key characteristics, which incidentally verifies that the HW recognizes the key.
     keymaster_key_characteristics_t* characteristics;
     keymaster_error_t error = km1_dev_->get_key_characteristics(km1_dev_, &blob, client_id_ptr,
                                                                 app_data_ptr, &characteristics);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
     unique_ptr<keymaster_key_characteristics_t, Characteristics_Delete> characteristics_deleter(
         characteristics);
 
@@ -424,49 +361,49 @@
     return KM_ERROR_OK;
 }
 
-keymaster_error_t SoftKeymasterContext::ParseKeymaster0HwBlob(const KeymasterKeyBlob& blob,
-                                                              KeymasterKeyBlob* key_material,
-                                                              AuthorizationSet* hw_enforced,
-                                                              AuthorizationSet* sw_enforced) const {
-    assert(km0_engine_);
-
-    unique_ptr<EVP_PKEY, EVP_PKEY_Delete> tmp_key(km0_engine_->GetKeymaster0PublicKey(blob));
-
-    if (!tmp_key)
-        return KM_ERROR_INVALID_KEY_BLOB;
-
-    LOG_D("Module \"%s\" accepted key", km0_engine_->device()->common.module->name);
-    keymaster_error_t error = FakeKeyAuthorizations(tmp_key.get(), hw_enforced, sw_enforced);
-    if (error == KM_ERROR_OK)
-        *key_material = blob;
-
-    return error;
-}
-
-keymaster_error_t SoftKeymasterContext::GenerateAttestation(const Key& key,
-        const AuthorizationSet& attest_params, CertChainPtr* cert_chain) const {
-
-    keymaster_error_t error = KM_ERROR_OK;
+CertificateChain
+SoftKeymasterContext::GenerateAttestation(const Key& key,  //
+                                          const AuthorizationSet& attest_params,
+                                          UniquePtr<Key> /* attest_key */,
+                                          const KeymasterBlob& /* issuer_subject */,  //
+                                          keymaster_error_t* error) const {
     keymaster_algorithm_t key_algorithm;
     if (!key.authorizations().GetTagValue(TAG_ALGORITHM, &key_algorithm)) {
-        return KM_ERROR_UNKNOWN_ERROR;
+        *error = KM_ERROR_UNKNOWN_ERROR;
+        return {};
     }
 
-    if ((key_algorithm != KM_ALGORITHM_RSA && key_algorithm != KM_ALGORITHM_EC))
-        return KM_ERROR_INCOMPATIBLE_ALGORITHM;
+    if ((key_algorithm != KM_ALGORITHM_RSA && key_algorithm != KM_ALGORITHM_EC)) {
+        *error = KM_ERROR_INCOMPATIBLE_ALGORITHM;
+        return {};
+    }
 
     // We have established that the given key has the correct algorithm, and because this is the
     // SoftKeymasterContext we can assume that the Key is an AsymmetricKey. So we can downcast.
     const AsymmetricKey& asymmetric_key = static_cast<const AsymmetricKey&>(key);
 
-    auto attestation_chain = getAttestationChain(key_algorithm, &error);
-    if (error != KM_ERROR_OK) return error;
+    return generate_attestation(asymmetric_key, attest_params, {} /* attest_key */, *this, error);
+}
 
-    auto attestation_key = getAttestationKey(key_algorithm, &error);
-    if (error != KM_ERROR_OK) return error;
+CertificateChain SoftKeymasterContext::GenerateSelfSignedCertificate(
+    const Key& key, const AuthorizationSet& cert_params, bool fake_signature,
+    keymaster_error_t* error) const {
+    keymaster_algorithm_t key_algorithm;
+    if (!key.authorizations().GetTagValue(TAG_ALGORITHM, &key_algorithm)) {
+        *error = KM_ERROR_UNKNOWN_ERROR;
+        return {};
+    }
 
-    return generate_attestation(asymmetric_key, attest_params,
-            *attestation_chain, *attestation_key, *this, cert_chain);
+    if ((key_algorithm != KM_ALGORITHM_RSA && key_algorithm != KM_ALGORITHM_EC)) {
+        *error = KM_ERROR_INCOMPATIBLE_ALGORITHM;
+        return {};
+    }
+
+    // We have established that the given key has the correct algorithm, and because this is the
+    // SoftKeymasterContext we can assume that the Key is an AsymmetricKey. So we can downcast.
+    const AsymmetricKey& asymmetric_key = static_cast<const AsymmetricKey&>(key);
+
+    return generate_self_signed_cert(asymmetric_key, cert_params, fake_signature, error);
 }
 
 keymaster_error_t SoftKeymasterContext::UnwrapKey(const KeymasterKeyBlob&, const KeymasterKeyBlob&,
diff --git a/contexts/soft_keymaster_device.cpp b/contexts/soft_keymaster_device.cpp
index 455c40a..71b0dd1 100644
--- a/contexts/soft_keymaster_device.cpp
+++ b/contexts/soft_keymaster_device.cpp
@@ -38,11 +38,10 @@
 #include <keymaster/android_keymaster_messages.h>
 #include <keymaster/android_keymaster_utils.h>
 #include <keymaster/authorization_set.h>
-#include <keymaster/km_openssl/openssl_utils.h>
 #include <keymaster/contexts/soft_keymaster_context.h>
-#include <keymaster/soft_keymaster_logger.h>
 #include <keymaster/key.h>
-
+#include <keymaster/km_openssl/openssl_utils.h>
+#include <keymaster/soft_keymaster_logger.h>
 
 struct keystore_module soft_keymaster1_device_module = {
     .common =
@@ -140,8 +139,7 @@
             bool alg_purpose_supports_all;
             keymaster_error_t error =
                 add_digests(dev, algorithm, purpose, map, &alg_purpose_supports_all);
-            if (error != KM_ERROR_OK)
-                return error;
+            if (error != KM_ERROR_OK) return error;
             *supports_all &= alg_purpose_supports_all;
         }
 
@@ -152,17 +150,15 @@
             bool alg_purpose_supports_all;
             keymaster_error_t error =
                 add_digests(dev, algorithm, purpose, map, &alg_purpose_supports_all);
-            if (error != KM_ERROR_OK)
-                return error;
+            if (error != KM_ERROR_OK) return error;
             *supports_all &= alg_purpose_supports_all;
         }
 
     return KM_ERROR_OK;
 }
 
-SoftKeymasterDevice::SoftKeymasterDevice()
-    : wrapped_km1_device_(nullptr),
-      context_(new SoftKeymasterContext),
+SoftKeymasterDevice::SoftKeymasterDevice(KmVersion version)
+    : wrapped_km1_device_(nullptr), context_(new SoftKeymasterContext(version)),
       impl_(new AndroidKeymaster(context_, kOperationTableSize)), configured_(false) {
     LOG_I("Creating device", 0);
     LOG_D("Device address: %p", this);
@@ -181,49 +177,18 @@
                              KEYMASTER_SUPPORTS_EC);
 }
 
-keymaster_error_t SoftKeymasterDevice::SetHardwareDevice(keymaster0_device_t* keymaster0_device) {
-    assert(keymaster0_device);
-    LOG_D("Reinitializing SoftKeymasterDevice to use HW keymaster0", 0);
-
-    if (!context_)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
-
-    supports_all_digests_ = false;
-    keymaster_error_t error = context_->SetHardwareDevice(keymaster0_device);
-    if (error != KM_ERROR_OK)
-        return error;
-
-    initialize_device_struct(keymaster0_device->flags);
-
-    module_name_ = km1_device_.common.module->name;
-    module_name_.append("(Wrapping ");
-    module_name_.append(keymaster0_device->common.module->name);
-    module_name_.append(")");
-
-    updated_module_ = *km1_device_.common.module;
-    updated_module_.name = module_name_.c_str();
-
-    km1_device_.common.module = &updated_module_;
-
-    wrapped_km1_device_ = nullptr;
-    return KM_ERROR_OK;
-}
-
 keymaster_error_t SoftKeymasterDevice::SetHardwareDevice(keymaster1_device_t* keymaster1_device) {
     assert(keymaster1_device);
     LOG_D("Reinitializing SoftKeymasterDevice to use HW keymaster1", 0);
 
-    if (!context_)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!context_) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
     keymaster_error_t error =
         map_digests(keymaster1_device, &km1_device_digests_, &supports_all_digests_);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     error = context_->SetHardwareDevice(keymaster1_device);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     initialize_device_struct(keymaster1_device->flags);
 
@@ -359,15 +324,12 @@
 void AddClientAndAppData(const keymaster_blob_t* client_id, const keymaster_blob_t* app_data,
                          RequestType* request) {
     request->additional_params.Clear();
-    if (client_id)
-        request->additional_params.push_back(TAG_APPLICATION_ID, *client_id);
-    if (app_data)
-        request->additional_params.push_back(TAG_APPLICATION_DATA, *app_data);
+    if (client_id) request->additional_params.push_back(TAG_APPLICATION_ID, *client_id);
+    if (app_data) request->additional_params.push_back(TAG_APPLICATION_DATA, *app_data);
 }
 
 template <typename T> SoftKeymasterDevice* convert_device(const T* dev) {
-    static_assert((std::is_same<T, keymaster0_device_t>::value ||
-                   std::is_same<T, keymaster1_device_t>::value ||
+    static_assert((std::is_same<T, keymaster1_device_t>::value ||
                    std::is_same<T, keymaster2_device_t>::value),
                   "convert_device should only be applied to keymaster devices");
     return reinterpret_cast<SoftKeymasterDevice*>(dev->context);
@@ -384,7 +346,7 @@
     return false;
 }
 
-}  // unnamed namespaced
+}  // namespace
 
 /* static */
 int SoftKeymasterDevice::close_device(hw_device_t* dev) {
@@ -410,19 +372,17 @@
 keymaster_error_t SoftKeymasterDevice::get_supported_algorithms(const keymaster1_device_t* dev,
                                                                 keymaster_algorithm_t** algorithms,
                                                                 size_t* algorithms_length) {
-    if (!dev)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
-    if (!algorithms || !algorithms_length)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    if (!algorithms || !algorithms_length) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
-    if (km1_dev)
-        return km1_dev->get_supported_algorithms(km1_dev, algorithms, algorithms_length);
+    if (km1_dev) return km1_dev->get_supported_algorithms(km1_dev, algorithms, algorithms_length);
 
-    SupportedAlgorithmsRequest request;
-    SupportedAlgorithmsResponse response;
-    convert_device(dev)->impl_->SupportedAlgorithms(request, &response);
+    auto& impl_ = convert_device(dev)->impl_;
+    SupportedAlgorithmsRequest request(impl_->message_version());
+    SupportedAlgorithmsResponse response(impl_->message_version());
+    impl_->SupportedAlgorithms(request, &response);
     if (response.error != KM_ERROR_OK) {
         LOG_E("get_supported_algorithms failed with %d", response.error);
 
@@ -432,8 +392,7 @@
     *algorithms_length = response.results_length;
     *algorithms =
         reinterpret_cast<keymaster_algorithm_t*>(malloc(*algorithms_length * sizeof(**algorithms)));
-    if (!*algorithms)
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!*algorithms) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
     std::copy(response.results, response.results + response.results_length, *algorithms);
     return KM_ERROR_OK;
 }
@@ -444,21 +403,20 @@
                                                                  keymaster_purpose_t purpose,
                                                                  keymaster_block_mode_t** modes,
                                                                  size_t* modes_length) {
-    if (!dev)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
-    if (!modes || !modes_length)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    if (!modes || !modes_length) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
     if (km1_dev)
         return km1_dev->get_supported_block_modes(km1_dev, algorithm, purpose, modes, modes_length);
 
-    SupportedBlockModesRequest request;
+    auto& impl_ = convert_device(dev)->impl_;
+    SupportedBlockModesRequest request(impl_->message_version());
     request.algorithm = algorithm;
     request.purpose = purpose;
-    SupportedBlockModesResponse response;
-    convert_device(dev)->impl_->SupportedBlockModes(request, &response);
+    SupportedBlockModesResponse response(impl_->message_version());
+    impl_->SupportedBlockModes(request, &response);
 
     if (response.error != KM_ERROR_OK) {
         LOG_E("get_supported_block_modes failed with %d", response.error);
@@ -468,8 +426,7 @@
 
     *modes_length = response.results_length;
     *modes = reinterpret_cast<keymaster_block_mode_t*>(malloc(*modes_length * sizeof(**modes)));
-    if (!*modes)
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!*modes) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
     std::copy(response.results, response.results + response.results_length, *modes);
     return KM_ERROR_OK;
 }
@@ -480,21 +437,20 @@
                                                                    keymaster_purpose_t purpose,
                                                                    keymaster_padding_t** modes,
                                                                    size_t* modes_length) {
-    if (!dev)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
-    if (!modes || !modes_length)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    if (!modes || !modes_length) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
     if (km1_dev)
         return km1_dev->get_supported_padding_modes(km1_dev, algorithm, purpose, modes,
                                                     modes_length);
 
-    SupportedPaddingModesRequest request;
+    auto& impl_ = convert_device(dev)->impl_;
+    SupportedPaddingModesRequest request(impl_->message_version());
     request.algorithm = algorithm;
     request.purpose = purpose;
-    SupportedPaddingModesResponse response;
+    SupportedPaddingModesResponse response(impl_->message_version());
     convert_device(dev)->impl_->SupportedPaddingModes(request, &response);
 
     if (response.error != KM_ERROR_OK) {
@@ -504,8 +460,7 @@
 
     *modes_length = response.results_length;
     *modes = reinterpret_cast<keymaster_padding_t*>(malloc(*modes_length * sizeof(**modes)));
-    if (!*modes)
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!*modes) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
     std::copy(response.results, response.results + response.results_length, *modes);
     return KM_ERROR_OK;
 }
@@ -516,21 +471,20 @@
                                                              keymaster_purpose_t purpose,
                                                              keymaster_digest_t** digests,
                                                              size_t* digests_length) {
-    if (!dev)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
-    if (!digests || !digests_length)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    if (!digests || !digests_length) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
     if (km1_dev)
         return km1_dev->get_supported_digests(km1_dev, algorithm, purpose, digests, digests_length);
 
-    SupportedDigestsRequest request;
+    auto& impl_ = convert_device(dev)->impl_;
+    SupportedDigestsRequest request(impl_->message_version());
     request.algorithm = algorithm;
     request.purpose = purpose;
-    SupportedDigestsResponse response;
-    convert_device(dev)->impl_->SupportedDigests(request, &response);
+    SupportedDigestsResponse response(impl_->message_version());
+    impl_->SupportedDigests(request, &response);
 
     if (response.error != KM_ERROR_OK) {
         LOG_E("get_supported_digests failed with %d", response.error);
@@ -539,8 +493,7 @@
 
     *digests_length = response.results_length;
     *digests = reinterpret_cast<keymaster_digest_t*>(malloc(*digests_length * sizeof(**digests)));
-    if (!*digests)
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!*digests) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
     std::copy(response.results, response.results + response.results_length, *digests);
     return KM_ERROR_OK;
 }
@@ -549,20 +502,19 @@
 keymaster_error_t SoftKeymasterDevice::get_supported_import_formats(
     const keymaster1_device_t* dev, keymaster_algorithm_t algorithm,
     keymaster_key_format_t** formats, size_t* formats_length) {
-    if (!dev)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
-    if (!formats || !formats_length)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    if (!formats || !formats_length) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
     if (km1_dev)
         return km1_dev->get_supported_import_formats(km1_dev, algorithm, formats, formats_length);
 
-    SupportedImportFormatsRequest request;
+    auto& impl_ = convert_device(dev)->impl_;
+    SupportedImportFormatsRequest request(impl_->message_version());
     request.algorithm = algorithm;
-    SupportedImportFormatsResponse response;
-    convert_device(dev)->impl_->SupportedImportFormats(request, &response);
+    SupportedImportFormatsResponse response(impl_->message_version());
+    impl_->SupportedImportFormats(request, &response);
 
     if (response.error != KM_ERROR_OK) {
         LOG_E("get_supported_import_formats failed with %d", response.error);
@@ -572,8 +524,7 @@
     *formats_length = response.results_length;
     *formats =
         reinterpret_cast<keymaster_key_format_t*>(malloc(*formats_length * sizeof(**formats)));
-    if (!*formats)
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!*formats) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
     std::copy(response.results, response.results + response.results_length, *formats);
     return KM_ERROR_OK;
 }
@@ -582,20 +533,19 @@
 keymaster_error_t SoftKeymasterDevice::get_supported_export_formats(
     const keymaster1_device_t* dev, keymaster_algorithm_t algorithm,
     keymaster_key_format_t** formats, size_t* formats_length) {
-    if (!dev)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
-    if (!formats || !formats_length)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    if (!formats || !formats_length) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
     if (km1_dev)
         return km1_dev->get_supported_export_formats(km1_dev, algorithm, formats, formats_length);
 
-    SupportedExportFormatsRequest request;
+    auto& impl_ = convert_device(dev)->impl_;
+    SupportedExportFormatsRequest request(impl_->message_version());
     request.algorithm = algorithm;
-    SupportedExportFormatsResponse response;
-    convert_device(dev)->impl_->SupportedExportFormats(request, &response);
+    SupportedExportFormatsResponse response(impl_->message_version());
+    impl_->SupportedExportFormats(request, &response);
 
     if (response.error != KM_ERROR_OK) {
         LOG_E("get_supported_export_formats failed with %d", response.error);
@@ -605,8 +555,7 @@
     *formats_length = response.results_length;
     *formats =
         reinterpret_cast<keymaster_key_format_t*>(malloc(*formats_length * sizeof(**formats)));
-    if (!*formats)
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!*formats) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
     std::copy(response.results, response.results + *formats_length, *formats);
     return KM_ERROR_OK;
 }
@@ -615,46 +564,42 @@
 keymaster_error_t SoftKeymasterDevice::configure(const keymaster2_device_t* dev,
                                                  const keymaster_key_param_set_t* params) {
     AuthorizationSet params_copy(*params);
-    ConfigureRequest request;
+    auto& impl_ = convert_device(dev)->impl_;
+    ConfigureRequest request(impl_->message_version());
     if (!params_copy.GetTagValue(TAG_OS_VERSION, &request.os_version) ||
         !params_copy.GetTagValue(TAG_OS_PATCHLEVEL, &request.os_patchlevel)) {
         LOG_E("Configuration parameters must contain OS version and patch level", 0);
         return KM_ERROR_INVALID_ARGUMENT;
     }
-    ConfigureResponse response;
-    convert_device(dev)->impl_->Configure(request, &response);
-    if (response.error == KM_ERROR_OK)
-        convert_device(dev)->configured_ = true;
+    ConfigureResponse response(impl_->message_version());
+    impl_->Configure(request, &response);
+    if (response.error == KM_ERROR_OK) convert_device(dev)->configured_ = true;
     return response.error;
 }
 
 /* static */
 keymaster_error_t SoftKeymasterDevice::add_rng_entropy(const keymaster1_device_t* dev,
                                                        const uint8_t* data, size_t data_length) {
-    if (!dev)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
     const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
-    if (km1_dev)
-        return km1_dev->add_rng_entropy(km1_dev, data, data_length);
+    if (km1_dev) return km1_dev->add_rng_entropy(km1_dev, data, data_length);
 
-    AddEntropyRequest request;
+    auto& impl_ = convert_device(dev)->impl_;
+    AddEntropyRequest request(impl_->message_version());
     request.random_data.Reinitialize(data, data_length);
-    AddEntropyResponse response;
-    convert_device(dev)->impl_->AddRngEntropy(request, &response);
-    if (response.error != KM_ERROR_OK)
-        LOG_E("add_rng_entropy failed with %d", response.error);
+    AddEntropyResponse response(impl_->message_version());
+    impl_->AddRngEntropy(request, &response);
+    if (response.error != KM_ERROR_OK) LOG_E("add_rng_entropy failed with %d", response.error);
     return response.error;
 }
 
 /* static */
 keymaster_error_t SoftKeymasterDevice::add_rng_entropy(const keymaster2_device_t* dev,
                                                        const uint8_t* data, size_t data_length) {
-    if (!dev)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
-    if (!convert_device(dev)->configured())
-        return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+    if (!convert_device(dev)->configured()) return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
 
     SoftKeymasterDevice* sk_dev = convert_device(dev);
     return add_rng_entropy(&sk_dev->km1_device_, data, data_length);
@@ -690,8 +635,7 @@
                                                     keymaster_purpose_t purpose,
                                                     const AuthorizationSet& params) const {
     assert(wrapped_km1_device_);
-    if (!wrapped_km1_device_)
-        return true;
+    if (!wrapped_km1_device_) return true;
 
     switch (algorithm) {
     case KM_ALGORITHM_AES:
@@ -716,8 +660,7 @@
 bool SoftKeymasterDevice::KeyRequiresSoftwareDigesting(
     const AuthorizationSet& key_description) const {
     assert(wrapped_km1_device_);
-    if (!wrapped_km1_device_)
-        return true;
+    if (!wrapped_km1_device_) return true;
 
     keymaster_algorithm_t algorithm;
     if (!key_description.GetTagValue(TAG_ALGORITHM, &algorithm)) {
@@ -728,8 +671,7 @@
     for (auto& entry : key_description)
         if (entry.tag == TAG_PURPOSE) {
             keymaster_purpose_t purpose = static_cast<keymaster_purpose_t>(entry.enumerated);
-            if (RequiresSoftwareDigesting(algorithm, purpose, key_description))
-                return true;
+            if (RequiresSoftwareDigesting(algorithm, purpose, key_description)) return true;
         }
 
     return false;
@@ -739,30 +681,27 @@
 keymaster_error_t SoftKeymasterDevice::generate_key(
     const keymaster1_device_t* dev, const keymaster_key_param_set_t* params,
     keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t** characteristics) {
-    if (!dev || !params)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!dev || !params) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
-    if (!key_blob)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    if (!key_blob) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     SoftKeymasterDevice* sk_dev = convert_device(dev);
 
-    GenerateKeyRequest request;
+    auto& impl_ = sk_dev->impl_;
+    GenerateKeyRequest request(impl_->message_version());
     request.key_description.Reinitialize(*params);
 
     keymaster1_device_t* km1_dev = sk_dev->wrapped_km1_device_;
     if (km1_dev && !sk_dev->KeyRequiresSoftwareDigesting(request.key_description))
         return km1_dev->generate_key(km1_dev, params, key_blob, characteristics);
 
-    GenerateKeyResponse response;
-    sk_dev->impl_->GenerateKey(request, &response);
-    if (response.error != KM_ERROR_OK)
-        return response.error;
+    GenerateKeyResponse response(impl_->message_version());
+    impl_->GenerateKey(request, &response);
+    if (response.error != KM_ERROR_OK) return response.error;
 
     key_blob->key_material_size = response.key_blob.key_material_size;
     uint8_t* tmp = reinterpret_cast<uint8_t*>(malloc(key_blob->key_material_size));
-    if (!tmp)
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!tmp) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
     memcpy(tmp, response.key_blob.key_material, response.key_blob.key_material_size);
     key_blob->key_material = tmp;
 
@@ -774,8 +713,7 @@
         response.unenforced.erase(response.unenforced.find(TAG_OS_PATCHLEVEL));
 
         *characteristics = BuildCharacteristics(response.enforced, response.unenforced);
-        if (!*characteristics)
-            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        if (!*characteristics) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
     }
 
     return KM_ERROR_OK;
@@ -786,18 +724,16 @@
                                   const keymaster_key_param_set_t* params,
                                   keymaster_key_blob_t* key_blob,
                                   keymaster_key_characteristics_t* characteristics) {
-    if (!dev)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
-    if (!convert_device(dev)->configured())
-        return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+    if (!convert_device(dev)->configured()) return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
 
-    if (!key_blob)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    if (!key_blob) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     SoftKeymasterDevice* sk_dev = convert_device(dev);
 
-    GenerateKeyRequest request;
+    auto& impl_ = sk_dev->impl_;
+    GenerateKeyRequest request(impl_->message_version());
     request.key_description.Reinitialize(*params);
 
     keymaster1_device_t* km1_dev = sk_dev->wrapped_km1_device_;
@@ -825,8 +761,7 @@
         keymaster_key_characteristics_t* chars_ptr;
         keymaster_error_t error = km1_dev->generate_key(km1_dev, &request.key_description, key_blob,
                                                         characteristics ? &chars_ptr : nullptr);
-        if (error != KM_ERROR_OK)
-            return error;
+        if (error != KM_ERROR_OK) return error;
 
         if (characteristics) {
             *characteristics = *chars_ptr;
@@ -836,15 +771,13 @@
         return KM_ERROR_OK;
     }
 
-    GenerateKeyResponse response;
-    sk_dev->impl_->GenerateKey(request, &response);
-    if (response.error != KM_ERROR_OK)
-        return response.error;
+    GenerateKeyResponse response(impl_->message_version());
+    impl_->GenerateKey(request, &response);
+    if (response.error != KM_ERROR_OK) return response.error;
 
     key_blob->key_material_size = response.key_blob.key_material_size;
     uint8_t* tmp = reinterpret_cast<uint8_t*>(malloc(key_blob->key_material_size));
-    if (!tmp)
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!tmp) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
     memcpy(tmp, response.key_blob.key_material, response.key_blob.key_material_size);
     key_blob->key_material = tmp;
 
@@ -861,11 +794,9 @@
     const keymaster1_device_t* dev, const keymaster_key_blob_t* key_blob,
     const keymaster_blob_t* client_id, const keymaster_blob_t* app_data,
     keymaster_key_characteristics_t** characteristics) {
-    if (!dev || !key_blob || !key_blob->key_material)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!dev || !key_blob || !key_blob->key_material) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
-    if (!characteristics)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    if (!characteristics) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
     if (km1_dev) {
@@ -878,14 +809,14 @@
         // software key blob.
     }
 
-    GetKeyCharacteristicsRequest request;
+    auto& impl_ = convert_device(dev)->impl_;
+    GetKeyCharacteristicsRequest request(impl_->message_version());
     request.SetKeyMaterial(*key_blob);
     AddClientAndAppData(client_id, app_data, &request);
 
-    GetKeyCharacteristicsResponse response;
-    convert_device(dev)->impl_->GetKeyCharacteristics(request, &response);
-    if (response.error != KM_ERROR_OK)
-        return response.error;
+    GetKeyCharacteristicsResponse response(impl_->message_version());
+    impl_->GetKeyCharacteristics(request, &response);
+    if (response.error != KM_ERROR_OK) return response.error;
 
     // This is a keymaster1 method, and keymaster1 doesn't include version info, so remove it.
     response.enforced.erase(response.enforced.find(TAG_OS_VERSION));
@@ -894,8 +825,7 @@
     response.unenforced.erase(response.unenforced.find(TAG_OS_PATCHLEVEL));
 
     *characteristics = BuildCharacteristics(response.enforced, response.unenforced);
-    if (!*characteristics)
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!*characteristics) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
     return KM_ERROR_OK;
 }
@@ -905,25 +835,22 @@
     const keymaster2_device_t* dev, const keymaster_key_blob_t* key_blob,
     const keymaster_blob_t* client_id, const keymaster_blob_t* app_data,
     keymaster_key_characteristics_t* characteristics) {
-    if (!dev)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
-    if (!convert_device(dev)->configured())
-        return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+    if (!convert_device(dev)->configured()) return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
 
-    if (!characteristics)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    if (!characteristics) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     SoftKeymasterDevice* sk_dev = convert_device(dev);
 
-    GetKeyCharacteristicsRequest request;
+    auto& impl_ = sk_dev->impl_;
+    GetKeyCharacteristicsRequest request(impl_->message_version());
     request.SetKeyMaterial(*key_blob);
     AddClientAndAppData(client_id, app_data, &request);
 
-    GetKeyCharacteristicsResponse response;
-    sk_dev->impl_->GetKeyCharacteristics(request, &response);
-    if (response.error != KM_ERROR_OK)
-        return response.error;
+    GetKeyCharacteristicsResponse response(impl_->message_version());
+    impl_->GetKeyCharacteristics(request, &response);
+    if (response.error != KM_ERROR_OK) return response.error;
 
     response.enforced.CopyToParamSet(&characteristics->hw_enforced);
     response.unenforced.CopyToParamSet(&characteristics->sw_enforced);
@@ -936,15 +863,14 @@
     const keymaster1_device_t* dev, const keymaster_key_param_set_t* params,
     keymaster_key_format_t key_format, const keymaster_blob_t* key_data,
     keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t** characteristics) {
-    if (!params || !key_data)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!params || !key_data) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
-    if (!key_blob)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    if (!key_blob) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     SoftKeymasterDevice* sk_dev = convert_device(dev);
 
-    ImportKeyRequest request;
+    auto& impl_ = sk_dev->impl_;
+    ImportKeyRequest request(impl_->message_version());
     request.key_description.Reinitialize(*params);
 
     keymaster1_device_t* km1_dev = sk_dev->wrapped_km1_device_;
@@ -952,28 +878,24 @@
         return km1_dev->import_key(km1_dev, params, key_format, key_data, key_blob,
                                    characteristics);
 
-    if (characteristics)
-        *characteristics = nullptr;
+    if (characteristics) *characteristics = nullptr;
 
     request.key_format = key_format;
-    request.SetKeyMaterial(key_data->data, key_data->data_length);
+    request.key_data = KeymasterKeyBlob(key_data->data, key_data->data_length);
 
-    ImportKeyResponse response;
-    convert_device(dev)->impl_->ImportKey(request, &response);
-    if (response.error != KM_ERROR_OK)
-        return response.error;
+    ImportKeyResponse response(impl_->message_version());
+    impl_->ImportKey(request, &response);
+    if (response.error != KM_ERROR_OK) return response.error;
 
     key_blob->key_material_size = response.key_blob.key_material_size;
     key_blob->key_material = reinterpret_cast<uint8_t*>(malloc(key_blob->key_material_size));
-    if (!key_blob->key_material)
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!key_blob->key_material) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
     memcpy(const_cast<uint8_t*>(key_blob->key_material), response.key_blob.key_material,
            response.key_blob.key_material_size);
 
     if (characteristics) {
         *characteristics = BuildCharacteristics(response.enforced, response.unenforced);
-        if (!*characteristics)
-            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        if (!*characteristics) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
     }
     return KM_ERROR_OK;
 }
@@ -983,11 +905,9 @@
     const keymaster2_device_t* dev, const keymaster_key_param_set_t* params,
     keymaster_key_format_t key_format, const keymaster_blob_t* key_data,
     keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t* characteristics) {
-    if (!dev)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
-    if (!convert_device(dev)->configured())
-        return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+    if (!convert_device(dev)->configured()) return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
 
     SoftKeymasterDevice* sk_dev = convert_device(dev);
 
@@ -1014,11 +934,9 @@
                                                   const keymaster_blob_t* client_id,
                                                   const keymaster_blob_t* app_data,
                                                   keymaster_blob_t* export_data) {
-    if (!key_to_export || !key_to_export->key_material)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!key_to_export || !key_to_export->key_material) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
-    if (!export_data)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    if (!export_data) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
     if (km1_dev)
@@ -1028,20 +946,19 @@
     export_data->data = nullptr;
     export_data->data_length = 0;
 
-    ExportKeyRequest request;
+    auto& impl_ = convert_device(dev)->impl_;
+    ExportKeyRequest request(impl_->message_version());
     request.key_format = export_format;
     request.SetKeyMaterial(*key_to_export);
     AddClientAndAppData(client_id, app_data, &request);
 
-    ExportKeyResponse response;
-    convert_device(dev)->impl_->ExportKey(request, &response);
-    if (response.error != KM_ERROR_OK)
-        return response.error;
+    ExportKeyResponse response(impl_->message_version());
+    impl_->ExportKey(request, &response);
+    if (response.error != KM_ERROR_OK) return response.error;
 
     export_data->data_length = response.key_data_length;
     uint8_t* tmp = reinterpret_cast<uint8_t*>(malloc(export_data->data_length));
-    if (!tmp)
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!tmp) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
     memcpy(tmp, response.key_data, export_data->data_length);
     export_data->data = tmp;
     return KM_ERROR_OK;
@@ -1054,11 +971,9 @@
                                                   const keymaster_blob_t* client_id,
                                                   const keymaster_blob_t* app_data,
                                                   keymaster_blob_t* export_data) {
-    if (!dev)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
-    if (!convert_device(dev)->configured())
-        return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+    if (!convert_device(dev)->configured()) return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
 
     SoftKeymasterDevice* sk_dev = convert_device(dev);
     return export_key(&sk_dev->km1_device_, export_format, key_to_export, client_id, app_data,
@@ -1073,12 +988,12 @@
     if (!dev || !key_to_attest || !attest_params || !cert_chain)
         return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
-    if (!convert_device(dev)->configured())
-        return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+    if (!convert_device(dev)->configured()) return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
 
     *cert_chain = {};
 
-    AttestKeyRequest request;
+    auto& impl_ = convert_device(dev)->impl_;
+    AttestKeyRequest request(impl_->message_version());
     request.SetKeyMaterial(*key_to_attest);
     request.attest_params.Reinitialize(*attest_params);
 
@@ -1090,17 +1005,15 @@
         return KM_ERROR_INVALID_INPUT_LENGTH;
     }
 
-    AttestKeyResponse response;
-    convert_device(dev)->impl_->AttestKey(request, &response);
-    if (response.error != KM_ERROR_OK)
-        return response.error;
+    AttestKeyResponse response(impl_->message_version());
+    impl_->AttestKey(request, &response);
+    if (response.error != KM_ERROR_OK) return response.error;
 
     // Allocate and clear storage for cert_chain.
     keymaster_cert_chain_t& rsp_chain = response.certificate_chain;
     cert_chain->entries = reinterpret_cast<keymaster_blob_t*>(
         malloc(rsp_chain.entry_count * sizeof(*cert_chain->entries)));
-    if (!cert_chain->entries)
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!cert_chain->entries) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
     cert_chain->entry_count = rsp_chain.entry_count;
     for (keymaster_blob_t& entry : array_range(cert_chain->entries, cert_chain->entry_count))
         entry = {};
@@ -1126,28 +1039,24 @@
                                                    const keymaster_key_blob_t* key_to_upgrade,
                                                    const keymaster_key_param_set_t* upgrade_params,
                                                    keymaster_key_blob_t* upgraded_key) {
-    if (!dev || !key_to_upgrade || !upgrade_params)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!dev || !key_to_upgrade || !upgrade_params) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
-    if (!upgraded_key)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    if (!upgraded_key) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
-    if (!convert_device(dev)->configured())
-        return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+    if (!convert_device(dev)->configured()) return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
 
-    UpgradeKeyRequest request;
+    auto& impl_ = convert_device(dev)->impl_;
+    UpgradeKeyRequest request(impl_->message_version());
     request.SetKeyMaterial(*key_to_upgrade);
     request.upgrade_params.Reinitialize(*upgrade_params);
 
-    UpgradeKeyResponse response;
-    convert_device(dev)->impl_->UpgradeKey(request, &response);
-    if (response.error != KM_ERROR_OK)
-        return response.error;
+    UpgradeKeyResponse response(impl_->message_version());
+    impl_->UpgradeKey(request, &response);
+    if (response.error != KM_ERROR_OK) return response.error;
 
     upgraded_key->key_material_size = response.upgraded_key.key_material_size;
     uint8_t* tmp = reinterpret_cast<uint8_t*>(malloc(upgraded_key->key_material_size));
-    if (!tmp)
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!tmp) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
     memcpy(tmp, response.upgraded_key.key_material, response.upgraded_key.key_material_size);
     upgraded_key->key_material = tmp;
 
@@ -1157,8 +1066,7 @@
 /* static */
 keymaster_error_t SoftKeymasterDevice::delete_key(const keymaster1_device_t* dev,
                                                   const keymaster_key_blob_t* key) {
-    if (!dev || !key || !key->key_material)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!dev || !key || !key->key_material) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
     KeymasterKeyBlob blob(*key);
     return convert_device(dev)->context_->DeleteKey(blob);
@@ -1167,11 +1075,9 @@
 /* static */
 keymaster_error_t SoftKeymasterDevice::delete_key(const keymaster2_device_t* dev,
                                                   const keymaster_key_blob_t* key) {
-    if (!dev || !key || !key->key_material)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!dev || !key || !key->key_material) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
-    if (!convert_device(dev)->configured())
-        return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+    if (!convert_device(dev)->configured()) return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
 
     KeymasterKeyBlob blob(*key);
     return convert_device(dev)->context_->DeleteKey(blob);
@@ -1179,19 +1085,16 @@
 
 /* static */
 keymaster_error_t SoftKeymasterDevice::delete_all_keys(const keymaster1_device_t* dev) {
-    if (!dev)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
     return convert_device(dev)->context_->DeleteAllKeys();
 }
 
 /* static */
 keymaster_error_t SoftKeymasterDevice::delete_all_keys(const keymaster2_device_t* dev) {
-    if (!dev)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
-    if (!convert_device(dev)->configured())
-        return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+    if (!convert_device(dev)->configured()) return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
 
     return convert_device(dev)->context_->DeleteAllKeys();
 }
@@ -1203,11 +1106,9 @@
                                              const keymaster_key_param_set_t* in_params,
                                              keymaster_key_param_set_t* out_params,
                                              keymaster_operation_handle_t* operation_handle) {
-    if (!dev || !key || !key->key_material)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!dev || !key || !key->key_material) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
-    if (!operation_handle)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    if (!operation_handle) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     SoftKeymasterDevice* skdev = convert_device(dev);
     const keymaster1_device_t* km1_dev = skdev->wrapped_km1_device_;
@@ -1215,7 +1116,7 @@
     if (km1_dev) {
         AuthorizationSet in_params_set(*in_params);
 
-        UniquePtr<Key> akmKey; // android keymaster key
+        UniquePtr<Key> akmKey;  // android keymaster key
         skdev->context_->ParseKeyBlob(KeymasterKeyBlob(*key), in_params_set, &akmKey);
 
         keymaster_algorithm_t algorithm = KM_ALGORITHM_AES;
@@ -1248,15 +1149,15 @@
         out_params->length = 0;
     }
 
-    BeginOperationRequest request;
+    auto& impl_ = skdev->impl_;
+    BeginOperationRequest request(impl_->message_version());
     request.purpose = purpose;
     request.SetKeyMaterial(*key);
     request.additional_params.Reinitialize(*in_params);
 
-    BeginOperationResponse response;
-    skdev->impl_->BeginOperation(request, &response);
-    if (response.error != KM_ERROR_OK)
-        return response.error;
+    BeginOperationResponse response(impl_->message_version());
+    impl_->BeginOperation(request, &response);
+    if (response.error != KM_ERROR_OK) return response.error;
 
     if (response.output_params.size() > 0) {
         if (out_params)
@@ -1276,11 +1177,9 @@
                                              const keymaster_key_param_set_t* in_params,
                                              keymaster_key_param_set_t* out_params,
                                              keymaster_operation_handle_t* operation_handle) {
-    if (!dev)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
-    if (!convert_device(dev)->configured())
-        return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+    if (!convert_device(dev)->configured()) return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
 
     SoftKeymasterDevice* sk_dev = convert_device(dev);
     return begin(&sk_dev->km1_device_, purpose, key, in_params, out_params, operation_handle);
@@ -1293,11 +1192,9 @@
                                               const keymaster_blob_t* input, size_t* input_consumed,
                                               keymaster_key_param_set_t* out_params,
                                               keymaster_blob_t* output) {
-    if (!input)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!input) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
-    if (!input_consumed)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    if (!input_consumed) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
     if (km1_dev && !convert_device(dev)->impl_->has_operation(operation_handle)) {
@@ -1317,17 +1214,15 @@
         output->data_length = 0;
     }
 
-    UpdateOperationRequest request;
+    auto& impl_ = convert_device(dev)->impl_;
+    UpdateOperationRequest request(impl_->message_version());
     request.op_handle = operation_handle;
-    if (input)
-        request.input.Reinitialize(input->data, input->data_length);
-    if (in_params)
-        request.additional_params.Reinitialize(*in_params);
+    if (input) request.input.Reinitialize(input->data, input->data_length);
+    if (in_params) request.additional_params.Reinitialize(*in_params);
 
-    UpdateOperationResponse response;
-    convert_device(dev)->impl_->UpdateOperation(request, &response);
-    if (response.error != KM_ERROR_OK)
-        return response.error;
+    UpdateOperationResponse response(impl_->message_version());
+    impl_->UpdateOperation(request, &response);
+    if (response.error != KM_ERROR_OK) return response.error;
 
     if (response.output_params.size() > 0) {
         if (out_params)
@@ -1340,8 +1235,7 @@
     if (output) {
         output->data_length = response.output.available_read();
         uint8_t* tmp = reinterpret_cast<uint8_t*>(malloc(output->data_length));
-        if (!tmp)
-            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        if (!tmp) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
         memcpy(tmp, response.output.peek_read(), output->data_length);
         output->data = tmp;
     } else if (response.output.available_read() > 0) {
@@ -1357,11 +1251,9 @@
                                               const keymaster_blob_t* input, size_t* input_consumed,
                                               keymaster_key_param_set_t* out_params,
                                               keymaster_blob_t* output) {
-    if (!dev)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
-    if (!convert_device(dev)->configured())
-        return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+    if (!convert_device(dev)->configured()) return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
 
     SoftKeymasterDevice* sk_dev = convert_device(dev);
     return update(&sk_dev->km1_device_, operation_handle, in_params, input, input_consumed,
@@ -1375,8 +1267,7 @@
                                               const keymaster_blob_t* signature,
                                               keymaster_key_param_set_t* out_params,
                                               keymaster_blob_t* output) {
-    if (!dev)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
     const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
     if (km1_dev && !convert_device(dev)->impl_->has_operation(operation_handle)) {
@@ -1396,16 +1287,16 @@
         output->data_length = 0;
     }
 
-    FinishOperationRequest request;
+    auto& impl_ = convert_device(dev)->impl_;
+    FinishOperationRequest request(impl_->message_version());
     request.op_handle = operation_handle;
     if (signature && signature->data_length > 0)
         request.signature.Reinitialize(signature->data, signature->data_length);
     request.additional_params.Reinitialize(*params);
 
-    FinishOperationResponse response;
-    convert_device(dev)->impl_->FinishOperation(request, &response);
-    if (response.error != KM_ERROR_OK)
-        return response.error;
+    FinishOperationResponse response(impl_->message_version());
+    impl_->FinishOperation(request, &response);
+    if (response.error != KM_ERROR_OK) return response.error;
 
     if (response.output_params.size() > 0) {
         if (out_params)
@@ -1416,8 +1307,7 @@
     if (output) {
         output->data_length = response.output.available_read();
         uint8_t* tmp = reinterpret_cast<uint8_t*>(malloc(output->data_length));
-        if (!tmp)
-            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        if (!tmp) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
         memcpy(tmp, response.output.peek_read(), output->data_length);
         output->data = tmp;
     } else if (response.output.available_read() > 0) {
@@ -1439,17 +1329,13 @@
                                               const keymaster_blob_t* signature,
                                               keymaster_key_param_set_t* out_params,
                                               keymaster_blob_t* output) {
-    if (!dev)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
-    if (!convert_device(dev)->configured())
-        return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+    if (!convert_device(dev)->configured()) return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
 
-    if (out_params)
-        *out_params = {};
+    if (out_params) *out_params = {};
 
-    if (output)
-        *output = {};
+    if (output) *output = {};
 
     const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
     if (km1_dev && !convert_device(dev)->impl_->has_operation(operation_handle)) {
@@ -1538,21 +1424,17 @@
             return KM_ERROR_OUTPUT_PARAMETER_NULL;
         }
 
-        if (out_params) {
-            *out_params = finish_out_params;
-        }
+        *out_params = finish_out_params;
+        *output = finish_output;
 
-        if (output) {
-            *output = finish_output;
-        }
-
-        finish_out_params_deleter.release();
-        finish_output_deleter.release();
+        finish_out_params_deleter.release();  // NOLINT(bugprone-unused-return-value)
+        finish_output_deleter.release();      // NOLINT(bugprone-unused-return-value)
 
         return KM_ERROR_OK;
     }
 
-    FinishOperationRequest request;
+    auto& impl_ = convert_device(dev)->impl_;
+    FinishOperationRequest request(impl_->message_version());
     request.op_handle = operation_handle;
     if (signature && signature->data_length > 0)
         request.signature.Reinitialize(signature->data, signature->data_length);
@@ -1560,10 +1442,9 @@
         request.input.Reinitialize(input->data, input->data_length);
     request.additional_params.Reinitialize(*params);
 
-    FinishOperationResponse response;
-    convert_device(dev)->impl_->FinishOperation(request, &response);
-    if (response.error != KM_ERROR_OK)
-        return response.error;
+    FinishOperationResponse response(impl_->message_version());
+    impl_->FinishOperation(request, &response);
+    if (response.error != KM_ERROR_OK) return response.error;
 
     if (response.output_params.size() > 0) {
         if (out_params)
@@ -1574,8 +1455,7 @@
     if (output) {
         output->data_length = response.output.available_read();
         uint8_t* tmp = reinterpret_cast<uint8_t*>(malloc(output->data_length));
-        if (!tmp)
-            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        if (!tmp) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
         memcpy(tmp, response.output.peek_read(), output->data_length);
         output->data = tmp;
     } else if (response.output.available_read() > 0) {
@@ -1596,21 +1476,20 @@
         return km1_dev->abort(km1_dev, operation_handle);
     }
 
-    AbortOperationRequest request;
+    auto& impl_ = convert_device(dev)->impl_;
+    AbortOperationRequest request(impl_->message_version());
     request.op_handle = operation_handle;
-    AbortOperationResponse response;
-    convert_device(dev)->impl_->AbortOperation(request, &response);
+    AbortOperationResponse response(impl_->message_version());
+    impl_->AbortOperation(request, &response);
     return response.error;
 }
 
 /* static */
 keymaster_error_t SoftKeymasterDevice::abort(const keymaster2_device_t* dev,
                                              keymaster_operation_handle_t operation_handle) {
-    if (!dev)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
-    if (!convert_device(dev)->configured())
-        return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+    if (!convert_device(dev)->configured()) return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
 
     SoftKeymasterDevice* sk_dev = convert_device(dev);
     return abort(&sk_dev->km1_device_, operation_handle);
diff --git a/cppcose/cppcose.cpp b/cppcose/cppcose.cpp
new file mode 100644
index 0000000..bfe9928
--- /dev/null
+++ b/cppcose/cppcose.cpp
@@ -0,0 +1,463 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <keymaster/cppcose/cppcose.h>
+
+#include <iostream>
+#include <stdio.h>
+
+#include <cppbor.h>
+#include <cppbor_parse.h>
+
+#include <openssl/err.h>
+
+namespace cppcose {
+
+namespace {
+
+ErrMsgOr<bssl::UniquePtr<EVP_CIPHER_CTX>> aesGcmInitAndProcessAad(const bytevec& key,
+                                                                  const bytevec& nonce,
+                                                                  const bytevec& aad,
+                                                                  bool encrypt) {
+    if (key.size() != kAesGcmKeySize) return "Invalid key size";
+
+    bssl::UniquePtr<EVP_CIPHER_CTX> ctx(EVP_CIPHER_CTX_new());
+    if (!ctx) return "Failed to allocate cipher context";
+
+    if (!EVP_CipherInit_ex(ctx.get(), EVP_aes_256_gcm(), nullptr /* engine */, key.data(),
+                           nonce.data(), encrypt ? 1 : 0)) {
+        return "Failed to initialize cipher";
+    }
+
+    int outlen;
+    if (!aad.empty() && !EVP_CipherUpdate(ctx.get(), nullptr /* out; null means AAD */, &outlen,
+                                          aad.data(), aad.size())) {
+        return "Failed to process AAD";
+    }
+
+    return std::move(ctx);
+}
+
+}  // namespace
+
+ErrMsgOr<HmacSha256> generateHmacSha256(const bytevec& key, const bytevec& data) {
+    HmacSha256 digest;
+    unsigned int outLen;
+    uint8_t* out = HMAC(EVP_sha256(),              //
+                        key.data(), key.size(),    //
+                        data.data(), data.size(),  //
+                        digest.data(), &outLen);
+
+    if (out == nullptr || outLen != digest.size()) {
+        return "Error generating HMAC";
+    }
+    return digest;
+}
+
+ErrMsgOr<HmacSha256> generateCoseMac0Mac(HmacSha256Function macFunction, const bytevec& externalAad,
+                                         const bytevec& payload) {
+    auto macStructure = cppbor::Array()
+                            .add("MAC0")
+                            .add(cppbor::Map().add(ALGORITHM, HMAC_256).canonicalize().encode())
+                            .add(externalAad)
+                            .add(payload)
+                            .encode();
+
+    auto macTag = macFunction(macStructure);
+    if (!macTag) {
+        return "Error computing public key MAC";
+    }
+
+    return *macTag;
+}
+
+ErrMsgOr<cppbor::Array> constructCoseMac0(HmacSha256Function macFunction,
+                                          const bytevec& externalAad, const bytevec& payload) {
+    auto tag = generateCoseMac0Mac(macFunction, externalAad, payload);
+    if (!tag) return tag.moveMessage();
+
+    return cppbor::Array()
+        .add(cppbor::Map().add(ALGORITHM, HMAC_256).canonicalize().encode())
+        .add(cppbor::Map() /* unprotected */)
+        .add(payload)
+        .add(std::pair(tag->begin(), tag->end()));
+}
+
+ErrMsgOr<bytevec /* payload */> verifyAndParseCoseMac0(const cppbor::Item* macItem,
+                                                       const bytevec& macKey) {
+    auto mac = macItem ? macItem->asArray() : nullptr;
+    if (!mac || mac->size() != kCoseMac0EntryCount) {
+        return "Invalid COSE_Mac0";
+    }
+
+    auto protectedParms = mac->get(kCoseMac0ProtectedParams)->asBstr();
+    auto unprotectedParms = mac->get(kCoseMac0UnprotectedParams)->asMap();
+    auto payload = mac->get(kCoseMac0Payload)->asBstr();
+    auto tag = mac->get(kCoseMac0Tag)->asBstr();
+    if (!protectedParms || !unprotectedParms || !payload || !tag) {
+        return "Invalid COSE_Mac0 contents";
+    }
+
+    auto [protectedMap, _, errMsg] = cppbor::parse(protectedParms);
+    if (!protectedMap || !protectedMap->asMap()) {
+        return "Invalid Mac0 protected: " + errMsg;
+    }
+    auto& algo = protectedMap->asMap()->get(ALGORITHM);
+    if (!algo || !algo->asInt() || algo->asInt()->value() != HMAC_256) {
+        return "Unsupported Mac0 algorithm";
+    }
+
+    auto macFunction = [&macKey](const bytevec& input) {
+        return generateHmacSha256(macKey, input);
+    };
+    auto macTag = generateCoseMac0Mac(macFunction, {} /* external_aad */, payload->value());
+    if (!macTag) return macTag.moveMessage();
+
+    if (macTag->size() != tag->value().size() ||
+        CRYPTO_memcmp(macTag->data(), tag->value().data(), macTag->size()) != 0) {
+        return "MAC tag mismatch";
+    }
+
+    return payload->value();
+}
+
+ErrMsgOr<bytevec> createCoseSign1Signature(const bytevec& key, const bytevec& protectedParams,
+                                           const bytevec& payload, const bytevec& aad) {
+    bytevec signatureInput = cppbor::Array()
+                                 .add("Signature1")  //
+                                 .add(protectedParams)
+                                 .add(aad)
+                                 .add(payload)
+                                 .encode();
+
+    if (key.size() != ED25519_PRIVATE_KEY_LEN) return "Invalid signing key";
+    bytevec signature(ED25519_SIGNATURE_LEN);
+    if (!ED25519_sign(signature.data(), signatureInput.data(), signatureInput.size(), key.data())) {
+        return "Signing failed";
+    }
+
+    return signature;
+}
+
+ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, cppbor::Map protectedParams,
+                                           const bytevec& payload, const bytevec& aad) {
+    bytevec protParms = protectedParams.add(ALGORITHM, EDDSA).canonicalize().encode();
+    auto signature = createCoseSign1Signature(key, protParms, payload, aad);
+    if (!signature) return signature.moveMessage();
+
+    return cppbor::Array()
+        .add(std::move(protParms))
+        .add(cppbor::Map() /* unprotected parameters */)
+        .add(std::move(payload))
+        .add(std::move(*signature));
+}
+
+ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, const bytevec& payload,
+                                           const bytevec& aad) {
+    return constructCoseSign1(key, {} /* protectedParams */, payload, aad);
+}
+
+ErrMsgOr<bytevec> verifyAndParseCoseSign1(const cppbor::Array* coseSign1,
+                                          const bytevec& signingCoseKey, const bytevec& aad) {
+    if (!coseSign1 || coseSign1->size() != kCoseSign1EntryCount) {
+        return "Invalid COSE_Sign1";
+    }
+
+    const cppbor::Bstr* protectedParams = coseSign1->get(kCoseSign1ProtectedParams)->asBstr();
+    const cppbor::Map* unprotectedParams = coseSign1->get(kCoseSign1UnprotectedParams)->asMap();
+    const cppbor::Bstr* payload = coseSign1->get(kCoseSign1Payload)->asBstr();
+
+    if (!protectedParams || !unprotectedParams || !payload) {
+        return "Missing input parameters";
+    }
+
+    auto [parsedProtParams, _, errMsg] = cppbor::parse(protectedParams);
+    if (!parsedProtParams) {
+        return errMsg + " when parsing protected params.";
+    }
+    if (!parsedProtParams->asMap()) {
+        return "Protected params must be a map";
+    }
+
+    auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM);
+    if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != EDDSA) {
+        return "Unsupported signature algorithm";
+    }
+
+    const cppbor::Bstr* signature = coseSign1->get(kCoseSign1Signature)->asBstr();
+    if (!signature || signature->value().empty()) {
+        return "Missing signature input";
+    }
+
+    bool selfSigned = signingCoseKey.empty();
+    auto key = CoseKey::parseEd25519(selfSigned ? payload->value() : signingCoseKey);
+    if (!key || key->getBstrValue(CoseKey::PUBKEY_X)->empty()) {
+        return "Bad signing key: " + key.moveMessage();
+    }
+
+    bytevec signatureInput =
+        cppbor::Array().add("Signature1").add(*protectedParams).add(aad).add(*payload).encode();
+
+    if (!ED25519_verify(signatureInput.data(), signatureInput.size(), signature->value().data(),
+                        key->getBstrValue(CoseKey::PUBKEY_X)->data())) {
+        return "Signature verification failed";
+    }
+
+    return payload->value();
+}
+
+ErrMsgOr<bytevec> createCoseEncryptCiphertext(const bytevec& key, const bytevec& nonce,
+                                              const bytevec& protectedParams,
+                                              const bytevec& plaintextPayload, const bytevec& aad) {
+    auto ciphertext = aesGcmEncrypt(key, nonce,
+                                    cppbor::Array()            // Enc strucure as AAD
+                                        .add("Encrypt")        // Context
+                                        .add(protectedParams)  // Protected
+                                        .add(aad)              // External AAD
+                                        .encode(),
+                                    plaintextPayload);
+
+    if (!ciphertext) return ciphertext.moveMessage();
+    return ciphertext.moveValue();
+}
+
+ErrMsgOr<cppbor::Array> constructCoseEncrypt(const bytevec& key, const bytevec& nonce,
+                                             const bytevec& plaintextPayload, const bytevec& aad,
+                                             cppbor::Array recipients) {
+    auto encryptProtectedHeader = cppbor::Map()  //
+                                      .add(ALGORITHM, AES_GCM_256)
+                                      .canonicalize()
+                                      .encode();
+
+    auto ciphertext =
+        createCoseEncryptCiphertext(key, nonce, encryptProtectedHeader, plaintextPayload, aad);
+    if (!ciphertext) return ciphertext.moveMessage();
+
+    return cppbor::Array()
+        .add(encryptProtectedHeader)                       // Protected
+        .add(cppbor::Map().add(IV, nonce).canonicalize())  // Unprotected
+        .add(*ciphertext)                                  // Payload
+        .add(std::move(recipients));
+}
+
+ErrMsgOr<std::pair<bytevec /* pubkey */, bytevec /* key ID */>>
+getSenderPubKeyFromCoseEncrypt(const cppbor::Item* coseEncrypt) {
+    if (!coseEncrypt || !coseEncrypt->asArray() ||
+        coseEncrypt->asArray()->size() != kCoseEncryptEntryCount) {
+        return "Invalid COSE_Encrypt";
+    }
+
+    auto& recipients = coseEncrypt->asArray()->get(kCoseEncryptRecipients);
+    if (!recipients || !recipients->asArray() || recipients->asArray()->size() != 1) {
+        return "Invalid recipients list";
+    }
+
+    auto& recipient = recipients->asArray()->get(0);
+    if (!recipient || !recipient->asArray() || recipient->asArray()->size() != 3) {
+        return "Invalid COSE_recipient";
+    }
+
+    auto& ciphertext = recipient->asArray()->get(2);
+    if (!ciphertext->asSimple() || !ciphertext->asSimple()->asNull()) {
+        return "Unexpected value in recipients ciphertext field " +
+               cppbor::prettyPrint(ciphertext.get());
+    }
+
+    auto& protParms = recipient->asArray()->get(0);
+    if (!protParms || !protParms->asBstr()) return "Invalid protected params";
+    auto [parsedProtParms, _, errMsg] = cppbor::parse(protParms->asBstr());
+    if (!parsedProtParms) return "Failed to parse protected params: " + errMsg;
+    if (!parsedProtParms->asMap()) return "Invalid protected params";
+
+    auto& algorithm = parsedProtParms->asMap()->get(ALGORITHM);
+    if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != ECDH_ES_HKDF_256) {
+        return "Invalid algorithm";
+    }
+
+    auto& unprotParms = recipient->asArray()->get(1);
+    if (!unprotParms || !unprotParms->asMap()) return "Invalid unprotected params";
+
+    auto& senderCoseKey = unprotParms->asMap()->get(COSE_KEY);
+    if (!senderCoseKey || !senderCoseKey->asMap()) return "Invalid sender COSE_Key";
+
+    auto& keyType = senderCoseKey->asMap()->get(CoseKey::KEY_TYPE);
+    if (!keyType || !keyType->asInt() || keyType->asInt()->value() != OCTET_KEY_PAIR) {
+        return "Invalid key type";
+    }
+
+    auto& curve = senderCoseKey->asMap()->get(CoseKey::CURVE);
+    if (!curve || !curve->asInt() || curve->asInt()->value() != X25519) {
+        return "Unsupported curve";
+    }
+
+    auto& pubkey = senderCoseKey->asMap()->get(CoseKey::PUBKEY_X);
+    if (!pubkey || !pubkey->asBstr() ||
+        pubkey->asBstr()->value().size() != X25519_PUBLIC_VALUE_LEN) {
+        return "Invalid X25519 public key";
+    }
+
+    auto& key_id = unprotParms->asMap()->get(KEY_ID);
+    if (key_id && key_id->asBstr()) {
+        return std::make_pair(pubkey->asBstr()->value(), key_id->asBstr()->value());
+    }
+
+    // If no key ID, just return an empty vector.
+    return std::make_pair(pubkey->asBstr()->value(), bytevec{});
+}
+
+ErrMsgOr<bytevec> decryptCoseEncrypt(const bytevec& key, const cppbor::Item* coseEncrypt,
+                                     const bytevec& external_aad) {
+    if (!coseEncrypt || !coseEncrypt->asArray() ||
+        coseEncrypt->asArray()->size() != kCoseEncryptEntryCount) {
+        return "Invalid COSE_Encrypt";
+    }
+
+    auto& protParms = coseEncrypt->asArray()->get(kCoseEncryptProtectedParams);
+    auto& unprotParms = coseEncrypt->asArray()->get(kCoseEncryptUnprotectedParams);
+    auto& ciphertext = coseEncrypt->asArray()->get(kCoseEncryptPayload);
+    auto& recipients = coseEncrypt->asArray()->get(kCoseEncryptRecipients);
+
+    if (!protParms || !protParms->asBstr() || !unprotParms || !ciphertext || !recipients) {
+        return "Invalid COSE_Encrypt";
+    }
+
+    auto [parsedProtParams, _, errMsg] = cppbor::parse(protParms->asBstr()->value());
+    if (!parsedProtParams) {
+        return errMsg + " when parsing protected params.";
+    }
+    if (!parsedProtParams->asMap()) {
+        return "Protected params must be a map";
+    }
+
+    auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM);
+    if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != AES_GCM_256) {
+        return "Unsupported encryption algorithm";
+    }
+
+    if (!unprotParms->asMap() || unprotParms->asMap()->size() != 1) {
+        return "Invalid unprotected params";
+    }
+
+    auto& nonce = unprotParms->asMap()->get(IV);
+    if (!nonce || !nonce->asBstr() || nonce->asBstr()->value().size() != kAesGcmNonceLength) {
+        return "Invalid nonce";
+    }
+
+    if (!ciphertext->asBstr()) return "Invalid ciphertext";
+
+    auto aad = cppbor::Array()                         // Enc strucure as AAD
+                   .add("Encrypt")                     // Context
+                   .add(protParms->asBstr()->value())  // Protected
+                   .add(external_aad)                  // External AAD
+                   .encode();
+
+    return aesGcmDecrypt(key, nonce->asBstr()->value(), aad, ciphertext->asBstr()->value());
+}
+
+ErrMsgOr<bytevec> x25519_HKDF_DeriveKey(const bytevec& pubKeyA, const bytevec& privKeyA,
+                                        const bytevec& pubKeyB, bool senderIsA) {
+    if (privKeyA.empty() || pubKeyA.empty() || pubKeyB.empty()) {
+        return "Missing input key parameters";
+    }
+
+    bytevec rawSharedKey(X25519_SHARED_KEY_LEN);
+    if (!::X25519(rawSharedKey.data(), privKeyA.data(), pubKeyB.data())) {
+        return "ECDH operation failed";
+    }
+
+    bytevec kdfContext = cppbor::Array()
+                             .add(AES_GCM_256)
+                             .add(cppbor::Array()  // Sender Info
+                                      .add(cppbor::Bstr("client"))
+                                      .add(bytevec{} /* nonce */)
+                                      .add(senderIsA ? pubKeyA : pubKeyB))
+                             .add(cppbor::Array()  // Recipient Info
+                                      .add(cppbor::Bstr("server"))
+                                      .add(bytevec{} /* nonce */)
+                                      .add(senderIsA ? pubKeyB : pubKeyA))
+                             .add(cppbor::Array()               // SuppPubInfo
+                                      .add(kAesGcmKeySizeBits)  // output key length
+                                      .add(bytevec{}))          // protected
+                             .encode();
+
+    bytevec retval(SHA256_DIGEST_LENGTH);
+    bytevec salt{};
+    if (!HKDF(retval.data(), retval.size(),              //
+              EVP_sha256(),                              //
+              rawSharedKey.data(), rawSharedKey.size(),  //
+              salt.data(), salt.size(),                  //
+              kdfContext.data(), kdfContext.size())) {
+        return "ECDH HKDF failed";
+    }
+
+    return retval;
+}
+
+ErrMsgOr<bytevec> aesGcmEncrypt(const bytevec& key, const bytevec& nonce, const bytevec& aad,
+                                const bytevec& plaintext) {
+    auto ctx = aesGcmInitAndProcessAad(key, nonce, aad, true /* encrypt */);
+    if (!ctx) return ctx.moveMessage();
+
+    bytevec ciphertext(plaintext.size() + kAesGcmTagSize);
+    int outlen;
+    if (!EVP_CipherUpdate(ctx->get(), ciphertext.data(), &outlen, plaintext.data(),
+                          plaintext.size())) {
+        return "Failed to encrypt plaintext";
+    }
+    assert(plaintext.size() == static_cast<uint64_t>(outlen));
+
+    if (!EVP_CipherFinal_ex(ctx->get(), ciphertext.data() + outlen, &outlen)) {
+        return "Failed to finalize encryption";
+    }
+    assert(outlen == 0);
+
+    if (!EVP_CIPHER_CTX_ctrl(ctx->get(), EVP_CTRL_GCM_GET_TAG, kAesGcmTagSize,
+                             ciphertext.data() + plaintext.size())) {
+        return "Failed to retrieve tag";
+    }
+
+    return ciphertext;
+}
+
+ErrMsgOr<bytevec> aesGcmDecrypt(const bytevec& key, const bytevec& nonce, const bytevec& aad,
+                                const bytevec& ciphertextWithTag) {
+    auto ctx = aesGcmInitAndProcessAad(key, nonce, aad, false /* encrypt */);
+    if (!ctx) return ctx.moveMessage();
+
+    if (ciphertextWithTag.size() < kAesGcmTagSize) return "Missing tag";
+
+    bytevec plaintext(ciphertextWithTag.size() - kAesGcmTagSize);
+    int outlen;
+    if (!EVP_CipherUpdate(ctx->get(), plaintext.data(), &outlen, ciphertextWithTag.data(),
+                          ciphertextWithTag.size() - kAesGcmTagSize)) {
+        return "Failed to decrypt plaintext";
+    }
+    assert(plaintext.size() == static_cast<uint64_t>(outlen));
+
+    bytevec tag(ciphertextWithTag.end() - kAesGcmTagSize, ciphertextWithTag.end());
+    if (!EVP_CIPHER_CTX_ctrl(ctx->get(), EVP_CTRL_GCM_SET_TAG, kAesGcmTagSize, tag.data())) {
+        return "Failed to set tag: " + std::to_string(ERR_peek_last_error());
+    }
+
+    if (!EVP_CipherFinal_ex(ctx->get(), nullptr, &outlen)) {
+        return "Failed to finalize encryption";
+    }
+    assert(outlen == 0);
+
+    return plaintext;
+}
+
+}  // namespace cppcose
diff --git a/ec_privkey_pk8.der b/ec_privkey_pk8.der
deleted file mode 100644
index a4af673..0000000
--- a/ec_privkey_pk8.der
+++ /dev/null
Binary files differ
diff --git a/include/keymaster/List.h b/include/keymaster/List.h
index 882c6c7..82aded4 100644
--- a/include/keymaster/List.h
+++ b/include/keymaster/List.h
@@ -24,8 +24,8 @@
 //
 // The only class you want to use from here is "List".
 //
-#ifndef _LIBS_UTILS_LIST_H
-#define _LIBS_UTILS_LIST_H
+
+#pragma once
 
 #include <stddef.h>
 #include <stdint.h>
@@ -38,15 +38,13 @@
  * Objects added to the list are copied using the assignment operator,
  * so this must be defined.
  */
-template<typename T> 
-class List 
-{
-protected:
+template <typename T> class List {
+  protected:
     /*
      * One element in the list.
      */
     class _Node {
-    public:
+      public:
         explicit _Node(const T& val) : mVal(val) {}
         ~_Node() {}
         inline T& getRef() { return mVal; }
@@ -56,53 +54,46 @@
         inline void setVal(const T& val) { mVal = val; }
         inline void setPrev(_Node* ptr) { mpPrev = ptr; }
         inline void setNext(_Node* ptr) { mpNext = ptr; }
-    private:
+
+      private:
         friend class List;
         friend class _ListIterator;
-        T           mVal;
-        _Node*      mpPrev;
-        _Node*      mpNext;
+        T mVal;
+        _Node* mpPrev;
+        _Node* mpNext;
     };
 
     /*
      * Iterator for walking through the list.
      */
-    
-    template <typename TYPE>
-    struct CONST_ITERATOR {
-        typedef _Node const * NodePtr;
+
+    template <typename TYPE> struct CONST_ITERATOR {
+        typedef _Node const* NodePtr;
         typedef const TYPE Type;
     };
-    
-    template <typename TYPE>
-    struct NON_CONST_ITERATOR {
+
+    template <typename TYPE> struct NON_CONST_ITERATOR {
         typedef _Node* NodePtr;
         typedef TYPE Type;
     };
-    
-    template<
-        typename U,
-        template <class> class Constness
-    > 
-    class _ListIterator {
-        typedef _ListIterator<U, Constness>     _Iter;
-        typedef typename Constness<U>::NodePtr  _NodePtr;
-        typedef typename Constness<U>::Type     _Type;
+
+    template <typename U, template <class> class Constness> class _ListIterator {
+        typedef _ListIterator<U, Constness> _Iter;
+        typedef typename Constness<U>::NodePtr _NodePtr;
+        typedef typename Constness<U>::Type _Type;
 
         explicit _ListIterator(_NodePtr ptr) : mpNode(ptr) {}
 
-    public:
+      public:
         _ListIterator() {}
         _ListIterator(const _Iter& rhs) : mpNode(rhs.mpNode) {}
         ~_ListIterator() {}
-        
+
         // this will handle conversions from iterator to const_iterator
         // (and also all convertible iterators)
         // Here, in this implementation, the iterators can be converted
         // if the nodes can be converted
-        template<typename V> explicit 
-        _ListIterator(const V& rhs) : mpNode(rhs.mpNode) {}
-        
+        template <typename V> explicit _ListIterator(const V& rhs) : mpNode(rhs.mpNode) {}
 
         /*
          * Dereference operator.  Used to get at the juicy insides.
@@ -113,40 +104,38 @@
         /*
          * Iterator comparison.
          */
-        inline bool operator==(const _Iter& right) const { 
-            return mpNode == right.mpNode; }
-        
-        inline bool operator!=(const _Iter& right) const { 
-            return mpNode != right.mpNode; }
+        inline bool operator==(const _Iter& right) const { return mpNode == right.mpNode; }
+
+        inline bool operator!=(const _Iter& right) const { return mpNode != right.mpNode; }
 
         /*
          * handle comparisons between iterator and const_iterator
          */
-        template<typename OTHER>
-        inline bool operator==(const OTHER& right) const { 
-            return mpNode == right.mpNode; }
-        
-        template<typename OTHER>
-        inline bool operator!=(const OTHER& right) const { 
-            return mpNode != right.mpNode; }
+        template <typename OTHER> inline bool operator==(const OTHER& right) const {
+            return mpNode == right.mpNode;
+        }
+
+        template <typename OTHER> inline bool operator!=(const OTHER& right) const {
+            return mpNode != right.mpNode;
+        }
 
         /*
          * Incr/decr, used to move through the list.
          */
-        inline _Iter& operator++() {     // pre-increment
+        inline _Iter& operator++() {  // pre-increment
             mpNode = mpNode->getNext();
             return *this;
         }
-        const _Iter operator++(int) {    // post-increment
+        const _Iter operator++(int) {  // post-increment
             _Iter tmp(*this);
             mpNode = mpNode->getNext();
             return tmp;
         }
-        inline _Iter& operator--() {     // pre-increment
+        inline _Iter& operator--() {  // pre-increment
             mpNode = mpNode->getPrev();
             return *this;
         }
-        const _Iter operator--(int) {   // post-increment
+        const _Iter operator--(int) {  // post-increment
             _Iter tmp(*this);
             mpNode = mpNode->getPrev();
             return tmp;
@@ -154,22 +143,20 @@
 
         inline _NodePtr getNode() const { return mpNode; }
 
-        _NodePtr mpNode;    /* should be private, but older gcc fails */
-    private:
+        _NodePtr mpNode; /* should be private, but older gcc fails */
+      private:
         friend class List;
     };
 
-public:
-    List() {
-        prep();
-    }
-    List(const List<T>& src) {      // copy-constructor
+  public:
+    List() { prep(); }
+    List(const List<T>& src) {  // copy-constructor
         prep();
         insert(begin(), src.begin(), src.end());
     }
     virtual ~List() {
         clear();
-        delete[] (unsigned char*) mpMiddle;
+        delete[](unsigned char*) mpMiddle;
     }
 
     typedef _ListIterator<T, NON_CONST_ITERATOR> iterator;
@@ -181,36 +168,27 @@
     inline bool empty() const { return mpMiddle->getNext() == mpMiddle; }
 
     /* return #of elements in list */
-    size_t size() const {
-        return size_t(distance(begin(), end()));
-    }
+    size_t size() const { return size_t(distance(begin(), end())); }
 
     /*
      * Return the first element or one past the last element.  The
      * _Node* we're returning is converted to an "iterator" by a
      * constructor in _ListIterator.
      */
-    inline iterator begin() { 
-        return iterator(mpMiddle->getNext()); 
+    inline iterator begin() { return iterator(mpMiddle->getNext()); }
+    inline const_iterator begin() const {
+        return const_iterator(const_cast<_Node const*>(mpMiddle->getNext()));
     }
-    inline const_iterator begin() const { 
-        return const_iterator(const_cast<_Node const*>(mpMiddle->getNext())); 
-    }
-    inline iterator end() { 
-        return iterator(mpMiddle); 
-    }
-    inline const_iterator end() const { 
-        return const_iterator(const_cast<_Node const*>(mpMiddle)); 
-    }
+    inline iterator end() { return iterator(mpMiddle); }
+    inline const_iterator end() const { return const_iterator(const_cast<_Node const*>(mpMiddle)); }
 
     /* add the object to the head or tail of the list */
     void push_front(const T& val) { insert(begin(), val); }
     void push_back(const T& val) { insert(end(), val); }
 
     /* insert before the current node; returns iterator at new node */
-    iterator insert(iterator posn, const T& val) 
-    {
-        _Node* newNode = new(std::nothrow) _Node(val);        // alloc & copy-construct
+    iterator insert(iterator posn, const T& val) {
+        _Node* newNode = new (std::nothrow) _Node(val);  // alloc & copy-construct
         newNode->setNext(posn.getNode());
         newNode->setPrev(posn.getNode()->getPrev());
         posn.getNode()->getPrev()->setNext(newNode);
@@ -220,7 +198,7 @@
 
     /* insert a range of elements before the current node */
     void insert(iterator posn, const_iterator first, const_iterator last) {
-        for ( ; first != last; ++first)
+        for (; first != last; ++first)
             insert(posn, *first);
     }
 
@@ -237,7 +215,7 @@
     /* remove a range of elements */
     iterator erase(iterator first, iterator last) {
         while (first != last)
-            erase(first++);     // don't erase than incr later!
+            erase(first++);  // don't erase than incr later!
         return iterator(last);
     }
 
@@ -260,19 +238,13 @@
      * will be equal to "last".  The iterators must refer to the same
      * list.
      *
-     * FIXME: This is actually a generic iterator function. It should be a 
+     * FIXME: This is actually a generic iterator function. It should be a
      * template function at the top-level with specializations for things like
      * vector<>, which can just do pointer math). Here we limit it to
      * _ListIterator of the same type but different constness.
      */
-    template<
-        typename U,
-        template <class> class CL,
-        template <class> class CR
-    > 
-    ptrdiff_t distance(
-            _ListIterator<U, CL> first, _ListIterator<U, CR> last) const 
-    {
+    template <typename U, template <class> class CL, template <class> class CR>
+    ptrdiff_t distance(_ListIterator<U, CL> first, _ListIterator<U, CR> last) const {
         ptrdiff_t count = 0;
         while (first != last) {
             ++first;
@@ -281,7 +253,7 @@
         return count;
     }
 
-private:
+  private:
     /*
      * I want a _Node but don't need it to hold valid data.  More
      * to the point, I don't want T's constructor to fire, since it
@@ -289,7 +261,7 @@
      * slightly uncouth storage alloc.
      */
     void prep() {
-        mpMiddle = (_Node*) new(std::nothrow) unsigned char[sizeof(_Node)];
+        mpMiddle = (_Node*)new (std::nothrow) unsigned char[sizeof(_Node)];
         mpMiddle->setPrev(mpMiddle);
         mpMiddle->setNext(mpMiddle);
     }
@@ -299,7 +271,7 @@
      * It sits in the middle of a circular list of nodes.  The iterator
      * runs around the circle until it encounters this one.
      */
-    _Node*      mpMiddle;
+    _Node* mpMiddle;
 };
 
 /*
@@ -309,24 +281,19 @@
  * fill it with the source.  However, we can speed things along by
  * re-using existing elements.
  */
-template<class T>
-List<T>& List<T>::operator=(const List<T>& right)
-{
-    if (this == &right)
-        return *this;       // self-assignment
+template <class T> List<T>& List<T>::operator=(const List<T>& right) {
+    if (this == &right) return *this;  // self-assignment
     iterator firstDst = begin();
     iterator lastDst = end();
     const_iterator firstSrc = right.begin();
     const_iterator lastSrc = right.end();
     while (firstSrc != lastSrc && firstDst != lastDst)
         *firstDst++ = *firstSrc++;
-    if (firstSrc == lastSrc)        // ran out of elements in source?
-        erase(firstDst, lastDst);   // yes, erase any extras
+    if (firstSrc == lastSrc)       // ran out of elements in source?
+        erase(firstDst, lastDst);  // yes, erase any extras
     else
-        insert(lastDst, firstSrc, lastSrc);     // copy remaining over
+        insert(lastDst, firstSrc, lastSrc);  // copy remaining over
     return *this;
 }
 
-}; // namespace android
-
-#endif // _LIBS_UTILS_LIST_H
+};  // namespace keymaster
diff --git a/include/keymaster/UniquePtr.h b/include/keymaster/UniquePtr.h
index 20ff446..aecebb2 100644
--- a/include/keymaster/UniquePtr.h
+++ b/include/keymaster/UniquePtr.h
@@ -14,264 +14,28 @@
  * limitations under the License.
  */
 
-#ifndef INCLUDE_KEYMASTER_UNIQUEPTR_H_
-#define INCLUDE_KEYMASTER_UNIQUEPTR_H_
+#pragma once
 
-#include <stddef.h> // for size_t
+#include <stddef.h>  // for size_t
+
+#include <memory>
 
 namespace keymaster {
 
 // Default deleter for pointer types.
-template <typename T>
-struct DefaultDelete {
+template <typename T> struct DefaultDelete {
     enum { type_must_be_complete = sizeof(T) };
     DefaultDelete() {}
-    void operator()(T* p) const {
-        delete p;
-    }
+    void operator()(T* p) const { delete p; }
 };
 
 // Default deleter for array types.
-template <typename T>
-struct DefaultDelete<T[]> {
+template <typename T> struct DefaultDelete<T[]> {
     enum { type_must_be_complete = sizeof(T) };
-    void operator()(T* p) const {
-        delete[] p;
-    }
+    void operator()(T* p) const { delete[] p; }
 };
 
-// A smart pointer that deletes the given pointer on destruction.
-// Equivalent to C++0x's std::unique_ptr (a combination of boost::scoped_ptr
-// and boost::scoped_array).
-// Named to be in keeping with Android style but also to avoid
-// collision with any other implementation, until we can switch over
-// to unique_ptr.
-// Use thus:
-//   UniquePtr<C> c(new C);
-template <typename T, typename D = DefaultDelete<T> >
-class UniquePtr {
-    template<typename U, typename UD>
-    friend
-    class UniquePtr;
-public:
-    UniquePtr() : mPtr(nullptr) {}
-    // Construct a new UniquePtr, taking ownership of the given raw pointer.
-    explicit UniquePtr(T* ptr) : mPtr(ptr) {
-    }
-    // NOLINTNEXTLINE(google-explicit-constructor)
-    UniquePtr(const decltype(nullptr)&) : mPtr(nullptr) {}
+template <class T, class Deleter = std::default_delete<T>>
+using UniquePtr = std::unique_ptr<T, Deleter>;
 
-    UniquePtr(UniquePtr && other): mPtr(other.mPtr) {
-        other.mPtr = nullptr;
-    }
-
-    template <typename U>
-    // NOLINTNEXTLINE(google-explicit-constructor)
-    UniquePtr(UniquePtr<U>&& other) : mPtr(other.mPtr) {
-        other.mPtr = nullptr;
-    }
-    UniquePtr& operator=(UniquePtr && other) {
-        if (&other != this) {
-            reset();
-            mPtr = other.release();
-        }
-        return *this;
-    }
-
-    ~UniquePtr() {
-        reset();
-    }
-
-    // Accessors.
-    T& operator*() const { return *mPtr; }
-    T* operator->() const { return mPtr; }
-    T* get() const { return mPtr; }
-
-    // NOLINTNEXTLINE(google-explicit-constructor)
-    operator bool() const { return mPtr != nullptr; }
-
-    // Returns the raw pointer and hands over ownership to the caller.
-    // The pointer will not be deleted by UniquePtr.
-    T* release() __attribute__((warn_unused_result)) {
-        T* result = mPtr;
-        mPtr = nullptr;
-        return result;
-    }
-
-    // Takes ownership of the given raw pointer.
-    // If this smart pointer previously owned a different raw pointer, that
-    // raw pointer will be freed.
-    void reset(T* ptr = nullptr) {
-        if (ptr != mPtr) {
-            D()(mPtr);
-            mPtr = ptr;
-        }
-    }
-
-private:
-    // The raw pointer.
-    T* mPtr;
-
-    // Comparing unique pointers is probably a mistake, since they're unique.
-    template <typename T2> bool operator==(const UniquePtr<T2>& p) const;
-    template <typename T2> bool operator!=(const UniquePtr<T2>& p) const;
-
-    UniquePtr(const UniquePtr&) = delete;
-    UniquePtr & operator=(const UniquePtr&) = delete;
-};
-
-// Partial specialization for array types. Like std::unique_ptr, this removes
-// operator* and operator-> but adds operator[].
-template <typename T, typename D>
-class UniquePtr<T[], D> {
-public:
-    UniquePtr() : mPtr(nullptr) {}
-    explicit UniquePtr(T* ptr) : mPtr(ptr) {
-    }
-    // NOLINTNEXTLINE(google-explicit-constructor)
-    UniquePtr(const decltype(nullptr)&) : mPtr(nullptr) {}
-
-    UniquePtr(UniquePtr && other): mPtr(other.mPtr) {
-        other.mPtr = nullptr;
-    }
-    UniquePtr& operator=(UniquePtr && other) {
-        if (&other != this) {
-            reset();
-            mPtr = other.release();
-        }
-        return *this;
-    }
-
-    ~UniquePtr() {
-        reset();
-    }
-
-    T& operator[](size_t i) const {
-        return mPtr[i];
-    }
-    T* get() const { return mPtr; }
-
-    T* release() __attribute__((warn_unused_result)) {
-        T* result = mPtr;
-        mPtr = nullptr;
-        return result;
-    }
-
-    // NOLINTNEXTLINE(google-explicit-constructor)
-    operator bool() const { return mPtr != nullptr; }
-
-    void reset(T* ptr = nullptr) {
-        if (ptr != mPtr) {
-            D()(mPtr);
-            mPtr = ptr;
-        }
-    }
-
-private:
-    T* mPtr;
-
-    UniquePtr(const UniquePtr&) = delete;
-    UniquePtr & operator=(const UniquePtr&) = delete;
-};
-
-} // namespace keymaster
-
-#if UNIQUE_PTR_TESTS
-
-// Run these tests with:
-// g++ -g -DUNIQUE_PTR_TESTS -x c++ UniquePtr.h && ./a.out
-
-#include <stdio.h>
-using namespace keymaster;
-
-static void assert(bool b) {
-    if (!b) {
-        fprintf(stderr, "FAIL\n");
-        abort();
-    }
-    fprintf(stderr, "OK\n");
-}
-static int cCount = 0;
-struct C {
-    C() { ++cCount; }
-    ~C() { --cCount; }
-};
-static bool freed = false;
-struct Freer {
-    void operator()(int* p) {
-        assert(*p == 123);
-        free(p);
-        freed = true;
-    }
-};
-
-int main(int argc, char* argv[]) {
-    //
-    // UniquePtr<T> tests...
-    //
-
-    // Can we free a single object?
-    {
-        UniquePtr<C> c(new C);
-        assert(cCount == 1);
-    }
-    assert(cCount == 0);
-    // Does release work?
-    C* rawC;
-    {
-        UniquePtr<C> c(new C);
-        assert(cCount == 1);
-        rawC = c.release();
-    }
-    assert(cCount == 1);
-    delete rawC;
-    // Does reset work?
-    {
-        UniquePtr<C> c(new C);
-        assert(cCount == 1);
-        c.reset(new C);
-        assert(cCount == 1);
-    }
-    assert(cCount == 0);
-
-    //
-    // UniquePtr<T[]> tests...
-    //
-
-    // Can we free an array?
-    {
-        UniquePtr<C[]> cs(new C[4]);
-        assert(cCount == 4);
-    }
-    assert(cCount == 0);
-    // Does release work?
-    {
-        UniquePtr<C[]> c(new C[4]);
-        assert(cCount == 4);
-        rawC = c.release();
-    }
-    assert(cCount == 4);
-    delete[] rawC;
-    // Does reset work?
-    {
-        UniquePtr<C[]> c(new C[4]);
-        assert(cCount == 4);
-        c.reset(new C[2]);
-        assert(cCount == 2);
-    }
-    assert(cCount == 0);
-
-    //
-    // Custom deleter tests...
-    //
-    assert(!freed);
-    {
-        UniquePtr<int, Freer> i(reinterpret_cast<int*>(malloc(sizeof(int))));
-        *i = 123;
-    }
-    assert(freed);
-    return 0;
-}
-#endif
-
-#endif  // INCLUDE_KEYMASTER_UNIQUEPTR_H_
+}  // namespace keymaster
diff --git a/include/keymaster/android_keymaster.h b/include/keymaster/android_keymaster.h
index 2836464..bbeb81a 100644
--- a/include/keymaster/android_keymaster.h
+++ b/include/keymaster/android_keymaster.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_ANDROID_KEYMASTER_H_
-#define SYSTEM_KEYMASTER_ANDROID_KEYMASTER_H_
+#pragma once
 
 #include <keymaster/android_keymaster_messages.h>
 #include <keymaster/authorization_set.h>
@@ -47,7 +46,8 @@
  */
 class AndroidKeymaster {
   public:
-    AndroidKeymaster(KeymasterContext* context, size_t operation_table_size);
+    AndroidKeymaster(KeymasterContext* context, size_t operation_table_size,
+                     uint32_t message_version = kDefaultMessageVersion);
     virtual ~AndroidKeymaster();
     AndroidKeymaster(AndroidKeymaster&&);
 
@@ -68,10 +68,13 @@
     GetHmacSharingParametersResponse GetHmacSharingParameters();
     ComputeSharedHmacResponse ComputeSharedHmac(const ComputeSharedHmacRequest& request);
     VerifyAuthorizationResponse VerifyAuthorization(const VerifyAuthorizationRequest& request);
-
+    void GenerateTimestampToken(GenerateTimestampTokenRequest& request,
+                                GenerateTimestampTokenResponse* response);
     void AddRngEntropy(const AddEntropyRequest& request, AddEntropyResponse* response);
     void Configure(const ConfigureRequest& request, ConfigureResponse* response);
     void GenerateKey(const GenerateKeyRequest& request, GenerateKeyResponse* response);
+    void GenerateRkpKey(const GenerateRkpKeyRequest& request, GenerateRkpKeyResponse* response);
+    void GenerateCsr(const GenerateCsrRequest& request, GenerateCsrResponse* response);
     void GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
                                GetKeyCharacteristicsResponse* response);
     void ImportKey(const ImportKeyRequest& request, ImportKeyResponse* response);
@@ -87,17 +90,35 @@
     void FinishOperation(const FinishOperationRequest& request, FinishOperationResponse* response);
     void AbortOperation(const AbortOperationRequest& request, AbortOperationResponse* response);
 
+    EarlyBootEndedResponse EarlyBootEnded();
+    DeviceLockedResponse DeviceLocked(const DeviceLockedRequest& request);
+    GetVersion2Response GetVersion2(const GetVersion2Request& request);
+    ConfigureVendorPatchlevelResponse
+    ConfigureVendorPatchlevel(const ConfigureVendorPatchlevelRequest& request);
+    ConfigureBootPatchlevelResponse
+    ConfigureBootPatchlevel(const ConfigureBootPatchlevelRequest& request);
+
     bool has_operation(keymaster_operation_handle_t op_handle) const;
 
+    // Returns the message version negotiated in GetVersion2.  All response messages should have
+    // this passed to their constructors.  This is done automatically for the methods that return a
+    // response by value.  The caller must do it for the methods that take a response pointer.
+    uint32_t message_version() const { return message_version_; }
+
   private:
-    keymaster_error_t LoadKey(const keymaster_key_blob_t& key_blob,
-                              const AuthorizationSet& additional_params,
-                              const KeyFactory** factory, UniquePtr<Key>* key);
+    // Loads the KM key from `key_blob`, getting app ID and app data from `additional_params`, if
+    // needed.  If loading the key fails for any reason (including failure of the version binding
+    // check), the returned UniquePtr is null and `*error` is set (`error` must not be null).
+    UniquePtr<Key> LoadKey(const keymaster_key_blob_t& key_blob,
+                           const AuthorizationSet& additional_params, keymaster_error_t* error);
 
     UniquePtr<KeymasterContext> context_;
     UniquePtr<OperationTable> operation_table_;
+
+    // If the caller doesn't bother to use GetVersion2 or GetVersion to configure the message
+    // version, assume kDefaultVersion, i.e. assume the client and server always support the
+    // latest default, which is the latest, except when experimental features are being added.
+    uint32_t message_version_;
 };
 
 }  // namespace keymaster
-
-#endif  //  SYSTEM_KEYMASTER_ANDROID_KEYMASTER_H_
diff --git a/include/keymaster/android_keymaster_messages.h b/include/keymaster/android_keymaster_messages.h
index 116dfc2..2ec473f 100644
--- a/include/keymaster/android_keymaster_messages.h
+++ b/include/keymaster/android_keymaster_messages.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_ANDROID_KEYMASTER_MESSAGES_H_
-#define SYSTEM_KEYMASTER_ANDROID_KEYMASTER_MESSAGES_H_
+#pragma once
 
 #include <assert.h>
 #include <stdint.h>
@@ -24,6 +23,7 @@
 
 #include <keymaster/android_keymaster_utils.h>
 #include <keymaster/authorization_set.h>
+#include <keymaster/km_version.h>
 
 namespace keymaster {
 
@@ -55,63 +55,110 @@
     DELETE_ALL_KEYS = 23,
     DESTROY_ATTESTATION_IDS = 24,
     IMPORT_WRAPPED_KEY = 25,
+    EARLY_BOOT_ENDED = 26,
+    DEVICE_LOCKED = 27,
+    GET_VERSION_2 = 28,
+    GENERATE_RKP_KEY = 29,
+    GENERATE_CSR = 30,
+    GENERATE_TIMESTAMP_TOKEN = 31,
+    CONFIGURE_VENDOR_PATCHLEVEL = 32,
+    CONFIGURE_BOOT_PATCHLEVEL = 33,
 };
 
 /**
- * Keymaster message versions are tied to keymaster versions.  We map the keymaster
- * major.minor.subminor version to a sequential "message version".
+ * Keymaster message versions are tied to keymaster versions.  We map the keymaster version to a
+ * sequential "message version".  The actual message formatting differences are implemented in the
+ * message classes. Note that it is not necessary to increase the message version when new messages
+ * are added, only when the serialized format of one or more messages changes.  A message version
+ * argument is provided to the message constructor and when the serialization/deserialization
+ * methods are called the implementations of those methods should examine the message version and
+ * generate/parse the byte stream accordingly.
  *
- * Rather than encoding a version number into each message we rely on the client -- who initiates
- * all requests -- to check the version of the keymaster implementation with the GET_VERSION command
- * and to send only requests that the implementation can understand.  This means that only the
- * client side needs to manage version compatibility; the implementation can always expect/produce
- * messages of its format.
+ * The original design of message versioning uses the GetVersion message, sent from client (e.g. HAL
+ * service) to server (e.g. trusted app), and then relies on the client to identify what messages to
+ * send.  This architecture assumes that the client is never older than the server.  This assumption
+ * turned out not to be true in general.
  *
- * Because message version selection is purely a client-side issue, all messages default to using
- * the latest version (MAX_MESSAGE_VERSION).  Client code must take care to check versions and pass
- * correct version values to message constructors.  The AndroidKeymaster implementation always uses
- * the default, latest.
+ * The current approach performs a mutual exchange of message version info between client and
+ * server, using the GetVersion2 message.  In addition, it defers the specification of the message
+ * ID to the message classes, so a message class can use a different ID when necessary.  ID changes
+ * should be rare, in fact the only time they should be required is during the switch from
+ * GetVersion to GetVersion2.
  *
- * Note that this approach implies that GetVersionRequest and GetVersionResponse cannot be
- * versioned.
+ * Assuming both client and server support GetVersion2, the approach is as follows:
+ *
+ * 1.  Client sends GetVersion2Request, containing its maximum message version, c_max.
+ * 2.  Server replies with GetVersion2Response, containing its maximum message version, s_max.
+ * 3.  Both sides proceed to create all messages with version min(c_max, s_max).
+ *
+ * To enable this, the client must always send GetVersion2 as its first message.  If the server
+ * doesn't support GetVersion2, it will reply with an error of some sort (the details are likely
+ * environment-specific).  If the client gets this error, it must respond by sending GetVersion, and
+ * then must configure its message version according to the response.  Note that an acceptable
+ * response to a too-old server version is to return an error to the caller of the client, informing
+ * it of the problem.
+ *
+ * On the server side, a server that supports GetVersion2 must also support GetVersion.  If it
+ * received GetVersion2 it should proceed as outline above, and expect that the client will not send
+ * GetVersion.  If it received GetVersion, it must assume that the client does not support
+ * GetVersion2 and reply that it is version 2.0.0 and use the corresponding message version (3).
  */
-const int32_t MAX_MESSAGE_VERSION = 3;
-inline int32_t MessageVersion(uint8_t major_ver, uint8_t minor_ver, uint8_t /* subminor_ver */) {
-    int32_t message_version = -1;
-    switch (major_ver) {
-    case 0:
-        // For the moment we still support version 0, though in general the plan is not to support
-        // non-matching major versions.
-        message_version = 0;
-        break;
-    case 1:
-        switch (minor_ver) {
-        case 0:
-            message_version = 1;
-            break;
-        case 1:
-            message_version = 2;
-            break;
-        }
-        break;
-    case 2:
-        message_version = 3;
-        break;
+constexpr int32_t kInvalidMessageVersion = -1;
+constexpr int32_t kMaxMessageVersion = 4;
+constexpr int32_t kDefaultMessageVersion = 3;
+
+/**
+ * MessageVersion returns the message version for a specified KM version and, possibly, KM release
+ * date in YYYYMMDD format (it's not recommended to change message formats within a KM version, but
+ * it could happen).
+ */
+inline constexpr int32_t MessageVersion(KmVersion version, uint32_t /* km_date */ = 0) {
+    switch (version) {
+    case KmVersion::KEYMASTER_1:
+        return 1;
+    case KmVersion::KEYMASTER_1_1:
+        return 2;
+    case KmVersion::KEYMASTER_2:
+    case KmVersion::KEYMASTER_3:
+    case KmVersion::KEYMASTER_4:
+    case KmVersion::KEYMASTER_4_1:
+        return 3;
+    case KmVersion::KEYMINT_1:
+        return 4;
     }
-    return message_version;
+    return kInvalidMessageVersion;
 }
 
+/**
+ * NegotiateMessageVersion implements the client side of the GetVersion protocol, determining the
+ * appropriate message version from the values returned by the server.
+ */
+struct GetVersionResponse;
+int32_t NegotiateMessageVersion(const GetVersionResponse& response, keymaster_error_t* error);
+
+/**
+ * This MessageVersion overload determines the message version to use given the provided client and
+ * server messages.  If the client gets an error when it sends GetVersion2Request, it should send
+ * GetVersionRequest and use the above overload.  If the server receives GetVersionRequest, it
+ * should assume it should use message version 3 and return GetVersionResponse(2, 0, 0).
+ */
+struct GetVersion2Request;
+struct GetVersion2Response;
+int32_t NegotiateMessageVersion(const GetVersion2Request& request,
+                                const GetVersion2Response& response);
+
 struct KeymasterMessage : public Serializable {
     explicit KeymasterMessage(int32_t ver) : message_version(ver) { assert(ver >= 0); }
 
-    uint32_t message_version;
+    // The message version that should be used for this message.  This indicates how the data is
+    // serialized/deserialized. Commonly, higher message versions serialize/deserialize additional
+    // arguments, though there is no specific rule limiting later version to adding parameters.
+    const int32_t message_version;
 };
 
 /**
  * All responses include an error value, and if the error is not KM_ERROR_OK, return no additional
- * data.  This abstract class factors out the common serialization functionality for all of the
- * responses, so we only have to implement it once.  Inheritance for reuse is generally not a great
- * structure, but in this case it's the cleanest option.
+ * data.
  */
 struct KeymasterResponse : public KeymasterMessage {
     explicit KeymasterResponse(int32_t ver)
@@ -128,9 +175,27 @@
     keymaster_error_t error;
 };
 
+// Abstract base for empty requests.
+struct EmptyKeymasterRequest : public KeymasterMessage {
+    explicit EmptyKeymasterRequest(int32_t ver) : KeymasterMessage(ver) {}
+
+    size_t SerializedSize() const override { return 0; }
+    uint8_t* Serialize(uint8_t* buf, const uint8_t*) const override { return buf; }
+    bool Deserialize(const uint8_t**, const uint8_t*) override { return true; };
+};
+
+// Empty response.
+struct EmptyKeymasterResponse : public KeymasterResponse {
+    explicit EmptyKeymasterResponse(int32_t ver) : KeymasterResponse(ver) {}
+
+    size_t NonErrorSerializedSize() const override { return 0; }
+    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t*) const override { return buf; }
+    bool NonErrorDeserialize(const uint8_t**, const uint8_t*) override { return true; }
+};
+
+// TODO(swillden): Remove when Keymaster1 is deleted
 struct SupportedAlgorithmsRequest : public KeymasterMessage {
-    explicit SupportedAlgorithmsRequest(int32_t ver = MAX_MESSAGE_VERSION)
-        : KeymasterMessage(ver) {}
+    explicit SupportedAlgorithmsRequest(int32_t ver) : KeymasterMessage(ver) {}
 
     size_t SerializedSize() const override { return 0; };
     uint8_t* Serialize(uint8_t* buf, const uint8_t* /* end */) const override { return buf; }
@@ -139,6 +204,7 @@
     }
 };
 
+// TODO(swillden): Remove when Keymaster1 is deleted
 struct SupportedByAlgorithmRequest : public KeymasterMessage {
     explicit SupportedByAlgorithmRequest(int32_t ver) : KeymasterMessage(ver) {}
 
@@ -153,19 +219,19 @@
     keymaster_algorithm_t algorithm;
 };
 
+// TODO(swillden): Remove when Keymaster1 is deleted
 struct SupportedImportFormatsRequest : public SupportedByAlgorithmRequest {
-    explicit SupportedImportFormatsRequest(int32_t ver = MAX_MESSAGE_VERSION)
-        : SupportedByAlgorithmRequest(ver) {}
+    explicit SupportedImportFormatsRequest(int32_t ver) : SupportedByAlgorithmRequest(ver) {}
 };
 
+// TODO(swillden): Remove when Keymaster1 is deleted
 struct SupportedExportFormatsRequest : public SupportedByAlgorithmRequest {
-    explicit SupportedExportFormatsRequest(int32_t ver = MAX_MESSAGE_VERSION)
-        : SupportedByAlgorithmRequest(ver) {}
+    explicit SupportedExportFormatsRequest(int32_t ver) : SupportedByAlgorithmRequest(ver) {}
 };
 
+// TODO(swillden): Remove when Keymaster1 is deleted
 struct SupportedByAlgorithmAndPurposeRequest : public KeymasterMessage {
-    explicit SupportedByAlgorithmAndPurposeRequest(int32_t ver = MAX_MESSAGE_VERSION)
-        : KeymasterMessage(ver) {}
+    explicit SupportedByAlgorithmAndPurposeRequest(int32_t ver) : KeymasterMessage(ver) {}
 
     size_t SerializedSize() const override { return sizeof(uint32_t) * 2; };
     uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
@@ -181,21 +247,23 @@
     keymaster_purpose_t purpose;
 };
 
+// TODO(swillden): Remove when Keymaster1 is deleted
 struct SupportedBlockModesRequest : public SupportedByAlgorithmAndPurposeRequest {
-    explicit SupportedBlockModesRequest(int32_t ver = MAX_MESSAGE_VERSION)
-        : SupportedByAlgorithmAndPurposeRequest(ver) {}
+    explicit SupportedBlockModesRequest(int32_t ver) : SupportedByAlgorithmAndPurposeRequest(ver) {}
 };
 
+// TODO(swillden): Remove when Keymaster1 is deleted
 struct SupportedPaddingModesRequest : public SupportedByAlgorithmAndPurposeRequest {
-    explicit SupportedPaddingModesRequest(int32_t ver = MAX_MESSAGE_VERSION)
+    explicit SupportedPaddingModesRequest(int32_t ver)
         : SupportedByAlgorithmAndPurposeRequest(ver) {}
 };
 
+// TODO(swillden): Remove when Keymaster1 is deleted
 struct SupportedDigestsRequest : public SupportedByAlgorithmAndPurposeRequest {
-    explicit SupportedDigestsRequest(int32_t ver = MAX_MESSAGE_VERSION)
-        : SupportedByAlgorithmAndPurposeRequest(ver) {}
+    explicit SupportedDigestsRequest(int32_t ver) : SupportedByAlgorithmAndPurposeRequest(ver) {}
 };
 
+// TODO(swillden): Remove when Keymaster1 is deleted
 template <typename T> struct SupportedResponse : public KeymasterResponse {
     explicit SupportedResponse(int32_t ver)
         : KeymasterResponse(ver), results(nullptr), results_length(0) {}
@@ -234,69 +302,126 @@
     size_t results_length;
 };
 
+// TODO(swillden): Remove when Keymaster1 is deleted
 struct SupportedAlgorithmsResponse : public SupportedResponse<keymaster_algorithm_t> {
-    explicit SupportedAlgorithmsResponse(int32_t ver = MAX_MESSAGE_VERSION)
+    explicit SupportedAlgorithmsResponse(int32_t ver)
         : SupportedResponse<keymaster_algorithm_t>(ver) {}
 };
 
+// TODO(swillden): Remove when Keymaster1 is deleted
 struct SupportedBlockModesResponse : public SupportedResponse<keymaster_block_mode_t> {
-    explicit SupportedBlockModesResponse(int32_t ver = MAX_MESSAGE_VERSION)
+    explicit SupportedBlockModesResponse(int32_t ver)
         : SupportedResponse<keymaster_block_mode_t>(ver) {}
 };
 
+// TODO(swillden): Remove when Keymaster1 is deleted
 struct SupportedPaddingModesResponse : public SupportedResponse<keymaster_padding_t> {
-    explicit SupportedPaddingModesResponse(int32_t ver = MAX_MESSAGE_VERSION)
+    explicit SupportedPaddingModesResponse(int32_t ver)
         : SupportedResponse<keymaster_padding_t>(ver) {}
 };
 
+// TODO(swillden): Remove when Keymaster1 is deleted
 struct SupportedDigestsResponse : public SupportedResponse<keymaster_digest_t> {
-    explicit SupportedDigestsResponse(int32_t ver = MAX_MESSAGE_VERSION)
-        : SupportedResponse<keymaster_digest_t>(ver) {}
+    explicit SupportedDigestsResponse(int32_t ver) : SupportedResponse<keymaster_digest_t>(ver) {}
 };
 
+// TODO(swillden): Remove when Keymaster1 is deleted
 struct SupportedImportFormatsResponse : public SupportedResponse<keymaster_key_format_t> {
-    explicit SupportedImportFormatsResponse(int32_t ver = MAX_MESSAGE_VERSION)
+    explicit SupportedImportFormatsResponse(int32_t ver)
         : SupportedResponse<keymaster_key_format_t>(ver) {}
 };
 
+// TODO(swillden): Remove when Keymaster1 is deleted
 struct SupportedExportFormatsResponse : public SupportedResponse<keymaster_key_format_t> {
-    explicit SupportedExportFormatsResponse(int32_t ver = MAX_MESSAGE_VERSION)
+    explicit SupportedExportFormatsResponse(int32_t ver)
         : SupportedResponse<keymaster_key_format_t>(ver) {}
 };
 
 struct GenerateKeyRequest : public KeymasterMessage {
-    explicit GenerateKeyRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {}
+    explicit GenerateKeyRequest(int32_t ver) : KeymasterMessage(ver) {}
 
-    size_t SerializedSize() const override { return key_description.SerializedSize(); }
-    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
-        return key_description.Serialize(buf, end);
-    }
-    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
-        return key_description.Deserialize(buf_ptr, end);
-    }
+    size_t SerializedSize() const override;
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override;
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
 
     AuthorizationSet key_description;
+    KeymasterKeyBlob attestation_signing_key_blob;
+    AuthorizationSet attest_key_params;
+    KeymasterBlob issuer_subject;
 };
 
 struct GenerateKeyResponse : public KeymasterResponse {
-    explicit GenerateKeyResponse(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterResponse(ver) {
-        key_blob.key_material = nullptr;
-        key_blob.key_material_size = 0;
-    }
-    ~GenerateKeyResponse();
+    explicit GenerateKeyResponse(int32_t ver)
+        : KeymasterResponse(ver), key_blob{}, certificate_chain{} {}
 
     size_t NonErrorSerializedSize() const override;
     uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* end) const override;
     bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
 
-    keymaster_key_blob_t key_blob;
+    KeymasterKeyBlob key_blob;
     AuthorizationSet enforced;
     AuthorizationSet unenforced;
+    CertificateChain certificate_chain;
+};
+
+struct GenerateRkpKeyRequest : KeymasterMessage {
+    explicit GenerateRkpKeyRequest(int32_t ver) : KeymasterMessage(ver) {}
+
+    size_t SerializedSize() const override { return sizeof(uint8_t); }
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+        return append_to_buf(buf, end, &test_mode, sizeof(uint8_t));
+    }
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+        return copy_from_buf(buf_ptr, end, &test_mode, sizeof(uint8_t));
+    }
+
+    bool test_mode = false;
+};
+
+struct GenerateRkpKeyResponse : public KeymasterResponse {
+    explicit GenerateRkpKeyResponse(int32_t ver) : KeymasterResponse(ver) {}
+
+    size_t NonErrorSerializedSize() const override;
+    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* end) const override;
+    bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+
+    KeymasterKeyBlob key_blob;
+    KeymasterBlob maced_public_key;
+};
+
+struct GenerateCsrRequest : public KeymasterMessage {
+    explicit GenerateCsrRequest(int32_t ver) : KeymasterMessage(ver) {}
+
+    ~GenerateCsrRequest() override { delete[] keys_to_sign_array; }
+
+    size_t SerializedSize() const override;
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override;
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+    void SetKeyToSign(uint32_t index, const void* data, size_t length);
+    void SetEndpointEncCertChain(const void* data, size_t length);
+    void SetChallenge(const void* data, size_t length);
+
+    bool test_mode = false;
+    size_t num_keys = 0;
+    KeymasterBlob* keys_to_sign_array = nullptr;
+    KeymasterBlob endpoint_enc_cert_chain;
+    KeymasterBlob challenge;
+};
+
+struct GenerateCsrResponse : public KeymasterResponse {
+    explicit GenerateCsrResponse(int32_t ver) : KeymasterResponse(ver) {}
+
+    size_t NonErrorSerializedSize() const override;
+    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* end) const override;
+    bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+
+    KeymasterBlob keys_to_sign_mac;
+    KeymasterBlob device_info_blob;
+    KeymasterBlob protected_data_blob;
 };
 
 struct GetKeyCharacteristicsRequest : public KeymasterMessage {
-    explicit GetKeyCharacteristicsRequest(int32_t ver = MAX_MESSAGE_VERSION)
-        : KeymasterMessage(ver) {
+    explicit GetKeyCharacteristicsRequest(int32_t ver) : KeymasterMessage(ver) {
         key_blob.key_material = nullptr;
         key_blob.key_material_size = 0;
     }
@@ -316,8 +441,8 @@
 };
 
 struct GetKeyCharacteristicsResponse : public KeymasterResponse {
-    explicit GetKeyCharacteristicsResponse(int32_t ver = MAX_MESSAGE_VERSION)
-        : KeymasterResponse(ver) {}
+    explicit GetKeyCharacteristicsResponse(int32_t ver) : KeymasterResponse(ver) {}
+
     size_t NonErrorSerializedSize() const override;
     uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* end) const override;
     bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
@@ -327,7 +452,7 @@
 };
 
 struct BeginOperationRequest : public KeymasterMessage {
-    explicit BeginOperationRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {
+    explicit BeginOperationRequest(int32_t ver) : KeymasterMessage(ver) {
         key_blob.key_material = nullptr;
         key_blob.key_material_size = 0;
     }
@@ -348,7 +473,7 @@
 };
 
 struct BeginOperationResponse : public KeymasterResponse {
-    explicit BeginOperationResponse(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterResponse(ver) {}
+    explicit BeginOperationResponse(int32_t ver) : KeymasterResponse(ver) {}
 
     size_t NonErrorSerializedSize() const override;
     uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* end) const override;
@@ -359,7 +484,7 @@
 };
 
 struct UpdateOperationRequest : public KeymasterMessage {
-    explicit UpdateOperationRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {}
+    explicit UpdateOperationRequest(int32_t ver) : KeymasterMessage(ver) {}
 
     size_t SerializedSize() const override;
     uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override;
@@ -371,8 +496,7 @@
 };
 
 struct UpdateOperationResponse : public KeymasterResponse {
-    explicit UpdateOperationResponse(int32_t ver = MAX_MESSAGE_VERSION)
-        : KeymasterResponse(ver), input_consumed(0) {}
+    explicit UpdateOperationResponse(int32_t ver) : KeymasterResponse(ver), input_consumed(0) {}
 
     size_t NonErrorSerializedSize() const override;
     uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* end) const override;
@@ -384,7 +508,7 @@
 };
 
 struct FinishOperationRequest : public KeymasterMessage {
-    explicit FinishOperationRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {}
+    explicit FinishOperationRequest(int32_t ver) : KeymasterMessage(ver) {}
 
     size_t SerializedSize() const override;
     uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override;
@@ -397,7 +521,7 @@
 };
 
 struct FinishOperationResponse : public KeymasterResponse {
-    explicit FinishOperationResponse(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterResponse(ver) {}
+    explicit FinishOperationResponse(int32_t ver) : KeymasterResponse(ver) {}
 
     size_t NonErrorSerializedSize() const override;
     uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* end) const override;
@@ -408,7 +532,7 @@
 };
 
 struct AbortOperationRequest : public KeymasterMessage {
-    explicit AbortOperationRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {}
+    explicit AbortOperationRequest(int32_t ver) : KeymasterMessage(ver) {}
 
     size_t SerializedSize() const override { return sizeof(uint64_t); }
     uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
@@ -421,16 +545,10 @@
     keymaster_operation_handle_t op_handle;
 };
 
-struct AbortOperationResponse : public KeymasterResponse {
-    explicit AbortOperationResponse(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterResponse(ver) {}
-
-    size_t NonErrorSerializedSize() const override { return 0; }
-    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t*) const override { return buf; }
-    bool NonErrorDeserialize(const uint8_t**, const uint8_t*) override { return true; }
-};
+using AbortOperationResponse = EmptyKeymasterResponse;
 
 struct AddEntropyRequest : public KeymasterMessage {
-    explicit AddEntropyRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {}
+    explicit AddEntropyRequest(int32_t ver) : KeymasterMessage(ver) {}
 
     size_t SerializedSize() const override;
     uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override;
@@ -439,27 +557,10 @@
     Buffer random_data;
 };
 
-struct AddEntropyResponse : public KeymasterResponse {
-    explicit AddEntropyResponse(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterResponse(ver) {}
-
-    size_t NonErrorSerializedSize() const override { return 0; }
-    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* /* end */) const override {
-        return buf;
-    }
-    bool NonErrorDeserialize(const uint8_t** /* buf_ptr */, const uint8_t* /* end */) override {
-        return true;
-    }
-};
+using AddEntropyResponse = EmptyKeymasterResponse;
 
 struct ImportKeyRequest : public KeymasterMessage {
-    explicit ImportKeyRequest(int32_t ver = MAX_MESSAGE_VERSION)
-        : KeymasterMessage(ver), key_data(nullptr) {}
-    ~ImportKeyRequest() { delete[] key_data; }
-
-    void SetKeyMaterial(const void* key_material, size_t length);
-    void SetKeyMaterial(const keymaster_key_blob_t& blob) {
-        SetKeyMaterial(blob.key_material, blob.key_material_size);
-    }
+    explicit ImportKeyRequest(int32_t ver) : KeymasterMessage(ver) {}
 
     size_t SerializedSize() const override;
     uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override;
@@ -467,17 +568,15 @@
 
     AuthorizationSet key_description;
     keymaster_key_format_t key_format;
-    uint8_t* key_data;
-    size_t key_data_length;
+    KeymasterKeyBlob key_data;
+    KeymasterKeyBlob attestation_signing_key_blob;
+    AuthorizationSet attest_key_params;
+    KeymasterBlob issuer_subject;
 };
 
 struct ImportKeyResponse : public KeymasterResponse {
-    explicit ImportKeyResponse(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterResponse(ver) {
-        key_blob.key_material = nullptr;
-        key_blob.key_material_size = 0;
-    }
-    ~ImportKeyResponse() { delete[] key_blob.key_material; }
-
+    explicit ImportKeyResponse(int32_t ver)
+        : KeymasterResponse(ver), key_blob{}, certificate_chain{} {}
     void SetKeyMaterial(const void* key_material, size_t length);
     void SetKeyMaterial(const keymaster_key_blob_t& blob) {
         SetKeyMaterial(blob.key_material, blob.key_material_size);
@@ -487,13 +586,14 @@
     uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* end) const override;
     bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
 
-    keymaster_key_blob_t key_blob;
+    KeymasterKeyBlob key_blob;
     AuthorizationSet enforced;
     AuthorizationSet unenforced;
+    CertificateChain certificate_chain;
 };
 
 struct ExportKeyRequest : public KeymasterMessage {
-    explicit ExportKeyRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {
+    explicit ExportKeyRequest(int32_t ver) : KeymasterMessage(ver) {
         key_blob.key_material = nullptr;
         key_blob.key_material_size = 0;
     }
@@ -514,8 +614,7 @@
 };
 
 struct ExportKeyResponse : public KeymasterResponse {
-    explicit ExportKeyResponse(int32_t ver = MAX_MESSAGE_VERSION)
-        : KeymasterResponse(ver), key_data(nullptr) {}
+    explicit ExportKeyResponse(int32_t ver) : KeymasterResponse(ver), key_data(nullptr) {}
     ~ExportKeyResponse() { delete[] key_data; }
 
     void SetKeyMaterial(const void* key_material, size_t length);
@@ -532,7 +631,7 @@
 };
 
 struct DeleteKeyRequest : public KeymasterMessage {
-    explicit DeleteKeyRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {
+    explicit DeleteKeyRequest(int32_t ver) : KeymasterMessage(ver) {
         key_blob.key_material = nullptr;
         key_blob.key_material_size = 0;
     }
@@ -550,40 +649,25 @@
     keymaster_key_blob_t key_blob;
 };
 
-struct DeleteKeyResponse : public KeymasterResponse {
-    explicit DeleteKeyResponse(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterResponse(ver) {}
+using DeleteKeyResponse = EmptyKeymasterResponse;
 
-    size_t NonErrorSerializedSize() const override { return 0; }
-    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t*) const override { return buf; }
-    bool NonErrorDeserialize(const uint8_t**, const uint8_t*) override { return true; }
+struct DeleteAllKeysRequest : public EmptyKeymasterRequest {
+    explicit DeleteAllKeysRequest(int32_t ver) : EmptyKeymasterRequest(ver) {}
 };
 
-struct DeleteAllKeysRequest : public KeymasterMessage {
-    explicit DeleteAllKeysRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {}
+using DeleteAllKeysResponse = EmptyKeymasterResponse;
 
-    size_t SerializedSize() const override { return 0; }
-    uint8_t* Serialize(uint8_t* buf, const uint8_t*) const override { return buf; }
-    bool Deserialize(const uint8_t**, const uint8_t*) override { return true; };
-};
-
-struct DeleteAllKeysResponse : public KeymasterResponse {
-    explicit DeleteAllKeysResponse(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterResponse(ver) {}
-
-    size_t NonErrorSerializedSize() const override { return 0; }
-    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t*) const override { return buf; }
-    bool NonErrorDeserialize(const uint8_t**, const uint8_t*) override { return true; }
-};
-
-struct GetVersionRequest : public KeymasterMessage {
-    GetVersionRequest() : KeymasterMessage(0 /* not versionable */) {}
-
-    size_t SerializedSize() const override { return 0; }
-    uint8_t* Serialize(uint8_t* buf, const uint8_t*) const override { return buf; }
-    bool Deserialize(const uint8_t**, const uint8_t*) override { return true; };
+struct GetVersionRequest : public EmptyKeymasterRequest {
+    // GetVersionRequest ctor takes a version arg so it has the same signature as others, but the
+    // value is ignored because it is not not versionable.
+    explicit GetVersionRequest(uint32_t /* ver */ = 0)
+        : EmptyKeymasterRequest(0 /* not versionable */) {}
 };
 
 struct GetVersionResponse : public KeymasterResponse {
-    GetVersionResponse()
+    // GetVersionResponse ctor takes a version arg so it has the same signature as others, but the
+    // value is ignored because it is not not versionable.
+    explicit GetVersionResponse(uint32_t /* ver */ = 0)
         : KeymasterResponse(0 /* not versionable */), major_ver(0), minor_ver(0), subminor_ver(0) {}
 
     size_t NonErrorSerializedSize() const override;
@@ -596,7 +680,7 @@
 };
 
 struct AttestKeyRequest : public KeymasterMessage {
-    explicit AttestKeyRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {
+    explicit AttestKeyRequest(int32_t ver) : KeymasterMessage(ver) {
         key_blob.key_material = nullptr;
         key_blob.key_material_size = 0;
     }
@@ -616,25 +700,17 @@
 };
 
 struct AttestKeyResponse : public KeymasterResponse {
-    explicit AttestKeyResponse(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterResponse(ver) {
-        certificate_chain.entry_count = 0;
-        certificate_chain.entries = nullptr;
-    }
-    ~AttestKeyResponse();
-
-    bool AllocateChain(size_t entry_count);
+    explicit AttestKeyResponse(int32_t ver) : KeymasterResponse(ver) {}
 
     size_t NonErrorSerializedSize() const override;
     uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* end) const override;
     bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
 
-    keymaster_cert_chain_t certificate_chain;
+    CertificateChain certificate_chain;
 };
 
 struct UpgradeKeyRequest : public KeymasterMessage {
-    explicit UpgradeKeyRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {
-        key_blob = {nullptr, 0};
-    }
+    explicit UpgradeKeyRequest(int32_t ver) : KeymasterMessage(ver) { key_blob = {nullptr, 0}; }
     ~UpgradeKeyRequest();
 
     void SetKeyMaterial(const void* key_material, size_t length);
@@ -651,7 +727,7 @@
 };
 
 struct UpgradeKeyResponse : public KeymasterResponse {
-    explicit UpgradeKeyResponse(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterResponse(ver) {
+    explicit UpgradeKeyResponse(int32_t ver) : KeymasterResponse(ver) {
         upgraded_key = {nullptr, 0};
     }
     ~UpgradeKeyResponse();
@@ -664,7 +740,7 @@
 };
 
 struct ConfigureRequest : public KeymasterMessage {
-    explicit ConfigureRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {}
+    explicit ConfigureRequest(int32_t ver) : KeymasterMessage(ver) {}
 
     size_t SerializedSize() const override { return sizeof(os_version) + sizeof(os_patchlevel); }
     uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
@@ -677,16 +753,10 @@
     }
 
     uint32_t os_version;
-    uint32_t os_patchlevel;
+    uint32_t os_patchlevel;  // YYYYMM
 };
 
-struct ConfigureResponse : public KeymasterResponse {
-    explicit ConfigureResponse(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterResponse(ver) {}
-
-    size_t NonErrorSerializedSize() const override { return 0; }
-    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t*) const override { return buf; }
-    bool NonErrorDeserialize(const uint8_t**, const uint8_t*) override { return true; }
-};
+using ConfigureResponse = EmptyKeymasterResponse;
 
 struct HmacSharingParameters : public Serializable {
     HmacSharingParameters() : seed({}) { memset(nonce, 0, sizeof(nonce)); }
@@ -724,9 +794,12 @@
     size_t num_params;
 };
 
+struct GetHmacSharingParametersRequest : public EmptyKeymasterRequest {
+    explicit GetHmacSharingParametersRequest(int32_t ver) : EmptyKeymasterRequest(ver) {}
+};
+
 struct GetHmacSharingParametersResponse : public KeymasterResponse {
-    explicit GetHmacSharingParametersResponse(int32_t ver = MAX_MESSAGE_VERSION)
-        : KeymasterResponse(ver) {}
+    explicit GetHmacSharingParametersResponse(int32_t ver) : KeymasterResponse(ver) {}
     GetHmacSharingParametersResponse(GetHmacSharingParametersResponse&& other)
         : KeymasterResponse(other.message_version), params(move(other.params)) {}
 
@@ -744,7 +817,7 @@
 };
 
 struct ComputeSharedHmacRequest : public KeymasterMessage {
-    explicit ComputeSharedHmacRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {}
+    explicit ComputeSharedHmacRequest(int32_t ver) : KeymasterMessage(ver) {}
 
     size_t SerializedSize() const override { return params_array.SerializedSize(); }
     uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
@@ -758,8 +831,7 @@
 };
 
 struct ComputeSharedHmacResponse : public KeymasterResponse {
-    explicit ComputeSharedHmacResponse(int32_t ver = MAX_MESSAGE_VERSION)
-        : KeymasterResponse(ver) {}
+    explicit ComputeSharedHmacResponse(int32_t ver) : KeymasterResponse(ver) {}
     ComputeSharedHmacResponse(ComputeSharedHmacResponse&& other) : KeymasterResponse(move(other)) {
         sharing_check = move(other.sharing_check);
     }
@@ -772,7 +844,7 @@
 };
 
 struct ImportWrappedKeyRequest : public KeymasterMessage {
-    explicit ImportWrappedKeyRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {}
+    explicit ImportWrappedKeyRequest(int32_t ver) : KeymasterMessage(ver) {}
 
     void SetWrappedMaterial(const void* key_material, size_t length);
     void SetWrappingMaterial(const void* key_material, size_t length);
@@ -796,8 +868,8 @@
 };
 
 struct ImportWrappedKeyResponse : public KeymasterResponse {
-    explicit ImportWrappedKeyResponse(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterResponse(ver) {}
-
+    explicit ImportWrappedKeyResponse(int32_t ver = kDefaultMessageVersion)
+        : KeymasterResponse(ver), key_blob{}, certificate_chain{} {}
     void SetKeyMaterial(const void* key_material, size_t length);
     void SetKeyMaterial(const keymaster_key_blob_t& blob) {
         SetKeyMaterial(blob.key_material, blob.key_material_size);
@@ -810,6 +882,7 @@
     KeymasterKeyBlob key_blob;
     AuthorizationSet enforced;
     AuthorizationSet unenforced;
+    CertificateChain certificate_chain;
 };
 
 struct HardwareAuthToken : public Serializable {
@@ -857,8 +930,7 @@
 };
 
 struct VerifyAuthorizationRequest : public KeymasterMessage {
-    explicit VerifyAuthorizationRequest(int32_t ver = MAX_MESSAGE_VERSION)
-        : KeymasterMessage(ver) {}
+    explicit VerifyAuthorizationRequest(int32_t ver) : KeymasterMessage(ver) {}
     VerifyAuthorizationRequest(VerifyAuthorizationRequest&& other) = default;
 
     size_t SerializedSize() const override {
@@ -884,8 +956,7 @@
 };
 
 struct VerifyAuthorizationResponse : public KeymasterResponse {
-    explicit VerifyAuthorizationResponse(int32_t ver = MAX_MESSAGE_VERSION)
-        : KeymasterResponse(ver) {}
+    explicit VerifyAuthorizationResponse(int32_t ver) : KeymasterResponse(ver) {}
     VerifyAuthorizationResponse(VerifyAuthorizationResponse&& other) = default;
 
     size_t NonErrorSerializedSize() const override {
@@ -902,6 +973,208 @@
     VerificationToken token;
 };
 
-}  // namespace keymaster
+struct EarlyBootEndedRequest : public EmptyKeymasterRequest {
+    explicit EarlyBootEndedRequest(int32_t ver) : EmptyKeymasterRequest(ver) {}
+};
 
-#endif  // SYSTEM_KEYMASTER_ANDROID_KEYMASTER_MESSAGES_H_
+struct EarlyBootEndedResponse : public KeymasterResponse {
+    explicit EarlyBootEndedResponse(int32_t ver) : KeymasterResponse(ver) {}
+
+    size_t NonErrorSerializedSize() const override { return 0; }
+    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t*) const override { return buf; }
+    bool NonErrorDeserialize(const uint8_t**, const uint8_t*) override { return true; }
+};
+
+struct DeviceLockedRequest : public KeymasterMessage {
+    explicit DeviceLockedRequest(int32_t ver) : KeymasterMessage(ver) {}
+    explicit DeviceLockedRequest(int32_t ver, bool passwordOnly_, VerificationToken&& token_)
+        : KeymasterMessage(ver), passwordOnly(passwordOnly_), token(move(token_)) {}
+
+    size_t SerializedSize() const override { return 1; }
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+        if (buf < end) *buf++ = passwordOnly ? 1 : 0;
+        return token.Serialize(buf, end);
+    }
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+        if (*buf_ptr >= end) return false;
+        passwordOnly = !!*(*buf_ptr)++;
+        return token.Deserialize(buf_ptr, end);
+    }
+
+    bool passwordOnly;
+    VerificationToken token;
+};
+
+struct DeviceLockedResponse : public KeymasterResponse {
+    explicit DeviceLockedResponse(int32_t ver) : KeymasterResponse(ver) {}
+
+    size_t NonErrorSerializedSize() const override { return 0; }
+    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t*) const override { return buf; }
+    bool NonErrorDeserialize(const uint8_t**, const uint8_t*) override { return true; }
+};
+
+struct GetVersion2Request : public KeymasterMessage {
+    // GetVersion2Request ctor takes a version arg so it has the same signature as others, but the
+    // value is ignored because it's not versionable.
+    explicit GetVersion2Request(uint32_t /* ver */ = 0)
+        : KeymasterMessage(0 /* not versionable */) {}
+
+    size_t SerializedSize() const override { return sizeof(uint32_t); /* max message version */ }
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+        return append_uint32_to_buf(buf, end, max_message_version);
+    }
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+        return copy_uint32_from_buf(buf_ptr, end, &max_message_version);
+    }
+
+    uint32_t max_message_version = kDefaultMessageVersion;
+};
+
+struct GetVersion2Response : public KeymasterResponse {
+    // GetVersion2Request ctor takes a version arg so it has the same signature as others, but the
+    // value is ignored because it's not versionable.
+    explicit GetVersion2Response(uint32_t /* ver */ = 0)
+        : KeymasterResponse(0 /* not versionable */) {}
+
+    size_t NonErrorSerializedSize() const override;
+    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t*) const override;
+    bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+
+    uint32_t max_message_version;
+    KmVersion km_version;
+    uint32_t km_date;
+};
+
+struct TimestampToken : public Serializable {
+    explicit TimestampToken() = default;
+    TimestampToken(TimestampToken&& other) {
+        challenge = other.challenge;
+        timestamp = other.timestamp;
+        security_level = other.security_level;
+        mac = move(other.mac);
+    }
+    size_t SerializedSize() const override {
+        return sizeof(challenge) + sizeof(timestamp) + sizeof(security_level) +
+               mac.SerializedSize();
+    }
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+        buf = append_uint64_to_buf(buf, end, challenge);
+        buf = append_uint64_to_buf(buf, end, timestamp);
+        buf = append_uint32_to_buf(buf, end, security_level);
+        return mac.Serialize(buf, end);
+    }
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+        return copy_uint64_from_buf(buf_ptr, end, &challenge) &&
+               copy_uint64_from_buf(buf_ptr, end, &timestamp) &&
+               copy_uint32_from_buf(buf_ptr, end, &security_level) && mac.Deserialize(buf_ptr, end);
+    }
+    uint64_t challenge{};
+    uint64_t timestamp{};
+    keymaster_security_level_t security_level{};
+    KeymasterBlob mac{};
+};
+
+struct GenerateTimestampTokenRequest : public KeymasterMessage {
+    explicit GenerateTimestampTokenRequest(int32_t ver) : KeymasterMessage(ver), challenge{} {}
+    size_t SerializedSize() const override { return sizeof(challenge); }
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+        return append_uint64_to_buf(buf, end, challenge);
+    }
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+        return copy_uint64_from_buf(buf_ptr, end, &challenge);
+    }
+    uint64_t challenge;
+};
+
+struct GenerateTimestampTokenResponse : public KeymasterResponse {
+    explicit GenerateTimestampTokenResponse(int32_t ver) : KeymasterResponse(ver), token{} {}
+    size_t NonErrorSerializedSize() const override { return token.SerializedSize(); }
+    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* end) const override {
+        return token.Serialize(buf, end);
+    }
+    bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+        return token.Deserialize(buf_ptr, end);
+    }
+    TimestampToken token;
+};
+
+struct SetAttestationIdsRequest : public KeymasterMessage {
+    explicit SetAttestationIdsRequest(int32_t ver) : KeymasterMessage(ver) {}
+    size_t SerializedSize() const override {
+        return brand.SerializedSize()           //
+               + device.SerializedSize()        //
+               + product.SerializedSize()       //
+               + serial.SerializedSize()        //
+               + imei.SerializedSize()          //
+               + meid.SerializedSize()          //
+               + manufacturer.SerializedSize()  //
+               + model.SerializedSize();
+    }
+
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+        buf = brand.Serialize(buf, end);
+        buf = device.Serialize(buf, end);
+        buf = product.Serialize(buf, end);
+        buf = serial.Serialize(buf, end);
+        buf = imei.Serialize(buf, end);
+        buf = meid.Serialize(buf, end);
+        buf = manufacturer.Serialize(buf, end);
+        return model.Serialize(buf, end);
+    }
+
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+        return brand.Deserialize(buf_ptr, end)            //
+               && device.Deserialize(buf_ptr, end)        //
+               && product.Deserialize(buf_ptr, end)       //
+               && serial.Deserialize(buf_ptr, end)        //
+               && imei.Deserialize(buf_ptr, end)          //
+               && meid.Deserialize(buf_ptr, end)          //
+               && manufacturer.Deserialize(buf_ptr, end)  //
+               && model.Deserialize(buf_ptr, end);        //
+    }
+
+    Buffer brand;
+    Buffer device;
+    Buffer product;
+    Buffer serial;
+    Buffer imei;
+    Buffer meid;
+    Buffer manufacturer;
+    Buffer model;
+};
+
+using SetAttestationIdsResponse = EmptyKeymasterResponse;
+
+struct ConfigureVendorPatchlevelRequest : public KeymasterMessage {
+    explicit ConfigureVendorPatchlevelRequest(int32_t ver) : KeymasterMessage(ver) {}
+
+    size_t SerializedSize() const override { return sizeof(vendor_patchlevel); }
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+        return append_uint32_to_buf(buf, end, vendor_patchlevel);
+    }
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+        return copy_uint32_from_buf(buf_ptr, end, &vendor_patchlevel);
+    }
+
+    uint32_t vendor_patchlevel{};  // YYYYMMDD
+};
+
+using ConfigureVendorPatchlevelResponse = EmptyKeymasterResponse;
+
+struct ConfigureBootPatchlevelRequest : public KeymasterMessage {
+    explicit ConfigureBootPatchlevelRequest(int32_t ver) : KeymasterMessage(ver) {}
+
+    size_t SerializedSize() const override { return sizeof(boot_patchlevel); }
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+        return append_uint32_to_buf(buf, end, boot_patchlevel);
+    }
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+        return copy_uint32_from_buf(buf_ptr, end, &boot_patchlevel);
+    }
+
+    uint32_t boot_patchlevel{};  // YYYYMMDD
+};
+
+using ConfigureBootPatchlevelResponse = EmptyKeymasterResponse;
+
+}  // namespace keymaster
diff --git a/include/keymaster/android_keymaster_utils.h b/include/keymaster/android_keymaster_utils.h
index 31f86d9..b0a4052 100644
--- a/include/keymaster/android_keymaster_utils.h
+++ b/include/keymaster/android_keymaster_utils.h
@@ -14,27 +14,15 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_ANDROID_KEYMASTER_UTILS_H_
-#define SYSTEM_KEYMASTER_ANDROID_KEYMASTER_UTILS_H_
+#pragma once
 
 #include <stdint.h>
-#ifndef  __clang__
-// We need to diable foritfy level for memset in gcc because we want to use
-// memset unoptimized. This would falsely trigger __warn_memset_zero_len in
-// /usr/include/bits/string3.h. The inline checking function is only supposed to
-// work when the optimization level is at least 1.
-#pragma push_macro("__USE_FORTIFY_LEVEL")
-#undef __USE_FORTIFY_LEVEL
-#endif
-#include <string.h>
-#ifndef  __clang__
-#pragma pop_macro("__USE_FORTIFY_LEVEL")
-#endif
 #include <time.h>  // for time_t.
 
-#include <keymaster/UniquePtr.h>
-
 #include <hardware/keymaster_defs.h>
+
+#include <keymaster/UniquePtr.h>
+#include <keymaster/mem.h>
 #include <keymaster/serializable.h>
 
 #ifndef __has_cpp_attribute
@@ -62,151 +50,6 @@
     return static_cast<int64_t>(time) * 1000;
 }
 
-/*
- * Array Manipulation functions.  This set of templated inline functions provides some nice tools
- * for operating on c-style arrays.  C-style arrays actually do have a defined size associated with
- * them, as long as they are not allowed to decay to a pointer.  These template methods exploit this
- * to allow size-based array operations without explicitly specifying the size.  If passed a pointer
- * rather than an array, they'll fail to compile.
- */
-
-/**
- * Return the size in bytes of the array \p a.
- */
-template <typename T, size_t N> inline size_t array_size(const T (&a)[N]) {
-    return sizeof(a);
-}
-
-/**
- * Return the number of elements in array \p a.
- */
-template <typename T, size_t N> inline size_t array_length(const T (&)[N]) {
-    return N;
-}
-
-/**
- * Duplicate the array \p a.  The memory for the new array is allocated and the caller takes
- * responsibility.
- */
-template <typename T> inline T* dup_array(const T* a, size_t n) {
-    T* dup = new (std::nothrow) T[n];
-    if (dup)
-        for (size_t i = 0; i < n; ++i)
-            dup[i] = a[i];
-    return dup;
-}
-
-/**
- * Duplicate the array \p a.  The memory for the new array is allocated and the caller takes
- * responsibility.  Note that the dup is necessarily returned as a pointer, so size is lost.  Call
- * array_length() on the original array to discover the size.
- */
-template <typename T, size_t N> inline T* dup_array(const T (&a)[N]) {
-    return dup_array(a, N);
-}
-
-/**
- * Duplicate the buffer \p buf.  The memory for the new buffer is allocated and the caller takes
- * responsibility.
- */
-uint8_t* dup_buffer(const void* buf, size_t size);
-
-/**
- * Copy the contents of array \p arr to \p dest.
- */
-template <typename T, size_t N> inline void copy_array(const T (&arr)[N], T* dest) {
-    for (size_t i = 0; i < N; ++i)
-        dest[i] = arr[i];
-}
-
-/**
- * Search array \p a for value \p val, returning true if found.  Note that this function is
- * early-exit, meaning that it should not be used in contexts where timing analysis attacks could be
- * a concern.
- */
-template <typename T, size_t N> inline bool array_contains(const T (&a)[N], T val) {
-    for (size_t i = 0; i < N; ++i) {
-        if (a[i] == val) {
-            return true;
-        }
-    }
-    return false;
-}
-
-/**
- * Variant of memset() that uses GCC-specific pragmas to disable optimizations, so effect is not
- * optimized away.  This is important because we often need to wipe blocks of sensitive data from
- * memory.  As an additional convenience, this implementation avoids writing to NULL pointers.
- */
-#ifdef __clang__
-#define OPTNONE __attribute__((optnone))
-#else  // not __clang__
-#define OPTNONE __attribute__((optimize("O0")))
-#endif  // not __clang__
-inline OPTNONE void* memset_s(void* s, int c, size_t n) {
-    if (!s)
-        return s;
-    return memset(s, c, n);
-}
-#undef OPTNONE
-
-/**
- * Variant of memcmp that has the same runtime regardless of whether the data matches (i.e. doesn't
- * short-circuit).  Not an exact equivalent to memcmp because it doesn't return <0 if p1 < p2, just
- * 0 for match and non-zero for non-match.
- */
-int memcmp_s(const void* p1, const void* p2, size_t length);
-
-/**
- * Eraser clears buffers.  Construct it with a buffer or object and the destructor will ensure that
- * it is zeroed.
- */
-class Eraser {
-  public:
-    /* Not implemented.  If this gets used, we want a link error. */
-    template <typename T> explicit Eraser(T* t);
-
-    template <typename T>
-    explicit Eraser(T& t) : buf_(reinterpret_cast<uint8_t*>(&t)), size_(sizeof(t)) {}
-
-    template <size_t N> explicit Eraser(uint8_t (&arr)[N]) : buf_(arr), size_(N) {}
-
-    Eraser(void* buf, size_t size) : buf_(static_cast<uint8_t*>(buf)), size_(size) {}
-    ~Eraser() { memset_s(buf_, 0, size_); }
-
-  private:
-    Eraser(const Eraser&);
-    void operator=(const Eraser&);
-
-    uint8_t* buf_;
-    size_t size_;
-};
-
-/**
- * ArrayWrapper is a trivial wrapper around a C-style array that provides begin() and end()
- * methods. This is primarily to facilitate range-based iteration on arrays.  It does not copy, nor
- * does it take ownership; it just holds pointers.
- */
-template <typename T> class ArrayWrapper {
-  public:
-    ArrayWrapper(T* array, size_t size) : begin_(array), end_(array + size) {}
-
-    T* begin() { return begin_; }
-    T* end() { return end_; }
-
-  private:
-    T* begin_;
-    T* end_;
-};
-
-template <typename T> ArrayWrapper<T> array_range(T* begin, size_t length) {
-    return ArrayWrapper<T>(begin, length);
-}
-
-template <typename T, size_t n> ArrayWrapper<T> array_range(T (&a)[n]) {
-    return ArrayWrapper<T>(a, n);
-}
-
 /**
  * Convert any unsigned integer from network to host order.  We implement this here rather than
  * using the functions from arpa/inet.h because the TEE doesn't have inet.h.  This isn't the most
@@ -237,37 +80,29 @@
     return retval;
 }
 
-inline
-const uint8_t* const & accessBlobData(const keymaster_key_blob_t* blob) {
+inline const uint8_t* const& accessBlobData(const keymaster_key_blob_t* blob) {
     return blob->key_material;
 }
-inline
-const uint8_t*& accessBlobData(keymaster_key_blob_t* blob) {
+inline const uint8_t*& accessBlobData(keymaster_key_blob_t* blob) {
     return blob->key_material;
 }
-inline
-const size_t& accessBlobSize(const keymaster_key_blob_t* blob) {
+inline const size_t& accessBlobSize(const keymaster_key_blob_t* blob) {
     return blob->key_material_size;
 }
-inline
-size_t& accessBlobSize(keymaster_key_blob_t* blob) {
+inline size_t& accessBlobSize(keymaster_key_blob_t* blob) {
     return blob->key_material_size;
 }
 
-inline
-const uint8_t* const & accessBlobData(const keymaster_blob_t* blob) {
+inline const uint8_t* const& accessBlobData(const keymaster_blob_t* blob) {
     return blob->data;
 }
-inline
-const uint8_t*& accessBlobData(keymaster_blob_t* blob) {
+inline const uint8_t*& accessBlobData(keymaster_blob_t* blob) {
     return blob->data;
 }
-inline
-const size_t & accessBlobSize(const keymaster_blob_t* blob) {
+inline const size_t& accessBlobSize(const keymaster_blob_t* blob) {
     return blob->data_length;
 }
-inline
-size_t& accessBlobSize(keymaster_blob_t* blob) {
+inline size_t& accessBlobSize(keymaster_blob_t* blob) {
     return blob->data_length;
 }
 
@@ -276,8 +111,7 @@
  * keymaster_key_blob_t.  It manages its own memory, which makes avoiding memory leaks
  * much easier.
  */
-template <typename BlobType>
-struct TKeymasterBlob : public BlobType {
+template <typename BlobType> struct TKeymasterBlob : public BlobType {
     TKeymasterBlob() {
         accessBlobData(this) = nullptr;
         accessBlobSize(this) = 0;
@@ -286,37 +120,31 @@
     TKeymasterBlob(const uint8_t* data, size_t size) {
         accessBlobSize(this) = 0;
         accessBlobData(this) = dup_buffer(data, size);
-        if (accessBlobData(this))
-            accessBlobSize(this) = size;
+        if (accessBlobData(this)) accessBlobSize(this) = size;
     }
 
     explicit TKeymasterBlob(size_t size) {
         accessBlobSize(this) = 0;
         accessBlobData(this) = new (std::nothrow) uint8_t[size];
-        if (accessBlobData(this))
-            accessBlobSize(this) = size;
+        if (accessBlobData(this)) accessBlobSize(this) = size;
     }
 
     explicit TKeymasterBlob(const BlobType& blob) {
         accessBlobSize(this) = 0;
         accessBlobData(this) = dup_buffer(accessBlobData(&blob), accessBlobSize(&blob));
-        if (accessBlobData(this))
-            accessBlobSize(this) = accessBlobSize(&blob);
+        if (accessBlobData(this)) accessBlobSize(this) = accessBlobSize(&blob);
     }
 
-    template<size_t N>
-    explicit TKeymasterBlob(const uint8_t (&data)[N]) {
+    template <size_t N> explicit TKeymasterBlob(const uint8_t (&data)[N]) {
         accessBlobSize(this) = 0;
         accessBlobData(this) = dup_buffer(data, N);
-        if (accessBlobData(this))
-            accessBlobSize(this) = N;
+        if (accessBlobData(this)) accessBlobSize(this) = N;
     }
 
     TKeymasterBlob(const TKeymasterBlob& blob) {
         accessBlobSize(this) = 0;
         accessBlobData(this) = dup_buffer(accessBlobData(&blob), accessBlobSize(&blob));
-        if (accessBlobData(this))
-            accessBlobSize(this) = accessBlobSize(&blob);
+        if (accessBlobData(this)) accessBlobSize(this) = accessBlobSize(&blob);
     }
 
     TKeymasterBlob(TKeymasterBlob&& rhs) {
@@ -351,6 +179,8 @@
     const uint8_t* begin() const { return accessBlobData(this); }
     const uint8_t* end() const { return accessBlobData(this) + accessBlobSize(this); }
 
+    size_t size() const { return accessBlobSize(this); }
+
     void Clear() {
         if (accessBlobSize(this)) {
             memset_s(const_cast<uint8_t*>(accessBlobData(this)), 0, accessBlobSize(this));
@@ -363,8 +193,7 @@
     const uint8_t* Reset(size_t new_size) {
         Clear();
         accessBlobData(this) = new (std::nothrow) uint8_t[new_size];
-        if (accessBlobData(this))
-            accessBlobSize(this) = new_size;
+        if (accessBlobData(this)) accessBlobSize(this) = new_size;
         return accessBlobData(this);
     }
 
@@ -408,45 +237,9 @@
     }
 };
 
-struct Malloc_Delete {
-    void operator()(void* p) { free(p); }
-};
-
-struct CertificateChainDelete {
-    void operator()(keymaster_cert_chain_t* p) {
-        if (!p)
-            return;
-        for (size_t i = 0; i < p->entry_count; ++i)
-            delete[] p->entries[i].data;
-        delete[] p->entries;
-        delete p;
-    }
-};
-
-typedef UniquePtr<keymaster_cert_chain_t, CertificateChainDelete> CertChainPtr;
-
 keymaster_error_t EcKeySizeToCurve(uint32_t key_size_bits, keymaster_ec_curve_t* curve);
 keymaster_error_t EcCurveToKeySize(keymaster_ec_curve_t curve, uint32_t* key_size_bits);
 
-template<typename T> struct remove_reference      {typedef T type;};
-template<typename T> struct remove_reference<T&>  {typedef T type;};
-template<typename T> struct remove_reference<T&&> {typedef T type;};
-template<typename T>
-using remove_reference_t = typename remove_reference<T>::type;
-template<typename T>
-remove_reference_t<T>&& move(T&& x) {
-    return static_cast<remove_reference_t<T>&&>(x);
-}
-
-template<typename T>
-constexpr T&& forward(remove_reference_t<T>& x) {
-    return static_cast<T&&>(x);
-}
-template<typename T>
-constexpr T&& forward(remove_reference_t<T>&& x) {
-    return static_cast<T&&>(x);
-}
-
 template <class F> class final_action {
   public:
     explicit final_action(F f) : f_(move(f)) {}
@@ -460,6 +253,116 @@
     return final_action<F>(f);
 }
 
-}  // namespace keymaster
+struct CertificateChain : public keymaster_cert_chain_t {
+    CertificateChain() : keymaster_cert_chain_t{} {}
 
-#endif  // SYSTEM_KEYMASTER_ANDROID_KEYMASTER_UTILS_H_
+    /**
+     * Create a chain with space allocated for `length` certificates.  If allocation fails,
+     * `entries` will be null.
+     */
+    explicit CertificateChain(size_t length) : keymaster_cert_chain_t{} {
+        entries = new (std::nothrow) keymaster_blob_t[length];
+        if (!entries) return;
+        entry_count = length;
+        for (size_t i = 0; i < entry_count; ++i) {
+            entries[i] = {};
+        }
+    }
+
+    CertificateChain(CertificateChain&& other) : keymaster_cert_chain_t{} { *this = move(other); }
+
+    ~CertificateChain() { Clear(); }
+
+    CertificateChain& operator=(CertificateChain&& other) {
+        Clear();
+        (keymaster_cert_chain_t&)(*this) = (keymaster_cert_chain_t&)(other);
+        (keymaster_cert_chain_t&)(other) = {};
+        return *this;
+    }
+
+    /**
+     * Clone `other`.  If anything fails, `entries` will be null.
+     */
+    static CertificateChain clone(const keymaster_cert_chain_t& other) {
+        CertificateChain retval;
+        retval.entry_count = other.entry_count;
+        retval.entries = new (std::nothrow) keymaster_blob_t[retval.entry_count];
+        if (!retval.entries) return {};
+
+        for (auto& entry : retval) {
+            entry = {};
+        }
+
+        for (size_t i = 0; i < retval.entry_count; ++i) {
+            retval.entries[i].data_length = other.entries[i].data_length;
+            retval.entries[i].data = new (std::nothrow) uint8_t[retval.entries[i].data_length];
+            if (!retval.entries[i].data) return {};
+
+            memcpy(const_cast<uint8_t*>(retval.entries[i].data), other.entries[i].data,
+                   retval.entries[i].data_length);
+        }
+
+        return retval;
+    }
+
+    explicit operator bool() { return entries; }
+
+    keymaster_blob_t* begin() { return entries; }
+    const keymaster_blob_t* begin() const { return entries; }
+    keymaster_blob_t* end() { return entries + entry_count; }
+    const keymaster_blob_t* end() const { return entries + entry_count; }
+
+    // Insert the provided blob at the front of the chain.  CertificateChain takes ownership of the
+    // contents of `new_entry`.
+    bool push_front(const keymaster_blob_t& new_entry) {
+        keymaster_blob_t* new_entries = new keymaster_blob_t[entry_count + 1];
+        if (!new_entries) return false;
+
+        new_entries[0] = new_entry;
+        for (size_t i = 1; i < entry_count + 1; ++i) {
+            new_entries[i] = entries[i - 1];
+        }
+
+        delete[] entries;
+        entries = new_entries;
+        ++entry_count;
+        return true;
+    }
+
+    keymaster_cert_chain_t release() {
+        keymaster_cert_chain_t retval = *this;
+        entries = nullptr;
+        entry_count = 0;
+        return retval;
+    }
+
+    void Clear() {
+        if (entries) {
+            for (size_t i = 0; i < entry_count; ++i) {
+                delete[] entries[i].data;
+            }
+            delete[] entries;
+        }
+        entry_count = 0;
+        entries = nullptr;
+    }
+};
+
+// Per RFC 5280 4.1.2.5, an undefined expiration (not-after) field should be set to GeneralizedTime
+// 999912312359559, which is 253402300799000 ms from Jan 1, 1970.
+constexpr int64_t kUndefinedExpirationDateTime = 253402300799000;
+
+// A confirmation token is the output of HMAC-SHA256. */
+constexpr size_t kConfirmationTokenSize = 32;
+
+// Defined in hardware/interfaces/confirmationui/1.0/IConfirmationResultCallback.hal
+constexpr const char kConfirmationTokenMessageTag[] = "confirmation token";
+
+constexpr size_t kConfirmationTokenMessageTagSize = sizeof(kConfirmationTokenMessageTag) - 1;
+
+// Maximum supported size for CBOR which includes prompt and
+// extra_data as returned by the ConfirmationUI. See
+// https://source.android.com/security/protected-confirmation/implementation
+constexpr size_t kConfirmationMessageMaxSize = 6144;
+
+}  // namespace keymaster
diff --git a/include/keymaster/asymmetric_key_factory.h b/include/keymaster/asymmetric_key_factory.h
index eacc9a8..dab7916 100644
--- a/include/keymaster/asymmetric_key_factory.h
+++ b/include/keymaster/asymmetric_key_factory.h
@@ -14,23 +14,25 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_ASYMMETRIC_KEY_FACTORY_H_
-#define SYSTEM_KEYMASTER_ASYMMETRIC_KEY_FACTORY_H_
+#pragma once
 
 #include <keymaster/key_factory.h>
 
 namespace keymaster {
 
+class KeymasterContext;
+
 /**
  * Abstract base for KeyFactories that handle asymmetric keys.
  */
 class AsymmetricKey;
 class AsymmetricKeyFactory : public KeyFactory {
   public:
+    explicit AsymmetricKeyFactory(const KeymasterContext& context) : context_(context) {}
     keymaster_error_t LoadKey(KeymasterKeyBlob&& key_material,
                               const AuthorizationSet& additional_params,
-                              AuthorizationSet&& hw_enforced,
-                              AuthorizationSet&& sw_enforced,
+                              AuthorizationSet&& hw_enforced,  //
+                              AuthorizationSet&& sw_enforced,  //
                               UniquePtr<Key>* key) const override;
 
     virtual keymaster_error_t CreateEmptyKey(AuthorizationSet&& hw_enforced,
@@ -40,10 +42,13 @@
     virtual keymaster_algorithm_t keymaster_key_type() const = 0;
     virtual int evp_key_type() const = 0;
 
-    virtual const keymaster_key_format_t* SupportedImportFormats(size_t* format_count) const override;
-    virtual const keymaster_key_format_t* SupportedExportFormats(size_t* format_count) const override;
+    virtual const keymaster_key_format_t*
+    SupportedImportFormats(size_t* format_count) const override;
+    virtual const keymaster_key_format_t*
+    SupportedExportFormats(size_t* format_count) const override;
+
+  protected:
+    const KeymasterContext& context_;
 };
 
 }  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_ASYMMETRIC_KEY_FACTORY_H_
diff --git a/include/keymaster/attestation_context.h b/include/keymaster/attestation_context.h
new file mode 100644
index 0000000..6d2887d
--- /dev/null
+++ b/include/keymaster/attestation_context.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <keymaster/authorization_set.h>
+#include <keymaster/km_version.h>
+
+namespace keymaster {
+
+class Key;
+
+/**
+ * AttestationContext provides an abstract interface to the information needed
+ * to generate attestation certificates.
+ */
+class AttestationContext {
+  protected:
+    virtual ~AttestationContext() {}
+
+  public:
+    explicit AttestationContext(KmVersion version) : version_(version) {}
+
+    KmVersion GetKmVersion() const { return version_; }
+
+    /**
+     * Returns the security level (SW or TEE) of this keymaster implementation.
+     */
+    virtual keymaster_security_level_t GetSecurityLevel() const = 0;
+
+    /**
+     * Verify that the device IDs provided in `attestation_params` match the device's actual IDs and
+     * copy the verified IDs into `attestation`.  If *any* of the IDs do not match or verification
+     * is not possible, return KM_ERROR_CANNOT_ATTEST_IDS.  If device ID attestation is unsupported,
+     * ignore all arguments and return KM_ERROR_UNIMPLEMENTED.  If ID attestation is supported and
+     * no ID mismatches are found, return KM_ERROR_OK;
+     */
+    virtual keymaster_error_t
+    VerifyAndCopyDeviceIds(const AuthorizationSet& /* attestation_params */,
+                           AuthorizationSet* /* attestation */) const {
+        return KM_ERROR_UNIMPLEMENTED;
+    }
+
+    /**
+     * Generate the current unique ID.  If unique IDs are not supported, set `error` to
+     * KM_ERROR_UNIMPLEMENTED.
+     */
+    virtual Buffer GenerateUniqueId(uint64_t /*creation_date_time*/,
+                                    const keymaster_blob_t& /*application_id*/,
+                                    bool /*reset_since_rotation*/, keymaster_error_t* error) const {
+        if (error) *error = KM_ERROR_UNIMPLEMENTED;
+        return {};
+    }
+
+    struct VerifiedBootParams {
+        keymaster_blob_t verified_boot_key;
+        keymaster_blob_t verified_boot_hash;
+        keymaster_verified_boot_t verified_boot_state;
+        bool device_locked;
+    };
+
+    /**
+     * Returns verified boot parameters for the Attestation Extension.  For hardware-based
+     * implementations, these will be the values reported by the bootloader. By default, verified
+     * boot state is unknown, and KM_ERROR_UNIMPLEMENTED is returned.
+     *
+     * The AttestationContext retains ownership of the VerifiedBootParams.
+     */
+    virtual const VerifiedBootParams* GetVerifiedBootParams(keymaster_error_t* error) const {
+        *error = KM_ERROR_UNIMPLEMENTED;
+        return nullptr;
+    }
+
+    /**
+     * Return the factory attestation signing key.  If not available, set `error` to
+     * KM_ERROR_UNIMPLEMENTED.
+     */
+    virtual KeymasterKeyBlob GetAttestationKey(keymaster_algorithm_t algorithm,
+                                               keymaster_error_t* error) const = 0;
+
+    /**
+     * Return the factory attestation signing key certificate chain.  If not available, set `error`
+     * to KM_ERROR_UNIMPLEMENTED.
+     */
+    virtual CertificateChain GetAttestationChain(keymaster_algorithm_t algorithm,
+                                                 keymaster_error_t* error) const = 0;
+
+  protected:
+    KmVersion version_;
+};
+
+}  // namespace keymaster
diff --git a/include/keymaster/attestation_record.h b/include/keymaster/attestation_record.h
deleted file mode 100644
index f4857af..0000000
--- a/include/keymaster/attestation_record.h
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright 2016 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_KEYMASTER_ATTESTATION_RECORD_H_
-#define SYSTEM_KEYMASTER_ATTESTATION_RECORD_H_
-
-#include <hardware/keymaster_defs.h>
-
-#include <keymaster/authorization_set.h>
-
-#include <openssl/asn1t.h>
-
-namespace keymaster {
-
-struct stack_st_ASN1_TYPE_Delete {
-    void operator()(stack_st_ASN1_TYPE* p) { sk_ASN1_TYPE_free(p); }
-};
-
-struct ASN1_STRING_Delete {
-    void operator()(ASN1_STRING* p) { ASN1_STRING_free(p); }
-};
-
-struct ASN1_TYPE_Delete {
-    void operator()(ASN1_TYPE* p) { ASN1_TYPE_free(p); }
-};
-
-#define ASN1_INTEGER_SET STACK_OF(ASN1_INTEGER)
-
-typedef struct km_root_of_trust {
-    ASN1_OCTET_STRING* verified_boot_key;
-    ASN1_BOOLEAN* device_locked;
-    ASN1_ENUMERATED* verified_boot_state;
-    ASN1_OCTET_STRING* verified_boot_hash;
-} KM_ROOT_OF_TRUST;
-
-ASN1_SEQUENCE(KM_ROOT_OF_TRUST) = {
-    ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_key, ASN1_OCTET_STRING),
-    ASN1_SIMPLE(KM_ROOT_OF_TRUST, device_locked, ASN1_BOOLEAN),
-    ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_state, ASN1_ENUMERATED),
-    ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_hash, ASN1_OCTET_STRING),
-} ASN1_SEQUENCE_END(KM_ROOT_OF_TRUST);
-DECLARE_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* block_mode;
-    ASN1_INTEGER_SET* digest;
-    ASN1_INTEGER_SET* padding;
-    ASN1_NULL* caller_nonce;
-    ASN1_INTEGER* min_mac_length;
-    ASN1_INTEGER_SET* kdf;
-    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* trusted_confirmation_required;
-    ASN1_NULL* unlocked_device_required;
-    ASN1_NULL* all_applications;
-    ASN1_OCTET_STRING* application_id;
-    ASN1_INTEGER* creation_date_time;
-    ASN1_INTEGER* origin;
-    ASN1_NULL* rollback_resistance;
-    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;
-    ASN1_OCTET_STRING* attestation_id_brand;
-    ASN1_OCTET_STRING* attestation_id_device;
-    ASN1_OCTET_STRING* attestation_id_product;
-    ASN1_OCTET_STRING* attestation_id_serial;
-    ASN1_OCTET_STRING* attestation_id_imei;
-    ASN1_OCTET_STRING* attestation_id_meid;
-    ASN1_OCTET_STRING* attestation_id_manufacturer;
-    ASN1_OCTET_STRING* attestation_id_model;
-} KM_AUTH_LIST;
-
-ASN1_SEQUENCE(KM_AUTH_LIST) = {
-    ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.masked_tag()),
-    ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, block_mode, ASN1_INTEGER, TAG_BLOCK_MODE.masked_tag()),
-    ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.masked_tag()),
-    ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, caller_nonce, ASN1_NULL, TAG_CALLER_NONCE.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, min_mac_length, ASN1_INTEGER, TAG_MIN_MAC_LENGTH.masked_tag()),
-    ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, kdf, ASN1_INTEGER, TAG_KDF.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER,
-                 TAG_RSA_PUBLIC_EXPONENT.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER,
-                 TAG_ORIGINATION_EXPIRE_DATETIME.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER,
-                 TAG_USAGE_EXPIRE_DATETIME.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, allow_while_on_body, ASN1_NULL,
-                 TAG_ALLOW_WHILE_ON_BODY.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, unlocked_device_required, ASN1_NULL,
-                 TAG_UNLOCKED_DEVICE_REQUIRED.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, all_applications, ASN1_NULL, TAG_ALL_APPLICATIONS.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, application_id, ASN1_OCTET_STRING, TAG_APPLICATION_ID.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER,
-                 TAG_CREATION_DATETIME.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistance, ASN1_NULL,
-                 TAG_ROLLBACK_RESISTANCE.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistant, ASN1_NULL, TAG_ROLLBACK_RESISTANT.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, attestation_application_id, ASN1_OCTET_STRING,
-                 TAG_ATTESTATION_APPLICATION_ID.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_brand, ASN1_OCTET_STRING,
-                 TAG_ATTESTATION_ID_BRAND.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_device, ASN1_OCTET_STRING,
-                 TAG_ATTESTATION_ID_DEVICE.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_product, ASN1_OCTET_STRING,
-                 TAG_ATTESTATION_ID_PRODUCT.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_serial, ASN1_OCTET_STRING,
-                 TAG_ATTESTATION_ID_SERIAL.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_imei, ASN1_OCTET_STRING,
-                 TAG_ATTESTATION_ID_IMEI.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_meid, ASN1_OCTET_STRING,
-                 TAG_ATTESTATION_ID_MEID.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_manufacturer, ASN1_OCTET_STRING,
-                 TAG_ATTESTATION_ID_MANUFACTURER.masked_tag()),
-    ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_model, ASN1_OCTET_STRING,
-                 TAG_ATTESTATION_ID_MODEL.masked_tag()),
-} ASN1_SEQUENCE_END(KM_AUTH_LIST);
-DECLARE_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);
-DECLARE_ASN1_FUNCTIONS(KM_KEY_DESCRIPTION);
-
-class AttestationRecordContext {
-  protected:
-    virtual ~AttestationRecordContext() {}
-
-  public:
-    /**
-     * Returns the security level (SW or TEE) of this keymaster implementation.
-     */
-    virtual keymaster_security_level_t GetSecurityLevel() const {
-        return KM_SECURITY_LEVEL_SOFTWARE;
-    }
-
-    /**
-     * Verify that the device IDs provided in the attestation_params match the device's actual IDs
-     * and copy them to attestation. If *any* of the IDs do not match or verification is not
-     * possible, return KM_ERROR_CANNOT_ATTEST_IDS. If *all* IDs provided are successfully verified
-     * or no IDs were provided, return KM_ERROR_OK.
-     *
-     * If you do not support device ID attestation, ignore all arguments and return
-     * KM_ERROR_UNIMPLEMENTED.
-     */
-    virtual keymaster_error_t
-    VerifyAndCopyDeviceIds(const AuthorizationSet& /* attestation_params */,
-                           AuthorizationSet* /* attestation */) const {
-        return KM_ERROR_UNIMPLEMENTED;
-    }
-    /**
-     * Generate the current unique ID.
-     */
-    virtual keymaster_error_t GenerateUniqueId(uint64_t /*creation_date_time*/,
-                                               const keymaster_blob_t& /*application_id*/,
-                                               bool /*reset_since_rotation*/,
-                                               Buffer* /*unique_id*/) const {
-        return KM_ERROR_UNIMPLEMENTED;
-    }
-
-    /**
-     * Returns verified boot parameters for the Attestation Extension.  For hardware-based
-     * implementations, these will be the values reported by the bootloader. By default,  verified
-     * boot state is unknown, and KM_ERROR_UNIMPLEMENTED is returned.
-     */
-    virtual keymaster_error_t
-    GetVerifiedBootParams(keymaster_blob_t* /* verified_boot_key */,
-                          keymaster_blob_t* /* verified_boot_hash */,
-                          keymaster_verified_boot_t* /* verified_boot_state */,
-                          bool* /* device_locked */) const {
-        return KM_ERROR_UNIMPLEMENTED;
-    }
-};
-
-/**
- * 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";
-
-keymaster_error_t build_attestation_record(const AuthorizationSet& attestation_params,
-                                           AuthorizationSet software_enforced,
-                                           AuthorizationSet tee_enforced,
-                                           const AttestationRecordContext& context,
-                                           UniquePtr<uint8_t[]>* asn1_key_desc,
-                                           size_t* asn1_key_desc_len);
-
-/**
- * Helper functions for attestation record tests. Caller takes ownership of
- * |attestation_challenge->data| and |unique_id->data|, deallocate using delete[].
- */
-keymaster_error_t parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
-                                           uint32_t* attestation_version,  //
-                                           keymaster_security_level_t* attestation_security_level,
-                                           uint32_t* keymaster_version,
-                                           keymaster_security_level_t* keymaster_security_level,
-                                           keymaster_blob_t* attestation_challenge,
-                                           AuthorizationSet* software_enforced,
-                                           AuthorizationSet* tee_enforced,
-                                           keymaster_blob_t* unique_id);
-
-/**
- * Caller takes ownership of |verified_boot_key->data|, deallocate using delete[].
- */
-keymaster_error_t parse_root_of_trust(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
-                                      keymaster_blob_t* verified_boot_key,
-                                      keymaster_verified_boot_t* verified_boot_state,
-                                      bool* device_locked);
-
-keymaster_error_t build_auth_list(const AuthorizationSet& auth_list, KM_AUTH_LIST* record);
-
-keymaster_error_t extract_auth_list(const KM_AUTH_LIST* record, AuthorizationSet* auth_list);
-}  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_ATTESTATION_RECORD_H_
diff --git a/include/keymaster/authorization_set.h b/include/keymaster/authorization_set.h
index 11ffc30..5eebadf 100644
--- a/include/keymaster/authorization_set.h
+++ b/include/keymaster/authorization_set.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_AUTHORIZATION_SET_H_
-#define SYSTEM_KEYMASTER_AUTHORIZATION_SET_H_
+#pragma once
 
 #include <keymaster/UniquePtr.h>
 
@@ -82,6 +81,9 @@
     explicit AuthorizationSet(/* NOT const */ AuthorizationSetBuilder& builder);
 
     // Copy constructor.
+    // A copy constructor normal should call a base class copy constructor,
+    // but Serializable is special without copy constructor.
+    // NOLINTNEXTLINE(bugprone-copy-constructor-init)
     AuthorizationSet(const AuthorizationSet& set)
         : Serializable(), elems_capacity_(0), indirect_data_(nullptr), indirect_data_size_(0),
           indirect_data_capacity_(0), error_(OK) {
@@ -92,12 +94,11 @@
     }
 
     // Move constructor.
-    AuthorizationSet(AuthorizationSet&& set) : Serializable() {
-        MoveFrom(set);
-    }
+    AuthorizationSet(AuthorizationSet&& set) : Serializable() { MoveFrom(set); }
 
     // Copy assignment.
     AuthorizationSet& operator=(const AuthorizationSet& set) {
+        if (&set == this) return *this;
         Reinitialize(set.elems_, set.elems_size_);
         error_ = set.error_;
         return *this;
@@ -225,9 +226,7 @@
     /**
      * Returns true if the set contains at least one instance of \p tag
      */
-    bool Contains(keymaster_tag_t tag) const {
-        return find(tag) != -1;
-    }
+    bool Contains(keymaster_tag_t tag) const { return find(tag) != -1; }
 
     /**
      * Returns the number of \p tag entries.
@@ -253,8 +252,7 @@
     /**
      * Returns true if the set contains the specified tag and value.
      */
-    template <keymaster_tag_t Tag>
-    bool Contains(TypedTag<KM_UINT, Tag> tag, uint32_t val) const {
+    template <keymaster_tag_t Tag> bool Contains(TypedTag<KM_UINT, Tag> tag, uint32_t val) const {
         return ContainsIntValue(tag, val);
     }
 
@@ -322,8 +320,7 @@
      */
     template <keymaster_tag_t Tag, typename T>
     bool GetTagValue(TypedEnumTag<KM_ENUM_REP, Tag, T> tag, T* val) const {
-        if (GetTagCount(tag) != 1)
-            return false;
+        if (GetTagCount(tag) != 1) return false;
         return GetTagValueEnumRep(tag, 0, reinterpret_cast<uint32_t*>(val));
     }
 
@@ -540,6 +537,10 @@
         return Authorization(TAG_DIGEST, digest);
     }
 
+    AuthorizationSetBuilder& OaepMgfDigest(keymaster_digest_t digest) {
+        return Authorization(TAG_RSA_OAEP_MGF_DIGEST, digest);
+    }
+
     AuthorizationSetBuilder& BlockMode(keymaster_block_mode_t mode) {
         return Authorization(TAG_BLOCK_MODE, mode);
     }
@@ -638,14 +639,14 @@
 
 class AuthProxyIterator {
     constexpr static size_t invalid = ~size_t(0);
-public:
-    AuthProxyIterator()
-        : pos_(invalid), auth_set1_(nullptr), auth_set2_(nullptr) {}
+
+  public:
+    AuthProxyIterator() : pos_(invalid), auth_set1_(nullptr), auth_set2_(nullptr) {}
     AuthProxyIterator(const AuthorizationSet& auth_set1, const AuthorizationSet& auth_set2)
         : pos_(0), auth_set1_(&auth_set1), auth_set2_(&auth_set2) {}
     AuthProxyIterator(const AuthProxyIterator& rhs)
         : pos_(rhs.pos_), auth_set1_(rhs.auth_set1_), auth_set2_(rhs.auth_set2_) {}
-    ~AuthProxyIterator() {};
+    ~AuthProxyIterator(){};
     AuthProxyIterator& operator=(const AuthProxyIterator& rhs) {
         if (this != &rhs) {
             pos_ = rhs.pos_;
@@ -669,25 +670,23 @@
             return (*auth_set2_)[pos_ - auth_set1_->size()];
         }
     }
-    AuthProxyIterator operator++(int) {
+    const AuthProxyIterator operator++(int) {
         AuthProxyIterator dummy(*this);
         ++(*this);
         return dummy;
     }
-    const keymaster_key_param_t* operator->() const {
-        return &(*(*this));
-    }
+    const keymaster_key_param_t* operator->() const { return &(*(*this)); }
 
     bool operator==(const AuthProxyIterator& rhs) {
         if (pos_ == rhs.pos_) {
             return pos_ == invalid ||
-                    (auth_set1_ == rhs.auth_set1_ && auth_set2_ == rhs.auth_set2_);
-        } else return false;
+                   (auth_set1_ == rhs.auth_set1_ && auth_set2_ == rhs.auth_set2_);
+        } else
+            return false;
     }
-    bool operator!=(const AuthProxyIterator& rhs) {
-        return !operator==(rhs);
-    }
-private:
+    bool operator!=(const AuthProxyIterator& rhs) { return !operator==(rhs); }
+
+  private:
     size_t pos_;
     const AuthorizationSet* auth_set1_;
     const AuthorizationSet* auth_set2_;
@@ -708,10 +707,13 @@
                sw_enforced_.GetTagValue(forward<ARGS>(args)...);
     }
 
-    AuthProxyIterator begin() const {
-        return AuthProxyIterator(hw_enforced_, sw_enforced_);
+    template <typename... ARGS> bool GetTagCount(ARGS&&... args) const {
+        return hw_enforced_.GetTagCount(forward<ARGS>(args)...) ||
+               sw_enforced_.GetTagCount(forward<ARGS>(args)...);
     }
 
+    AuthProxyIterator begin() const { return AuthProxyIterator(hw_enforced_, sw_enforced_); }
+
     AuthProxyIterator end() const { return AuthProxyIterator(); }
 
     size_t size() const { return hw_enforced_.size() + sw_enforced_.size(); }
@@ -730,5 +732,3 @@
 };
 
 }  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_KEY_AUTHORIZATION_SET_H_
diff --git a/include/keymaster/contexts/keymaster0_passthrough_context.h b/include/keymaster/contexts/keymaster0_passthrough_context.h
deleted file mode 100644
index cad9df6..0000000
--- a/include/keymaster/contexts/keymaster0_passthrough_context.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
-**
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef CONTEXTS_KEYMASTER0_PASSTHROUGH_CONTEXT_H_
-#define CONTEXTS_KEYMASTER0_PASSTHROUGH_CONTEXT_H_
-
-#include <hardware/keymaster0.h>
-
-#include <keymaster/contexts/pure_soft_keymaster_context.h>
-#include <keymaster/legacy_support/ec_keymaster0_key.h>
-#include <keymaster/legacy_support/keymaster0_engine.h>
-#include <keymaster/legacy_support/rsa_keymaster0_key.h>
-
-namespace keymaster {
-
-class Keymaster0PassthroughContext : public PureSoftKeymasterContext {
-  public:
-    explicit Keymaster0PassthroughContext(keymaster0_device_t* dev) : PureSoftKeymasterContext() {
-        km0_engine_.reset(new Keymaster0Engine(dev));
-        rsa_factory_.reset(new RsaKeymaster0KeyFactory(this, km0_engine_.get()));
-        ec_factory_.reset(new EcdsaKeymaster0KeyFactory(this, km0_engine_.get()));
-    }
-
-  private:
-    UniquePtr<Keymaster0Engine> km0_engine_;
-};
-
-}  // namespace keymaster
-
-#endif  // CONTEXTS_KEYMASTER0_PASSTHROUGH_CONTEXT_H_
diff --git a/include/keymaster/contexts/keymaster1_passthrough_context.h b/include/keymaster/contexts/keymaster1_passthrough_context.h
index 820e01c..e5bd16b 100644
--- a/include/keymaster/contexts/keymaster1_passthrough_context.h
+++ b/include/keymaster/contexts/keymaster1_passthrough_context.h
@@ -23,7 +23,7 @@
 #include <hardware/keymaster1.h>
 #include <hardware/keymaster_defs.h>
 
-#include <keymaster/attestation_record.h>
+#include <keymaster/contexts/soft_attestation_context.h>
 #include <keymaster/keymaster_context.h>
 #include <keymaster/km_openssl/software_random_source.h>
 #include <keymaster/legacy_support/keymaster1_engine.h>
@@ -34,11 +34,13 @@
 namespace keymaster {
 
 class Keymaster1PassthroughContext : public KeymasterContext,
-                                     AttestationRecordContext,
+                                     public SoftAttestationContext,
                                      public SoftwareRandomSource,
                                      public SoftwareKeyBlobMaker {
   public:
-    explicit Keymaster1PassthroughContext(keymaster1_device_t* dev);
+    Keymaster1PassthroughContext(KmVersion version, keymaster1_device_t* dev);
+
+    KmVersion GetKmVersion() const override { return AttestationContext::GetKmVersion(); }
 
     /**
      * Sets the system version as reported by the system *itself*.  This is used to verify that the
@@ -106,8 +108,18 @@
      */
     KeymasterEnforcement* enforcement_policy() override;
 
-    keymaster_error_t GenerateAttestation(const Key& key, const AuthorizationSet& attest_params,
-                                          CertChainPtr* cert_chain) const override;
+    CertificateChain GenerateAttestation(const Key& key,  //
+                                         const AuthorizationSet& attest_params,
+                                         UniquePtr<Key> attest_key,
+                                         const KeymasterBlob& issuer_subject,
+                                         keymaster_error_t* error) const override;
+    CertificateChain GenerateSelfSignedCertificate(const Key& /* key */,
+                                                   const AuthorizationSet& /* cert_params */,
+                                                   bool /* fake_signature */,
+                                                   keymaster_error_t* error) const override {
+        *error = KM_ERROR_UNIMPLEMENTED;
+        return {};
+    }
 
     keymaster_error_t CreateKeyBlob(const AuthorizationSet& key_description,
                                     const keymaster_key_origin_t origin,
diff --git a/include/keymaster/contexts/keymaster2_passthrough_context.h b/include/keymaster/contexts/keymaster2_passthrough_context.h
index 8b889f3..37592f8 100644
--- a/include/keymaster/contexts/keymaster2_passthrough_context.h
+++ b/include/keymaster/contexts/keymaster2_passthrough_context.h
@@ -24,6 +24,7 @@
 #include <hardware/keymaster_defs.h>
 
 #include <keymaster/keymaster_context.h>
+#include <keymaster/km_version.h>
 #include <keymaster/legacy_support/keymaster_passthrough_engine.h>
 #include <keymaster/legacy_support/keymaster_passthrough_key.h>
 
@@ -31,7 +32,9 @@
 
 class Keymaster2PassthroughContext : public KeymasterContext {
   public:
-    explicit Keymaster2PassthroughContext(keymaster2_device_t* dev);
+    explicit Keymaster2PassthroughContext(KmVersion version, keymaster2_device_t* dev);
+
+    KmVersion GetKmVersion() const override { return version_; }
 
     /**
      * Sets the system version as reported by the system *itself*.  This is used to verify that the
@@ -99,8 +102,18 @@
      */
     KeymasterEnforcement* enforcement_policy() override;
 
-    keymaster_error_t GenerateAttestation(const Key& key, const AuthorizationSet& attest_params,
-                                          CertChainPtr* cert_chain) const override;
+    CertificateChain GenerateAttestation(const Key& key,  //
+                                         const AuthorizationSet& attest_params,
+                                         UniquePtr<Key> attest_key,
+                                         const KeymasterBlob& issuer_subject,
+                                         keymaster_error_t* error) const override;
+    CertificateChain GenerateSelfSignedCertificate(const Key& /* key */,
+                                                   const AuthorizationSet& /* cert_params */,
+                                                   bool /* fake_signature */,
+                                                   keymaster_error_t* error) const override {
+        *error = KM_ERROR_UNIMPLEMENTED;
+        return {};
+    }
 
     keymaster_error_t
     UnwrapKey(const KeymasterKeyBlob& wrapped_key_blob, const KeymasterKeyBlob& wrapping_key_blob,
@@ -115,6 +128,7 @@
     UniquePtr<KeymasterPassthroughEngine> engine_;
     uint32_t os_version_;
     uint32_t os_patchlevel_;
+    const KmVersion version_;
 };
 
 }  // namespace keymaster
diff --git a/include/keymaster/contexts/pure_soft_keymaster_context.h b/include/keymaster/contexts/pure_soft_keymaster_context.h
index a1951a0..2f7f098 100644
--- a/include/keymaster/contexts/pure_soft_keymaster_context.h
+++ b/include/keymaster/contexts/pure_soft_keymaster_context.h
@@ -14,19 +14,21 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_PURE_SOFT_KEYMASTER_CONTEXT_H_
-#define SYSTEM_KEYMASTER_PURE_SOFT_KEYMASTER_CONTEXT_H_
-
+#pragma once
 
 #include <memory>
 #include <string>
 
+#include <keymaster/attestation_context.h>
+#include <keymaster/contexts/pure_soft_remote_provisioning_context.h>
+#include <keymaster/contexts/soft_attestation_context.h>
 #include <keymaster/keymaster_context.h>
-#include <keymaster/attestation_record.h>
-#include <keymaster/km_openssl/software_random_source.h>
+#include <keymaster/km_openssl/attestation_record.h>
 #include <keymaster/km_openssl/soft_keymaster_enforcement.h>
-#include <keymaster/soft_key_factory.h>
+#include <keymaster/km_openssl/software_random_source.h>
+#include <keymaster/pure_soft_secure_key_storage.h>
 #include <keymaster/random_source.h>
+#include <keymaster/soft_key_factory.h>
 
 namespace keymaster {
 
@@ -38,16 +40,18 @@
 /**
  * SoftKeymasterContext provides the context for a non-secure implementation of AndroidKeymaster.
  */
-class PureSoftKeymasterContext: public KeymasterContext,
-        protected SoftwareKeyBlobMaker,
-        AttestationRecordContext,
-        SoftwareRandomSource {
+class PureSoftKeymasterContext : public KeymasterContext,
+                                 protected SoftwareKeyBlobMaker,
+                                 public SoftAttestationContext,
+                                 SoftwareRandomSource {
   public:
     // Security level must only be used for testing.
     explicit PureSoftKeymasterContext(
-        keymaster_security_level_t security_level = KM_SECURITY_LEVEL_SOFTWARE);
+        KmVersion version, keymaster_security_level_t security_level = KM_SECURITY_LEVEL_SOFTWARE);
     ~PureSoftKeymasterContext() override;
 
+    KmVersion GetKmVersion() const override { return AttestationContext::GetKmVersion(); }
+
     /*********************************************************************************************
      * Implement KeymasterContext
      */
@@ -67,17 +71,47 @@
     keymaster_error_t DeleteKey(const KeymasterKeyBlob& blob) const override;
     keymaster_error_t DeleteAllKeys() const override;
     keymaster_error_t AddRngEntropy(const uint8_t* buf, size_t length) const override;
-
-    keymaster_error_t GenerateAttestation(const Key& key,
-                                          const AuthorizationSet& attest_params,
-                                          CertChainPtr* cert_chain) const override;
-
-
+    CertificateChain GenerateAttestation(const Key& key, const AuthorizationSet& attest_params,
+                                         UniquePtr<Key> attest_key,
+                                         const KeymasterBlob& issuer_subject,
+                                         keymaster_error_t* error) const override;
+    CertificateChain GenerateSelfSignedCertificate(const Key& key,
+                                                   const AuthorizationSet& cert_params,
+                                                   bool fake_signature,
+                                                   keymaster_error_t* error) const override;
     KeymasterEnforcement* enforcement_policy() override {
         // SoftKeymaster does no enforcement; it's all done by Keystore.
         return &soft_keymaster_enforcement_;
     }
 
+    SecureKeyStorage* secure_key_storage() override { return pure_soft_secure_key_storage_.get(); }
+
+    RemoteProvisioningContext* GetRemoteProvisioningContext() const override {
+        return pure_soft_remote_provisioning_context_.get();
+    }
+
+    keymaster_error_t SetVendorPatchlevel(uint32_t vendor_patchlevel) override {
+        if (vendor_patchlevel_.has_value() && vendor_patchlevel != vendor_patchlevel_.value()) {
+            // Can't set patchlevel to a different value.
+            return KM_ERROR_INVALID_ARGUMENT;
+        }
+        vendor_patchlevel_ = vendor_patchlevel;
+        return KM_ERROR_OK;
+    }
+
+    keymaster_error_t SetBootPatchlevel(uint32_t boot_patchlevel) override {
+        if (boot_patchlevel_.has_value() && boot_patchlevel != boot_patchlevel_.value()) {
+            // Can't set patchlevel to a different value.
+            return KM_ERROR_INVALID_ARGUMENT;
+        }
+        boot_patchlevel_ = boot_patchlevel;
+        return KM_ERROR_OK;
+    }
+
+    std::optional<uint32_t> GetVendorPatchlevel() const override { return vendor_patchlevel_; }
+
+    std::optional<uint32_t> GetBootPatchlevel() const override { return boot_patchlevel_; }
+
     /*********************************************************************************************
      * Implement SoftwareKeyBlobMaker
      */
@@ -93,13 +127,10 @@
               KeymasterKeyBlob* wrapped_key_material) const override;
 
     /*********************************************************************************************
-     * Implement AttestationRecordContext
+     * Implement AttestationContext
      */
 
-    keymaster_error_t GetVerifiedBootParams(keymaster_blob_t* verified_boot_key,
-                                            keymaster_blob_t* verified_boot_hash,
-                                            keymaster_verified_boot_t* verified_boot_state,
-                                            bool* device_locked) const override;
+    const VerifiedBootParams* GetVerifiedBootParams(keymaster_error_t* error) const override;
 
     keymaster_security_level_t GetSecurityLevel() const override { return security_level_; }
 
@@ -111,10 +142,12 @@
     std::unique_ptr<KeyFactory> hmac_factory_;
     uint32_t os_version_;
     uint32_t os_patchlevel_;
+    std::optional<uint32_t> vendor_patchlevel_;
+    std::optional<uint32_t> boot_patchlevel_;
     SoftKeymasterEnforcement soft_keymaster_enforcement_;
-    keymaster_security_level_t security_level_;
+    const keymaster_security_level_t security_level_;
+    std::unique_ptr<SecureKeyStorage> pure_soft_secure_key_storage_;
+    std::unique_ptr<RemoteProvisioningContext> pure_soft_remote_provisioning_context_;
 };
 
 }  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_PURE_SOFT_KEYMASTER_CONTEXT_H_
diff --git a/include/keymaster/contexts/pure_soft_remote_provisioning_context.h b/include/keymaster/contexts/pure_soft_remote_provisioning_context.h
new file mode 100644
index 0000000..307795b
--- /dev/null
+++ b/include/keymaster/contexts/pure_soft_remote_provisioning_context.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <keymaster/remote_provisioning_context.h>
+
+#include <cppbor.h>
+
+namespace keymaster {
+
+/**
+ * SoftKeymasterContext provides the context for a non-secure implementation of AndroidKeymaster.
+ */
+class PureSoftRemoteProvisioningContext : public RemoteProvisioningContext {
+  public:
+    PureSoftRemoteProvisioningContext();
+    ~PureSoftRemoteProvisioningContext() override;
+    std::vector<uint8_t> DeriveBytesFromHbk(const std::string& context,
+                                            size_t numBytes) const override;
+    std::unique_ptr<cppbor::Map> CreateDeviceInfo() const override;
+    std::pair<std::vector<uint8_t>, cppbor::Array> GenerateBcc(bool testMode) const override;
+    std::optional<cppcose::HmacSha256>
+    GenerateHmacSha256(const cppcose::bytevec& input) const override;
+};
+
+}  // namespace keymaster
diff --git a/contexts/soft_attestation_cert.h b/include/keymaster/contexts/soft_attestation_cert.h
similarity index 85%
rename from contexts/soft_attestation_cert.h
rename to include/keymaster/contexts/soft_attestation_cert.h
index a508ff8..6273c63 100644
--- a/contexts/soft_attestation_cert.h
+++ b/include/keymaster/contexts/soft_attestation_cert.h
@@ -19,13 +19,13 @@
 #define SOFTWARE_CONTEXT_SOFT_ATTESTATION_CERT_H_
 
 #include <hardware/keymaster_defs.h>
+#include <keymaster/android_keymaster_utils.h>
 
 namespace keymaster {
 
 const keymaster_key_blob_t* getAttestationKey(keymaster_algorithm_t algorithm,
                                               keymaster_error_t* error);
-const keymaster_cert_chain_t* getAttestationChain(keymaster_algorithm_t algorithm,
-                                                  keymaster_error_t* error);
+CertificateChain getAttestationChain(keymaster_algorithm_t algorithm, keymaster_error_t* error);
 
-}
+}  // namespace keymaster
 #endif  // SOFTWARE_CONTEXT_SOFT_ATTESTATION_CERT_H_
diff --git a/include/keymaster/contexts/soft_attestation_context.h b/include/keymaster/contexts/soft_attestation_context.h
new file mode 100644
index 0000000..5c8db61
--- /dev/null
+++ b/include/keymaster/contexts/soft_attestation_context.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <keymaster/attestation_context.h>
+
+#include <keymaster/contexts/soft_attestation_cert.h>
+
+namespace keymaster {
+
+class SoftAttestationContext : public AttestationContext {
+  public:
+    explicit SoftAttestationContext(KmVersion version) : AttestationContext(version) {}
+
+    keymaster_security_level_t GetSecurityLevel() const override {
+        return KM_SECURITY_LEVEL_SOFTWARE;
+    }
+
+    const VerifiedBootParams* GetVerifiedBootParams(keymaster_error_t* error) const override;
+
+    KeymasterKeyBlob GetAttestationKey(keymaster_algorithm_t algorithm,
+                                       keymaster_error_t* error) const override {
+        return KeymasterKeyBlob(*getAttestationKey(algorithm, error));
+    }
+
+    CertificateChain GetAttestationChain(keymaster_algorithm_t algorithm,
+                                         keymaster_error_t* error) const override {
+        return getAttestationChain(algorithm, error);
+    }
+};
+
+}  // namespace keymaster
diff --git a/include/keymaster/contexts/soft_keymaster_context.h b/include/keymaster/contexts/soft_keymaster_context.h
index 588e3db..aae0542 100644
--- a/include/keymaster/contexts/soft_keymaster_context.h
+++ b/include/keymaster/contexts/soft_keymaster_context.h
@@ -14,44 +14,42 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_SOFT_KEYMASTER_CONTEXT_H_
-#define SYSTEM_KEYMASTER_SOFT_KEYMASTER_CONTEXT_H_
+#pragma once
 
 #include <memory>
 #include <string>
 
 #include <openssl/evp.h>
 
-#include <hardware/keymaster0.h>
 #include <hardware/keymaster1.h>
 
-#include <keymaster/attestation_record.h>
+#include <keymaster/attestation_context.h>
+#include <keymaster/contexts/soft_attestation_context.h>
 #include <keymaster/keymaster_context.h>
 #include <keymaster/km_openssl/software_random_source.h>
-#include <keymaster/soft_key_factory.h>
 #include <keymaster/random_source.h>
+#include <keymaster/soft_key_factory.h>
 
 namespace keymaster {
 
 class SoftKeymasterKeyRegistrations;
-class Keymaster0Engine;
 class Keymaster1Engine;
 class Key;
 
 /**
- * SoftKeymasterContext provides the context for a non-secure implementation of AndroidKeymaster.
+ * SoftKeymasterContext provides the context for a non-secure implementation of AndroidKeymaster
+ * that can wrap a Keymaster0 implementation or an incomplete Keymaster1 implementation (one that
+ * lacks support for all required digests).
  */
-class SoftKeymasterContext: public KeymasterContext, SoftwareKeyBlobMaker, SoftwareRandomSource,
-        AttestationRecordContext {
+class SoftKeymasterContext : public KeymasterContext,
+                             SoftwareKeyBlobMaker,
+                             SoftwareRandomSource,
+                             public SoftAttestationContext {
   public:
-    explicit SoftKeymasterContext(const std::string& root_of_trust = "SW");
+    explicit SoftKeymasterContext(KmVersion version, const std::string& root_of_trust = "SW");
     ~SoftKeymasterContext() override;
 
-    /**
-     * Use the specified HW keymaster0 device for the operations it supports.  Takes ownership of
-     * the specified device (will call keymaster0_device->common.close());
-     */
-    keymaster_error_t SetHardwareDevice(keymaster0_device_t* keymaster0_device);
+    KmVersion GetKmVersion() const override { return AttestationContext::GetKmVersion(); }
 
     /**
      * Use the specified HW keymaster1 device for performing undigested RSA and EC operations after
@@ -80,9 +78,14 @@
     keymaster_error_t DeleteAllKeys() const override;
     keymaster_error_t AddRngEntropy(const uint8_t* buf, size_t length) const override;
 
-    keymaster_error_t GenerateAttestation(const Key& key,
-                                          const AuthorizationSet& attest_params,
-                                          CertChainPtr* cert_chain) const override;
+    CertificateChain GenerateAttestation(const Key& key, const AuthorizationSet& attest_params,
+                                         UniquePtr<Key> attest_key,
+                                         const KeymasterBlob& issuer_subject,
+                                         keymaster_error_t* error) const override;
+    CertificateChain GenerateSelfSignedCertificate(const Key& key,
+                                                   const AuthorizationSet& cert_params,
+                                                   bool fake_signature,
+                                                   keymaster_error_t* error) const override;
 
     keymaster_error_t
     UnwrapKey(const KeymasterKeyBlob& wrapped_key_blob, const KeymasterKeyBlob& wrapping_key_blob,
@@ -110,12 +113,7 @@
                                             KeymasterKeyBlob* key_material,
                                             AuthorizationSet* hw_enforced,
                                             AuthorizationSet* sw_enforced) const;
-    keymaster_error_t ParseKeymaster0HwBlob(const KeymasterKeyBlob& blob,
-                                            KeymasterKeyBlob* key_material,
-                                            AuthorizationSet* hw_enforced,
-                                            AuthorizationSet* sw_enforced) const;
 
-    std::unique_ptr<Keymaster0Engine> km0_engine_;
     std::unique_ptr<Keymaster1Engine> km1_engine_;
     std::unique_ptr<KeyFactory> rsa_factory_;
     std::unique_ptr<KeyFactory> ec_factory_;
@@ -129,5 +127,3 @@
 };
 
 }  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_SOFT_KEYMASTER_CONTEXT_H_
diff --git a/include/keymaster/cppcose/cppcose.h b/include/keymaster/cppcose/cppcose.h
new file mode 100644
index 0000000..0f97388
--- /dev/null
+++ b/include/keymaster/cppcose/cppcose.h
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <array>
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+#include <cppbor.h>
+#include <cppbor_parse.h>
+
+#include <openssl/cipher.h>
+#include <openssl/curve25519.h>
+#include <openssl/digest.h>
+#include <openssl/hkdf.h>
+#include <openssl/hmac.h>
+#include <openssl/mem.h>
+#include <openssl/sha.h>
+
+namespace cppcose {
+
+template <typename T> class ErrMsgOr;
+using bytevec = std::vector<uint8_t>;
+using HmacSha256 = std::array<uint8_t, SHA256_DIGEST_LENGTH>;
+using HmacSha256Function = std::function<ErrMsgOr<HmacSha256>(const bytevec&)>;
+
+constexpr int kCoseSign1EntryCount = 4;
+constexpr int kCoseSign1ProtectedParams = 0;
+constexpr int kCoseSign1UnprotectedParams = 1;
+constexpr int kCoseSign1Payload = 2;
+constexpr int kCoseSign1Signature = 3;
+
+constexpr int kCoseMac0EntryCount = 4;
+constexpr int kCoseMac0ProtectedParams = 0;
+constexpr int kCoseMac0UnprotectedParams = 1;
+constexpr int kCoseMac0Payload = 2;
+constexpr int kCoseMac0Tag = 3;
+
+constexpr int kCoseEncryptEntryCount = 4;
+constexpr int kCoseEncryptProtectedParams = 0;
+constexpr int kCoseEncryptUnprotectedParams = 1;
+constexpr int kCoseEncryptPayload = 2;
+constexpr int kCoseEncryptRecipients = 3;
+
+enum Label : int {
+    ALGORITHM = 1,
+    KEY_ID = 4,
+    IV = 5,
+    COSE_KEY = -1,
+};
+
+enum CoseKeyAlgorithm : int {
+    AES_GCM_256 = 3,
+    HMAC_256 = 5,
+    ES256 = -7,  // ECDSA with SHA-256
+    EDDSA = -8,
+    ECDH_ES_HKDF_256 = -25,
+};
+
+enum CoseKeyCurve : int { P256 = 1, X25519 = 4, ED25519 = 6 };
+enum CoseKeyType : int { OCTET_KEY_PAIR = 1, EC2 = 2, SYMMETRIC_KEY = 4 };
+enum CoseKeyOps : int { SIGN = 1, VERIFY = 2, ENCRYPT = 3, DECRYPT = 4 };
+
+constexpr int kAesGcmNonceLength = 12;
+constexpr int kAesGcmTagSize = 16;
+constexpr int kAesGcmKeySize = 32;
+constexpr int kAesGcmKeySizeBits = 256;
+
+template <typename T> class ErrMsgOr {
+  public:
+    ErrMsgOr(std::string errMsg)  // NOLINT(google-explicit-constructor)
+        : errMsg_(std::move(errMsg)) {}
+    ErrMsgOr(const char* errMsg)  // NOLINT(google-explicit-constructor)
+        : errMsg_(errMsg) {}
+    ErrMsgOr(T val)  // NOLINT(google-explicit-constructor)
+        : value_(std::move(val)) {}
+
+    explicit operator bool() const { return value_.has_value(); }
+
+    T* operator->() & {
+        assert(value_);
+        return &value_.value();
+    }
+    T& operator*() & {
+        assert(value_);
+        return value_.value();
+    };
+    T&& operator*() && {
+        assert(value_);
+        return std::move(value_).value();
+    };
+
+    const std::string& message() { return errMsg_; }
+    std::string moveMessage() { return std::move(errMsg_); }
+
+    T moveValue() {
+        assert(value_);
+        return std::move(value_).value();
+    }
+
+  private:
+    std::string errMsg_;
+    std::optional<T> value_;
+};
+
+class CoseKey {
+  public:
+    CoseKey() {}
+    CoseKey(const CoseKey&) = delete;
+    CoseKey(CoseKey&&) = default;
+
+    enum Label : int {
+        KEY_TYPE = 1,
+        KEY_ID = 2,
+        ALGORITHM = 3,
+        KEY_OPS = 4,
+        CURVE = -1,
+        PUBKEY_X = -2,
+        PUBKEY_Y = -3,
+        PRIVATE_KEY = -4,
+        TEST_KEY = -70000  // Application-defined
+    };
+
+    static ErrMsgOr<CoseKey> parse(const bytevec& coseKey) {
+        auto [parsedKey, _, errMsg] = cppbor::parse(coseKey);
+        if (!parsedKey) return errMsg + " when parsing key";
+        if (!parsedKey->asMap()) return "CoseKey must be a map";
+        return CoseKey(static_cast<cppbor::Map*>(parsedKey.release()));
+    }
+
+    static ErrMsgOr<CoseKey> parse(const bytevec& coseKey, CoseKeyType expectedKeyType,
+                                   CoseKeyAlgorithm expectedAlgorithm, CoseKeyCurve expectedCurve) {
+        auto key = parse(coseKey);
+        if (!key) return key;
+
+        if (!key->checkIntValue(CoseKey::KEY_TYPE, expectedKeyType) ||
+            !key->checkIntValue(CoseKey::ALGORITHM, expectedAlgorithm) ||
+            !key->checkIntValue(CoseKey::CURVE, expectedCurve)) {
+            return "Unexpected key type:";
+        }
+
+        return key;
+    }
+
+    static ErrMsgOr<CoseKey> parseEd25519(const bytevec& coseKey) {
+        auto key = parse(coseKey, OCTET_KEY_PAIR, EDDSA, ED25519);
+        if (!key) return key;
+
+        auto& pubkey = key->getMap().get(PUBKEY_X);
+        if (!pubkey || !pubkey->asBstr() ||
+            pubkey->asBstr()->value().size() != ED25519_PUBLIC_KEY_LEN) {
+            return "Invalid Ed25519 public key";
+        }
+
+        return key;
+    }
+
+    static ErrMsgOr<CoseKey> parseX25519(const bytevec& coseKey, bool requireKid) {
+        auto key = parse(coseKey, OCTET_KEY_PAIR, ECDH_ES_HKDF_256, X25519);
+        if (!key) return key;
+
+        auto& pubkey = key->getMap().get(PUBKEY_X);
+        if (!pubkey || !pubkey->asBstr() ||
+            pubkey->asBstr()->value().size() != X25519_PUBLIC_VALUE_LEN) {
+            return "Invalid X25519 public key";
+        }
+
+        auto& kid = key->getMap().get(KEY_ID);
+        if (requireKid && (!kid || !kid->asBstr())) {
+            return "Missing KID";
+        }
+
+        return key;
+    }
+
+    static ErrMsgOr<CoseKey> parseP256(const bytevec& coseKey) {
+        auto key = parse(coseKey, EC2, ES256, P256);
+        if (!key) return key;
+
+        auto& pubkey_x = key->getMap().get(PUBKEY_X);
+        auto& pubkey_y = key->getMap().get(PUBKEY_Y);
+        if (!pubkey_x || !pubkey_y || !pubkey_x->asBstr() || !pubkey_y->asBstr() ||
+            pubkey_x->asBstr()->value().size() != 32 || pubkey_y->asBstr()->value().size() != 32) {
+            return "Invalid P256 public key";
+        }
+
+        return key;
+    }
+
+    std::optional<int> getIntValue(Label label) {
+        const auto& value = key_->get(label);
+        if (!value || !value->asInt()) return {};
+        return value->asInt()->value();
+    }
+
+    std::optional<bytevec> getBstrValue(Label label) {
+        const auto& value = key_->get(label);
+        if (!value || !value->asBstr()) return {};
+        return value->asBstr()->value();
+    }
+
+    const cppbor::Map& getMap() const { return *key_; }
+    cppbor::Map&& moveMap() { return std::move(*key_); }
+
+    bool checkIntValue(Label label, int expectedValue) {
+        const auto& value = key_->get(label);
+        return value && value->asInt() && value->asInt()->value() == expectedValue;
+    }
+
+    void add(Label label, int value) { key_->add(label, value); }
+    void add(Label label, bytevec value) { key_->add(label, std::move(value)); }
+
+    bytevec encode() { return key_->canonicalize().encode(); }
+
+  private:
+    explicit CoseKey(cppbor::Map* parsedKey) : key_(parsedKey) {}
+
+    // This is the full parsed key structure.
+    std::unique_ptr<cppbor::Map> key_;
+};
+
+// Utility function for generating an HMAC given a key and some input
+// data. Returns std::nullopt on error
+ErrMsgOr<HmacSha256> generateHmacSha256(const bytevec& key, const bytevec& data);
+
+ErrMsgOr<HmacSha256> generateCoseMac0Mac(HmacSha256Function macFunction, const bytevec& externalAad,
+                                         const bytevec& payload);
+ErrMsgOr<cppbor::Array> constructCoseMac0(HmacSha256Function macFunction,
+                                          const bytevec& externalAad, const bytevec& payload);
+ErrMsgOr<bytevec /* payload */> verifyAndParseCoseMac0(const cppbor::Item* macItem,
+                                                       const bytevec& macKey);
+
+ErrMsgOr<bytevec> createCoseSign1Signature(const bytevec& key, const bytevec& protectedParams,
+                                           const bytevec& payload, const bytevec& aad);
+ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, const bytevec& payload,
+                                           const bytevec& aad);
+ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, cppbor::Map extraProtectedFields,
+                                           const bytevec& payload, const bytevec& aad);
+/**
+ * Verify and parse a COSE_Sign1 message, returning the payload.
+ *
+ * @param coseSign1 is the COSE_Sign1 to verify and parse.
+ *
+ * @param signingCoseKey is a CBOR-encoded COSE_Key to use to verify the signature.  The bytevec may
+ *        be empty, in which case the function assumes that coseSign1's payload is the COSE_Key to
+ *        use, i.e. that coseSign1 is a self-signed "certificate".
+ */
+ErrMsgOr<bytevec /* payload */> verifyAndParseCoseSign1(const cppbor::Array* coseSign1,
+                                                        const bytevec& signingCoseKey,
+                                                        const bytevec& aad);
+
+ErrMsgOr<bytevec> createCoseEncryptCiphertext(const bytevec& key, const bytevec& nonce,
+                                              const bytevec& protectedParams, const bytevec& aad);
+ErrMsgOr<cppbor::Array> constructCoseEncrypt(const bytevec& key, const bytevec& nonce,
+                                             const bytevec& plaintextPayload, const bytevec& aad,
+                                             cppbor::Array recipients);
+ErrMsgOr<std::pair<bytevec /* pubkey */, bytevec /* key ID */>>
+getSenderPubKeyFromCoseEncrypt(const cppbor::Item* encryptItem);
+inline ErrMsgOr<std::pair<bytevec /* pubkey */, bytevec /* key ID */>>
+getSenderPubKeyFromCoseEncrypt(const std::unique_ptr<cppbor::Item>& encryptItem) {
+    return getSenderPubKeyFromCoseEncrypt(encryptItem.get());
+}
+
+ErrMsgOr<bytevec /* plaintextPayload */>
+decryptCoseEncrypt(const bytevec& key, const cppbor::Item* encryptItem, const bytevec& aad);
+
+ErrMsgOr<bytevec> x25519_HKDF_DeriveKey(const bytevec& senderPubKey, const bytevec& senderPrivKey,
+                                        const bytevec& recipientPubKey, bool senderIsA);
+
+ErrMsgOr<bytevec /* ciphertextWithTag */> aesGcmEncrypt(const bytevec& key, const bytevec& nonce,
+                                                        const bytevec& aad,
+                                                        const bytevec& plaintext);
+ErrMsgOr<bytevec /* plaintext */> aesGcmDecrypt(const bytevec& key, const bytevec& nonce,
+                                                const bytevec& aad,
+                                                const bytevec& ciphertextWithTag);
+
+}  // namespace cppcose
diff --git a/include/keymaster/key_blob_utils/auth_encrypted_key_blob.h b/include/keymaster/key_blob_utils/auth_encrypted_key_blob.h
index d69d136..e328818 100644
--- a/include/keymaster/key_blob_utils/auth_encrypted_key_blob.h
+++ b/include/keymaster/key_blob_utils/auth_encrypted_key_blob.h
@@ -14,30 +14,77 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_AUTH_ENCRYPTED_KEY_BLOB_H_
-#define SYSTEM_KEYMASTER_AUTH_ENCRYPTED_KEY_BLOB_H_
+#pragma once
 
 #include <hardware/keymaster_defs.h>
 
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/authorization_set.h>
+
 namespace keymaster {
 
-class AuthorizationSet;
 class Buffer;
-template<typename BlobType> struct TKeymasterBlob;
-typedef TKeymasterBlob<keymaster_key_blob_t> KeymasterKeyBlob;
+class RandomSource;
 
-keymaster_error_t SerializeAuthEncryptedBlob(const KeymasterKeyBlob& encrypted_key_material,
-                                             const AuthorizationSet& hw_enforced,
-                                             const AuthorizationSet& sw_enforced,
-                                             const Buffer& nonce, const Buffer& tag,
-                                             KeymasterKeyBlob* key_blob);
+// Define the formats this code knows about.  Note that "format" here implies both structure and KEK
+// derivation and encryption algorithm, though the KEK derivation and encryption is performed prior
+// to serialization.
+enum AuthEncryptedBlobFormat : uint8_t {
+    AES_OCB = 0,
+    AES_GCM_WITH_SW_ENFORCED = 1,
+};
 
-keymaster_error_t DeserializeAuthEncryptedBlob(const KeymasterKeyBlob& key_blob,
-                                               KeymasterKeyBlob* encrypted_key_material,
-                                               AuthorizationSet* hw_enforced,
-                                               AuthorizationSet* sw_enforced, Buffer* nonce,
-                                               Buffer* tag);
+struct MoveOnly {
+    MoveOnly() = default;
+    MoveOnly(const MoveOnly&) = delete;
+    MoveOnly(MoveOnly&&) = default;
+
+    MoveOnly& operator=(MoveOnly&&) = default;
+    void operator=(const MoveOnly&) = delete;
+};
+
+struct EncryptedKey : private MoveOnly {
+    AuthEncryptedBlobFormat format;
+    KeymasterKeyBlob ciphertext;
+    Buffer nonce;
+    Buffer tag;
+};
+
+struct DeserializedKey : private MoveOnly {
+    EncryptedKey encrypted_key;
+    AuthorizationSet hw_enforced;
+    AuthorizationSet sw_enforced;
+};
+
+/**
+ * Encrypt the provided plaintext with format `format`, using the provided authorization lists and
+ * master_key to derive the key encryption key.
+ */
+EncryptedKey EncryptKey(const KeymasterKeyBlob& plaintext, AuthEncryptedBlobFormat format,
+                        const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+                        const AuthorizationSet& hidden, const KeymasterKeyBlob& master_key,
+                        const RandomSource& random, keymaster_error_t* error);
+
+/**
+ * Serialize `encrypted_key` (which contains necessary nonce & tag information),
+ * along with the associated authorization data into a blob.
+ */
+KeymasterKeyBlob SerializeAuthEncryptedBlob(const EncryptedKey& encrypted_key,
+                                            const AuthorizationSet& hw_enforced,
+                                            const AuthorizationSet& sw_enforced,
+                                            keymaster_error_t* error);
+
+/**
+ * Deserialize a blob, retrieving the key ciphertext, decryption parameters and associated
+ * authorization lists.
+ */
+DeserializedKey DeserializeAuthEncryptedBlob(const KeymasterKeyBlob& key_blob,
+                                             keymaster_error_t* error);
+
+/**
+ * Decrypt key material from the Deserialized data in `key'.
+ */
+KeymasterKeyBlob DecryptKey(const DeserializedKey& key, const AuthorizationSet& hidden,
+                            const KeymasterKeyBlob& master_key, keymaster_error_t* error);
 
 }  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_AUTH_ENCRYPTED_KEY_BLOB_H_
diff --git a/include/keymaster/key_blob_utils/integrity_assured_key_blob.h b/include/keymaster/key_blob_utils/integrity_assured_key_blob.h
index 8cc6050..8257195 100644
--- a/include/keymaster/key_blob_utils/integrity_assured_key_blob.h
+++ b/include/keymaster/key_blob_utils/integrity_assured_key_blob.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_INTEGRITY_ASSURED_KEY_BLOB_
-#define SYSTEM_KEYMASTER_INTEGRITY_ASSURED_KEY_BLOB_
+#pragma once
 
 #include <hardware/keymaster_defs.h>
 
@@ -23,7 +22,7 @@
 
 class AuthorizationSet;
 class Buffer;
-template<typename BlobType> struct TKeymasterBlob;
+template <typename BlobType> struct TKeymasterBlob;
 typedef TKeymasterBlob<keymaster_key_blob_t> KeymasterKeyBlob;
 
 keymaster_error_t SerializeIntegrityAssuredBlob(const KeymasterKeyBlob& key_material,
@@ -43,6 +42,4 @@
                                                               AuthorizationSet* hw_enforced,
                                                               AuthorizationSet* sw_enforced);
 
-}  // namespace keymaster;
-
-#endif  // SYSTEM_KEYMASTER_INTEGRITY_ASSURED_KEY_BLOB_
+}  // namespace keymaster
diff --git a/include/keymaster/key_blob_utils/ocb_utils.h b/include/keymaster/key_blob_utils/ocb_utils.h
index 5a5b661..7eb555a 100644
--- a/include/keymaster/key_blob_utils/ocb_utils.h
+++ b/include/keymaster/key_blob_utils/ocb_utils.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_OCB_UTILS_H_
-#define SYSTEM_KEYMASTER_OCB_UTILS_H_
+#pragma once
 
 #include "ae.h"
 
@@ -26,7 +25,7 @@
 namespace keymaster {
 
 class AuthorizationSet;
-template<typename BlobType> struct TKeymasterBlob;
+template <typename BlobType> struct TKeymasterBlob;
 typedef TKeymasterBlob<keymaster_key_blob_t> KeymasterKeyBlob;
 
 static const int OCB_NONCE_LENGTH = 12;
@@ -45,5 +44,3 @@
                                 const Buffer& tag, KeymasterKeyBlob* plaintext);
 
 }  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_OCB_UTILS_H_
diff --git a/include/keymaster/key_blob_utils/software_keyblobs.h b/include/keymaster/key_blob_utils/software_keyblobs.h
index 15dc0a4..962ed5a 100644
--- a/include/keymaster/key_blob_utils/software_keyblobs.h
+++ b/include/keymaster/key_blob_utils/software_keyblobs.h
@@ -15,12 +15,13 @@
 ** limitations under the License.
 */
 
-#ifndef KEY_BLOB_UTILS_SOFTWARE_KEYBLOBS_H_
-#define KEY_BLOB_UTILS_SOFTWARE_KEYBLOBS_H_
+#pragma once
+
+#include <optional>
 
 #include <hardware/keymaster_defs.h>
-#include <openssl/base.h>
 #include <keymaster/android_keymaster_utils.h>
+#include <openssl/base.h>
 
 namespace keymaster {
 
@@ -35,8 +36,7 @@
                                             AuthorizationSet* hidden,
                                             const KeymasterBlob& root_of_trust);
 
-keymaster_error_t FakeKeyAuthorizations(EVP_PKEY* pubkey,
-                                        AuthorizationSet* hw_enforced,
+keymaster_error_t FakeKeyAuthorizations(EVP_PKEY* pubkey, AuthorizationSet* hw_enforced,
                                         AuthorizationSet* sw_enforced);
 
 keymaster_error_t ParseOldSoftkeymasterBlob(const KeymasterKeyBlob& blob,
@@ -44,20 +44,31 @@
                                             AuthorizationSet* hw_enforced,
                                             AuthorizationSet* sw_enforced);
 
-keymaster_error_t ParseOcbAuthEncryptedBlob(const KeymasterKeyBlob& blob,
-                                            const AuthorizationSet& hidden,
-                                            KeymasterKeyBlob* key_material,
-                                            AuthorizationSet* hw_enforced,
-                                            AuthorizationSet* sw_enforced);
+keymaster_error_t ParseAuthEncryptedBlob(const KeymasterKeyBlob& blob,
+                                         const AuthorizationSet& hidden,
+                                         KeymasterKeyBlob* key_material,
+                                         AuthorizationSet* hw_enforced,
+                                         AuthorizationSet* sw_enforced);
 
 keymaster_error_t SetKeyBlobAuthorizations(const AuthorizationSet& key_description,
                                            keymaster_key_origin_t origin, uint32_t os_version,
                                            uint32_t os_patchlevel, AuthorizationSet* hw_enforced,
                                            AuthorizationSet* sw_enforced);
-keymaster_error_t UpgradeSoftKeyBlob(const UniquePtr<Key>& key,
-                                     const uint32_t os_version, const uint32_t os_patchlevel,
+
+keymaster_error_t ExtendKeyBlobAuthorizations(AuthorizationSet* hw_enforced,
+                                              AuthorizationSet* sw_enforced,
+                                              std::optional<uint32_t> vendor_patchlevel,
+                                              std::optional<uint32_t> boot_patchlevel);
+
+keymaster_error_t UpgradeSoftKeyBlob(const UniquePtr<Key>& key, const uint32_t os_version,
+                                     const uint32_t os_patchlevel,
                                      const AuthorizationSet& upgrade_params,
                                      KeymasterKeyBlob* upgraded_key);
-} // namespace keymaster
 
-#endif  // KEY_BLOB_UTILS_SOFTWARE_KEYBLOBS_H_
+keymaster_error_t FullUpgradeSoftKeyBlob(const UniquePtr<Key>& key, const uint32_t os_version,
+                                         uint32_t os_patchlevel,
+                                         std::optional<uint32_t> vendor_patchlevel,
+                                         std::optional<uint32_t> boot_patchlevel,
+                                         const AuthorizationSet& upgrade_params,
+                                         KeymasterKeyBlob* upgraded_key);
+}  // namespace keymaster
diff --git a/include/keymaster/key_factory.h b/include/keymaster/key_factory.h
index a9fcdac..ad9e161 100644
--- a/include/keymaster/key_factory.h
+++ b/include/keymaster/key_factory.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_KEY_FACTORY_H_
-#define SYSTEM_KEYMASTER_KEY_FACTORY_H_
+#pragma once
 
 #include <hardware/keymaster_defs.h>
 #include <keymaster/authorization_set.h>
@@ -25,7 +24,7 @@
 class Key;
 class KeymasterContext;
 class OperationFactory;
-template<typename BlobType> struct TKeymasterBlob;
+template <typename BlobType> struct TKeymasterBlob;
 typedef TKeymasterBlob<keymaster_key_blob_t> KeymasterKeyBlob;
 
 /**
@@ -38,15 +37,22 @@
 
     // Factory methods.
     virtual keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
-                                          KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
-                                          AuthorizationSet* sw_enforced) const = 0;
+                                          UniquePtr<Key> attestation_signing_key,
+                                          const KeymasterBlob& issuer_subject,
+                                          KeymasterKeyBlob* key_blob,  //
+                                          AuthorizationSet* hw_enforced,
+                                          AuthorizationSet* sw_enforced,
+                                          CertificateChain* cert_chain) const = 0;
 
-    virtual keymaster_error_t ImportKey(const AuthorizationSet& key_description,
+    virtual keymaster_error_t ImportKey(const AuthorizationSet& key_description,  //
                                         keymaster_key_format_t input_key_material_format,
                                         const KeymasterKeyBlob& input_key_material,
+                                        UniquePtr<Key> attestation_signing_key,  //
+                                        const KeymasterBlob& issuer_subject,
                                         KeymasterKeyBlob* output_key_blob,
                                         AuthorizationSet* hw_enforced,
-                                        AuthorizationSet* sw_enforced) const = 0;
+                                        AuthorizationSet* sw_enforced,
+                                        CertificateChain* cert_chain) const = 0;
 
     virtual keymaster_error_t LoadKey(KeymasterKeyBlob&& key_material,
                                       const AuthorizationSet& additional_params,
@@ -62,5 +68,3 @@
 };
 
 }  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_KEY_FACTORY_H_
diff --git a/include/keymaster/keymaster_configuration.h b/include/keymaster/keymaster_configuration.h
index 69738fd..32da101 100644
--- a/include/keymaster/keymaster_configuration.h
+++ b/include/keymaster/keymaster_configuration.h
@@ -48,16 +48,23 @@
 /**
  * Parses OS patch level string, returning year and month in integer form. For example, "2016-03-25"
  * will be returned as 201603. Returns 0 if the string doesn't contain a date in the form
- * YYYY-MM-DD.
+ * YYYY-MM-DD; returns YYYMM on success.
  */
 uint32_t GetOsPatchlevel(const char* patchlevel_string);
 
 /**
  * Retrieves and parses OS patch level from build properties. Returns 0 if the string doesn't
- * contain a date in the form YYYY-MM-DD.
+ * contain a date in the form YYYY-MM-DD; returns YYYYMM on success.
  */
 uint32_t GetOsPatchlevel();
 
+/**
+ * Retrieves and parses vendor patch level from build properties (which may require SELinux
+ * permission). Returns 0 if the string doesn't contain a date in the form YYYY-MM-DD; returns
+ * YYYYMMDD on success.
+ */
+uint32_t GetVendorPatchlevel();
+
 }  // namespace keymaster
 
 #endif  // SYSTEM_KEYMASTER_KEYMASTER_CONFIGURATION_H_
diff --git a/include/keymaster/keymaster_context.h b/include/keymaster/keymaster_context.h
index c33d20b..65c1b73 100644
--- a/include/keymaster/keymaster_context.h
+++ b/include/keymaster/keymaster_context.h
@@ -17,11 +17,16 @@
 #ifndef SYSTEM_KEYMASTER_KEYMASTER_CONTEXT_H_
 #define SYSTEM_KEYMASTER_KEYMASTER_CONTEXT_H_
 
+#include <optional>
+
 #include <assert.h>
 
 #include <hardware/keymaster_defs.h>
 #include <keymaster/android_keymaster_utils.h>
 #include <keymaster/keymaster_enforcement.h>
+#include <keymaster/km_version.h>
+#include <keymaster/remote_provisioning_context.h>
+#include <keymaster/secure_key_storage.h>
 
 namespace keymaster {
 
@@ -67,6 +72,15 @@
     virtual ~KeymasterContext(){};
 
     /**
+     * Returns the Keymaster/KeyMint version we're currently implementing.
+     *
+     * Because AndroidKeymaster supports multiple versions of Keymaster/KeyMint, with slightly
+     * different behavior, we sometimes need to branch based on the version currently being
+     * implemented.  This method provides the currently-implemented version.
+     */
+    virtual KmVersion GetKmVersion() const = 0;
+
+    /**
      * Sets the system version as reported by the system *itself*.  This is used to verify that the
      * system believes itself to be running the same version that is reported by the bootloader, in
      * hardware implementations.  For SoftKeymasterDevice, this sets the version information used.
@@ -134,9 +148,33 @@
      */
     virtual KeymasterEnforcement* enforcement_policy() = 0;
 
-    virtual keymaster_error_t GenerateAttestation(const Key& key,
-                                                  const AuthorizationSet& attest_params,
-                                                  CertChainPtr* cert_chain) const = 0;
+    /**
+     * Generate an attestation certificate, with chain.
+     *
+     * If attest_key is null, the certificate will be signed with the factory attestation key (from
+     * AttestationContext) and have the issuer subject set to the subject name from the signing key
+     * certificate.  If attest_key is non-null, it will be used to sign the certificate and the
+     * provided issuer subject will be used (must contain a DER-encoded X.509 NAME).
+     */
+    virtual CertificateChain GenerateAttestation(const Key& key,
+                                                 const AuthorizationSet& attest_params,
+                                                 UniquePtr<Key> attest_key,
+                                                 const KeymasterBlob& issuer_subject,
+                                                 keymaster_error_t* error) const = 0;
+
+    /**
+     * Generate a self-signed certificate.  If fake_signature is true, a fake signature is installed
+     * in the certificate, rather than an actual self-signature.  The fake signature will not
+     * verify, of course.  In this case the certificate is primarily a way to convey the public key.
+     *
+     * Note that although the return type is CertificateChain, this is for convenience and
+     * consistency with GenerateAttestation, the chain never contains more than a single
+     * certificate.
+     */
+    virtual CertificateChain GenerateSelfSignedCertificate(const Key& key,
+                                                           const AuthorizationSet& cert_params,
+                                                           bool fake_signature,
+                                                           keymaster_error_t* error) const = 0;
 
     virtual keymaster_error_t
     UnwrapKey(const KeymasterKeyBlob& wrapped_key_blob, const KeymasterKeyBlob& wrapping_key_blob,
@@ -144,6 +182,69 @@
               AuthorizationSet* wrapped_key_params, keymaster_key_format_t* wrapped_key_format,
               KeymasterKeyBlob* wrapped_key_material) const = 0;
 
+    /**
+     * Return the secure key storage for this context, or null if there is no available secure key
+     * storage.
+     */
+    virtual SecureKeyStorage* secure_key_storage() { return nullptr; }
+
+    /**
+     * Checks that the data in |input_data| of size |input_data_size| matches the
+     * confirmation token given by |confirmation_token|.
+     *
+     * Note that |input_data| will already contain the prefixed message tag
+     * "confirmation token" (not including NUL byte) so all the implementation
+     * of this method needs to do is to calculate HMAC-SHA256 over |input_data|
+     * and compare it with |confirmation_token|. To do this the implementation
+     * needs access to the secret key shared with the ConfirmationUI TA.
+     *
+     * Returns KM_ERROR_OK if |input_data| matches |confirmation_token|,
+     * KM_ERROR_NO_USER_CONFIRMATION if it doesn't, and if memory allocation
+     * fails KM_ERROR_MEMORY_ALLOCATION_FAILED. If not implemented then
+     * KM_ERROR_UNIMPLEMENTED is returned.
+     */
+    virtual keymaster_error_t
+    CheckConfirmationToken(const uint8_t* /*input_data*/, size_t /*input_data_size*/,
+                           const uint8_t /*confirmation_token*/[kConfirmationTokenSize]) const {
+        return KM_ERROR_UNIMPLEMENTED;
+    }
+
+    /**
+     * Return the remote provisioning context object, or null if remote provisioning is not
+     * supported.
+     */
+    virtual RemoteProvisioningContext* GetRemoteProvisioningContext() const { return nullptr; }
+
+    /**
+     * Sets the vendor patchlevel (format YYYYMMDD) for the implementation. This value should
+     * be set by the HAL service at start of day.  A subsequent attempt to set a different
+     * value will return KM_ERROR_INVALID_ARGUMENT.
+     */
+    virtual keymaster_error_t SetVendorPatchlevel(uint32_t /* vendor_patchlevel */) {
+        return KM_ERROR_UNIMPLEMENTED;
+    }
+
+    /**
+     * Sets the boot patchlevel (format YYYYMMDD) for the implementation. This value should be set
+     * by the bootloader.  A subsequent to set a different value will return
+     * KM_ERROR_INVALID_ARGUMENT;
+     */
+    virtual keymaster_error_t SetBootPatchlevel(uint32_t /* boot_patchlevel */) {
+        return KM_ERROR_UNIMPLEMENTED;
+    }
+
+    /**
+     * Returns the vendor patchlevel, as set by the HAL service using SetVendorPatchlevel.
+     */
+    virtual std::optional<uint32_t> GetVendorPatchlevel() const { return std::nullopt; }
+
+    /**
+     * Returns the boot patchlevel. For hardware-based implementations this will be the value set by
+     * the bootloader. For software implementations this will be the information set by
+     * SetBootPatchLevel.
+     */
+    virtual std::optional<uint32_t> GetBootPatchlevel() const { return std::nullopt; }
+
   private:
     // Uncopyable.
     KeymasterContext(const KeymasterContext&);
diff --git a/include/keymaster/keymaster_enforcement.h b/include/keymaster/keymaster_enforcement.h
index 4e33aff..1d783ba 100644
--- a/include/keymaster/keymaster_enforcement.h
+++ b/include/keymaster/keymaster_enforcement.h
@@ -133,6 +133,11 @@
     virtual uint64_t get_current_time_ms() const = 0;
 
     /*
+     * Get whether or not we're in early boot.  See early_boot_ended() below.
+     */
+    bool in_early_boot() const { return in_early_boot_; }
+
+    /*
      * Get current time in seconds from some starting point.  This value is used to compute relative
      * times between events.  It must be monotonically increasing, and must not skip or lag.  It
      * need not have any relation to any external time standard (other than the duration of
@@ -171,14 +176,35 @@
     VerifyAuthorization(const VerifyAuthorizationRequest& request) = 0;
 
     /**
-     * Creates a key ID for use in subsequent calls to AuthorizeOperation.  AndroidKeymaster uses
-     * this method for creating key IDs. The generated id must be stable in that the same key_blob
-     * bits yield the same keyid.
+     * Generate TimestampToken for secure clock instance.
+     */
+    virtual keymaster_error_t GenerateTimestampToken(TimestampToken* token);
+
+    /**
+     * Creates a key ID for use in subsequent calls to AuthorizeOperation.  AndroidKeymaster
+     * uses this method for creating key IDs. The generated id must be stable in that the same
+     * key_blob bits yield the same keyid.
      *
      * Returns false if an error in the crypto library prevents creation of an ID.
      */
     virtual bool CreateKeyId(const keymaster_key_blob_t& key_blob, km_id_t* keyid) const = 0;
 
+    /*
+     * Inform the KeymasterEnforcement object that early boot stage has ended.
+     */
+    void early_boot_ended() { in_early_boot_ = false; }
+
+    /*
+     * Inform the KeymasterEnforcement object that the device is locked, so it knows not to permit
+     * UNLOCKED_DEVICE_REQUIRED keys to be used until a fresh (later than "now") auth token is
+     * provided.  If password_only is true, the fresh auth token must additionally be a password
+     * auth token.
+     */
+    void device_locked(bool password_only) {
+        device_locked_at_ = get_current_time_ms();
+        password_unlock_only_ = password_only;
+    }
+
   private:
     keymaster_error_t AuthorizeUpdateOrFinish(const AuthProxy& auth_set,
                                               const AuthorizationSet& operation_params,
@@ -186,6 +212,8 @@
 
     bool MinTimeBetweenOpsPassed(uint32_t min_time_between, const km_id_t keyid);
     bool MaxUsesPerBootNotExceeded(const km_id_t keyid, uint32_t max_uses);
+    bool GetAndValidateAuthToken(const AuthorizationSet& operation_params,
+                                 const hw_auth_token_t** token, uint32_t* token_auth_type) const;
     bool AuthTokenMatches(const AuthProxy& auth_set, const AuthorizationSet& operation_params,
                           const uint64_t user_secure_id, const int auth_type_index,
                           const int auth_timeout_index,
@@ -194,6 +222,9 @@
 
     AccessTimeMap* access_time_map_;
     AccessCountMap* access_count_map_;
+    bool in_early_boot_ = true;
+    uint64_t device_locked_at_ = 0;
+    bool password_unlock_only_ = false;
 };
 
 }; /* namespace keymaster */
diff --git a/include/keymaster/keymaster_tags.h b/include/keymaster/keymaster_tags.h
index 071f0b1..f620dfb 100644
--- a/include/keymaster/keymaster_tags.h
+++ b/include/keymaster/keymaster_tags.h
@@ -107,6 +107,7 @@
     }
     // NOLINTNEXTLINE(google-explicit-constructor)
     inline operator keymaster_tag_t() { return tag; }
+    // NOLINTNEXTLINE(google-runtime-int)
     inline long masked_tag() { return static_cast<long>(keymaster_tag_mask_type(tag)); }
 };
 
@@ -124,6 +125,7 @@
     }
     // NOLINTNEXTLINE(google-explicit-constructor)
     inline operator keymaster_tag_t() { return tag; }
+    // NOLINTNEXTLINE(google-runtime-int)
     inline long masked_tag() { return static_cast<long>(keymaster_tag_mask_type(tag)); }
 };
 
@@ -147,6 +149,7 @@
 DECLARE_KEYMASTER_TAG(KM_DATE, TAG_USAGE_EXPIRE_DATETIME);
 DECLARE_KEYMASTER_TAG(KM_UINT, TAG_MIN_SECONDS_BETWEEN_OPS);
 DECLARE_KEYMASTER_TAG(KM_UINT, TAG_MAX_USES_PER_BOOT);
+DECLARE_KEYMASTER_TAG(KM_UINT, TAG_USAGE_COUNT_LIMIT);
 DECLARE_KEYMASTER_TAG(KM_BOOL, TAG_ALL_USERS);
 DECLARE_KEYMASTER_TAG(KM_UINT, TAG_USER_ID);
 DECLARE_KEYMASTER_TAG(KM_ULONG_REP, TAG_USER_SECURE_ID);
@@ -180,7 +183,18 @@
 DECLARE_KEYMASTER_TAG(KM_BYTES, TAG_ATTESTATION_ID_MEID);
 DECLARE_KEYMASTER_TAG(KM_BYTES, TAG_ATTESTATION_ID_MANUFACTURER);
 DECLARE_KEYMASTER_TAG(KM_BYTES, TAG_ATTESTATION_ID_MODEL);
-
+DECLARE_KEYMASTER_TAG(KM_BOOL, TAG_EARLY_BOOT_ONLY);
+DECLARE_KEYMASTER_TAG(KM_BOOL, TAG_DEVICE_UNIQUE_ATTESTATION);
+DECLARE_KEYMASTER_TAG(KM_BOOL, TAG_IDENTITY_CREDENTIAL_KEY);
+DECLARE_KEYMASTER_TAG(KM_BOOL, TAG_STORAGE_KEY);
+DECLARE_KEYMASTER_TAG(KM_BOOL, TAG_TRUSTED_USER_PRESENCE_REQUIRED);
+DECLARE_KEYMASTER_TAG(KM_UINT, TAG_BOOT_PATCHLEVEL);
+DECLARE_KEYMASTER_TAG(KM_UINT, TAG_VENDOR_PATCHLEVEL);
+DECLARE_KEYMASTER_TAG(KM_BYTES, TAG_CONFIRMATION_TOKEN);
+DECLARE_KEYMASTER_TAG(KM_BIGNUM, TAG_CERTIFICATE_SERIAL);
+DECLARE_KEYMASTER_TAG(KM_BYTES, TAG_CERTIFICATE_SUBJECT);
+DECLARE_KEYMASTER_TAG(KM_DATE, TAG_CERTIFICATE_NOT_BEFORE);
+DECLARE_KEYMASTER_TAG(KM_DATE, TAG_CERTIFICATE_NOT_AFTER);
 // DECLARE_KEYMASTER_ENUM_TAG is used to declare TypedEnumTag instances for each enum keymaster tag.
 #define DECLARE_KEYMASTER_ENUM_TAG(type, name, enumtype)                                           \
     extern TypedEnumTag<type, KM_##name, enumtype> name
@@ -198,6 +212,7 @@
 DECLARE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_USER_AUTH_TYPE, hw_authenticator_type_t);
 DECLARE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_KDF, keymaster_kdf_t);
 DECLARE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_EC_CURVE, keymaster_ec_curve_t);
+DECLARE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_RSA_OAEP_MGF_DIGEST, keymaster_digest_t);
 
 //
 // Overloaded function "Authorization" to create keymaster_key_param_t objects for all of tags.
diff --git a/include/keymaster/km_date.h b/include/keymaster/km_date.h
new file mode 100644
index 0000000..f3a6c58
--- /dev/null
+++ b/include/keymaster/km_date.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace keymaster {
+
+// kKmDate is the date that KM was last modified.  Ideally it should be changed every time
+// there's a significant change in the implementation, and it should be set to the date that
+// the change is merged into AOSP.
+//
+// TODO(swillden): Look into how to create a commit hook to update this.
+constexpr uint32_t kKmDate = 20201219;
+
+}  // namespace keymaster
diff --git a/include/keymaster/km_openssl/aes_key.h b/include/keymaster/km_openssl/aes_key.h
index 642c502..f00a665 100644
--- a/include/keymaster/km_openssl/aes_key.h
+++ b/include/keymaster/km_openssl/aes_key.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_AES_KEY_H_
-#define SYSTEM_KEYMASTER_AES_KEY_H_
+#pragma once
 
 #include <openssl/aes.h>
 
@@ -28,16 +27,15 @@
 
 class AesKeyFactory : public SymmetricKeyFactory {
   public:
-    explicit AesKeyFactory(const SoftwareKeyBlobMaker* blob_maker,
-                           const RandomSource* random_source) :
-		SymmetricKeyFactory(blob_maker, random_source) {}
+    explicit AesKeyFactory(const SoftwareKeyBlobMaker& blob_maker,
+                           const RandomSource& random_source)
+        : SymmetricKeyFactory(blob_maker, random_source) {}
 
     keymaster_algorithm_t registry_key() const { return KM_ALGORITHM_AES; }
 
     keymaster_error_t LoadKey(KeymasterKeyBlob&& key_material,
                               const AuthorizationSet& additional_params,
-                              AuthorizationSet&& hw_enforced,
-                              AuthorizationSet&& sw_enforced,
+                              AuthorizationSet&& hw_enforced, AuthorizationSet&& sw_enforced,
                               UniquePtr<Key>* key) const override;
 
     OperationFactory* GetOperationFactory(keymaster_purpose_t purpose) const override;
@@ -53,11 +51,8 @@
 class AesKey : public SymmetricKey {
   public:
     AesKey(KeymasterKeyBlob&& key_material, AuthorizationSet&& hw_enforced,
-           AuthorizationSet&& sw_enforced,
-           const KeyFactory* key_factory)
+           AuthorizationSet&& sw_enforced, const KeyFactory* key_factory)
         : SymmetricKey(move(key_material), move(hw_enforced), move(sw_enforced), key_factory) {}
 };
 
 }  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_AES_KEY_H_
diff --git a/include/keymaster/km_openssl/attestation_record.h b/include/keymaster/km_openssl/attestation_record.h
new file mode 100644
index 0000000..3ae1a10
--- /dev/null
+++ b/include/keymaster/km_openssl/attestation_record.h
@@ -0,0 +1,431 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <hardware/keymaster_defs.h>
+
+#include <keymaster/authorization_set.h>
+#include <keymaster/km_version.h>
+
+#include <cppbor.h>
+#include <openssl/asn1t.h>
+
+#include <vector>
+
+#define remove_type_mask(tag) ((tag)&0x0FFFFFFF)
+
+namespace keymaster {
+
+class AttestationContext;
+
+constexpr KmVersion kCurrentKmVersion = KmVersion::KEYMASTER_4_1;
+
+constexpr int EAT_CLAIM_PRIVATE_BASE = -80000;
+constexpr int EAT_CLAIM_PRIVATE_NON_KM_BASE = EAT_CLAIM_PRIVATE_BASE - 2000;
+
+constexpr int64_t convert_to_eat_claim(keymaster_tag_t tag) {
+    return EAT_CLAIM_PRIVATE_BASE - remove_type_mask(tag);
+}
+
+struct stack_st_ASN1_TYPE_Delete {
+    void operator()(stack_st_ASN1_TYPE* p) { sk_ASN1_TYPE_free(p); }
+};
+
+struct ASN1_STRING_Delete {
+    void operator()(ASN1_STRING* p) { ASN1_STRING_free(p); }
+};
+
+struct ASN1_TYPE_Delete {
+    void operator()(ASN1_TYPE* p) { ASN1_TYPE_free(p); }
+};
+
+#define ASN1_INTEGER_SET STACK_OF(ASN1_INTEGER)
+
+typedef struct km_root_of_trust {
+    ASN1_OCTET_STRING* verified_boot_key;
+    ASN1_BOOLEAN device_locked;
+    ASN1_ENUMERATED* verified_boot_state;
+    ASN1_OCTET_STRING* verified_boot_hash;
+} KM_ROOT_OF_TRUST;
+
+ASN1_SEQUENCE(KM_ROOT_OF_TRUST) = {
+    ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_key, ASN1_OCTET_STRING),
+    ASN1_SIMPLE(KM_ROOT_OF_TRUST, device_locked, ASN1_BOOLEAN),
+    ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_state, ASN1_ENUMERATED),
+    ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_hash, ASN1_OCTET_STRING),
+} ASN1_SEQUENCE_END(KM_ROOT_OF_TRUST);
+DECLARE_ASN1_FUNCTIONS(KM_ROOT_OF_TRUST);
+
+// Fields ordered in tag order.
+typedef struct km_auth_list {
+    ASN1_INTEGER_SET* purpose;
+    ASN1_INTEGER* algorithm;
+    ASN1_INTEGER* key_size;
+    ASN1_INTEGER_SET* block_mode;
+    ASN1_INTEGER_SET* digest;
+    ASN1_INTEGER_SET* padding;
+    ASN1_NULL* caller_nonce;
+    ASN1_INTEGER* min_mac_length;
+    ASN1_INTEGER_SET* kdf;
+    ASN1_INTEGER* ec_curve;
+    ASN1_INTEGER* rsa_public_exponent;
+    ASN1_INTEGER_SET* mgf_digest;
+    ASN1_NULL* rollback_resistance;
+    ASN1_NULL* early_boot_only;
+    ASN1_INTEGER* active_date_time;
+    ASN1_INTEGER* origination_expire_date_time;
+    ASN1_INTEGER* usage_expire_date_time;
+    ASN1_INTEGER* usage_count_limit;
+    ASN1_NULL* no_auth_required;
+    ASN1_INTEGER* user_auth_type;
+    ASN1_INTEGER* auth_timeout;
+    ASN1_NULL* allow_while_on_body;
+    ASN1_NULL* trusted_user_presence_required;
+    ASN1_NULL* trusted_confirmation_required;
+    ASN1_NULL* unlocked_device_required;
+    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;
+    ASN1_OCTET_STRING* attestation_id_brand;
+    ASN1_OCTET_STRING* attestation_id_device;
+    ASN1_OCTET_STRING* attestation_id_product;
+    ASN1_OCTET_STRING* attestation_id_serial;
+    ASN1_OCTET_STRING* attestation_id_imei;
+    ASN1_OCTET_STRING* attestation_id_meid;
+    ASN1_OCTET_STRING* attestation_id_manufacturer;
+    ASN1_OCTET_STRING* attestation_id_model;
+    ASN1_INTEGER* vendor_patchlevel;
+    ASN1_INTEGER* boot_patch_level;
+    ASN1_NULL* device_unique_attestation;
+    ASN1_NULL* identity_credential_key;
+} KM_AUTH_LIST;
+
+ASN1_SEQUENCE(KM_AUTH_LIST) = {
+    ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.masked_tag()),
+    ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, block_mode, ASN1_INTEGER, TAG_BLOCK_MODE.masked_tag()),
+    ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.masked_tag()),
+    ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, caller_nonce, ASN1_NULL, TAG_CALLER_NONCE.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, min_mac_length, ASN1_INTEGER, TAG_MIN_MAC_LENGTH.masked_tag()),
+    ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, kdf, ASN1_INTEGER, TAG_KDF.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER,
+                 TAG_RSA_PUBLIC_EXPONENT.masked_tag()),
+    ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, mgf_digest, ASN1_INTEGER,
+                        TAG_RSA_OAEP_MGF_DIGEST.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistance, ASN1_NULL,
+                 TAG_ROLLBACK_RESISTANCE.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, early_boot_only, ASN1_NULL, TAG_EARLY_BOOT_ONLY.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER,
+                 TAG_ORIGINATION_EXPIRE_DATETIME.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER,
+                 TAG_USAGE_EXPIRE_DATETIME.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, usage_count_limit, ASN1_INTEGER, TAG_USAGE_COUNT_LIMIT.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, allow_while_on_body, ASN1_NULL,
+                 TAG_ALLOW_WHILE_ON_BODY.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, trusted_user_presence_required, ASN1_NULL,
+                 TAG_TRUSTED_USER_PRESENCE_REQUIRED.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, trusted_confirmation_required, ASN1_NULL,
+                 TAG_TRUSTED_CONFIRMATION_REQUIRED.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, unlocked_device_required, ASN1_NULL,
+                 TAG_UNLOCKED_DEVICE_REQUIRED.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, all_applications, ASN1_NULL, TAG_ALL_APPLICATIONS.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, application_id, ASN1_OCTET_STRING, TAG_APPLICATION_ID.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER,
+                 TAG_CREATION_DATETIME.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistant, ASN1_NULL, TAG_ROLLBACK_RESISTANT.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, attestation_application_id, ASN1_OCTET_STRING,
+                 TAG_ATTESTATION_APPLICATION_ID.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_brand, ASN1_OCTET_STRING,
+                 TAG_ATTESTATION_ID_BRAND.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_device, ASN1_OCTET_STRING,
+                 TAG_ATTESTATION_ID_DEVICE.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_product, ASN1_OCTET_STRING,
+                 TAG_ATTESTATION_ID_PRODUCT.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_serial, ASN1_OCTET_STRING,
+                 TAG_ATTESTATION_ID_SERIAL.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_imei, ASN1_OCTET_STRING,
+                 TAG_ATTESTATION_ID_IMEI.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_meid, ASN1_OCTET_STRING,
+                 TAG_ATTESTATION_ID_MEID.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_manufacturer, ASN1_OCTET_STRING,
+                 TAG_ATTESTATION_ID_MANUFACTURER.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_model, ASN1_OCTET_STRING,
+                 TAG_ATTESTATION_ID_MODEL.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, vendor_patchlevel, ASN1_INTEGER, TAG_VENDOR_PATCHLEVEL.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, boot_patch_level, ASN1_INTEGER, TAG_BOOT_PATCHLEVEL.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, device_unique_attestation, ASN1_NULL,
+                 TAG_DEVICE_UNIQUE_ATTESTATION.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, identity_credential_key, ASN1_NULL,
+                 TAG_IDENTITY_CREDENTIAL_KEY.masked_tag()),
+} ASN1_SEQUENCE_END(KM_AUTH_LIST);
+DECLARE_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);
+DECLARE_ASN1_FUNCTIONS(KM_KEY_DESCRIPTION);
+
+enum class EatClaim {
+
+    // Official CWT claims, as defined in https://www.iana.org/assignments/cwt/cwt.xhtml
+
+    IAT = 6,
+    CTI = 7,
+
+    // Claims defined in
+    // https://github.com/laurencelundblade/ctoken/blob/master/inc/ctoken_eat_labels.h, by the
+    // author of the EAT standard, and in the ARM PSA. They should be considered stable at least
+    // until the standard is officially published.
+
+    UEID = -75009,
+    NONCE = -75008,
+    SECURITY_LEVEL = -76002,
+    BOOT_STATE = -76003,
+    SUBMODS = -76000,
+
+    // Claims specific to Android, and not part of the official EAT standard.
+
+    PURPOSE = convert_to_eat_claim(KM_TAG_PURPOSE),
+    ALGORITHM = convert_to_eat_claim(KM_TAG_ALGORITHM),
+    KEY_SIZE = convert_to_eat_claim(KM_TAG_KEY_SIZE),
+    BLOCK_MODE = convert_to_eat_claim(KM_TAG_BLOCK_MODE),
+    DIGEST = convert_to_eat_claim(KM_TAG_DIGEST),
+    PADDING = convert_to_eat_claim(KM_TAG_PADDING),
+    // TODO: Check if CALLER_NONCE is needed (see go/keymint-eat)
+    CALLER_NONCE = convert_to_eat_claim(KM_TAG_CALLER_NONCE),
+    MIN_MAC_LENGTH = convert_to_eat_claim(KM_TAG_MIN_MAC_LENGTH),
+    EC_CURVE = convert_to_eat_claim(KM_TAG_EC_CURVE),
+    RSA_PUBLIC_EXPONENT = convert_to_eat_claim(KM_TAG_RSA_PUBLIC_EXPONENT),
+    EARLY_BOOT_ONLY = convert_to_eat_claim(KM_TAG_EARLY_BOOT_ONLY),
+    ACTIVE_DATETIME = convert_to_eat_claim(KM_TAG_ACTIVE_DATETIME),
+    ORIGINATION_EXPIRE_DATETIME = convert_to_eat_claim(KM_TAG_ORIGINATION_EXPIRE_DATETIME),
+    USAGE_EXPIRE_DATETIME = convert_to_eat_claim(KM_TAG_USAGE_EXPIRE_DATETIME),
+    NO_AUTH_REQUIRED = convert_to_eat_claim(KM_TAG_NO_AUTH_REQUIRED),
+    USER_AUTH_TYPE = convert_to_eat_claim(KM_TAG_USER_AUTH_TYPE),
+    AUTH_TIMEOUT = convert_to_eat_claim(KM_TAG_AUTH_TIMEOUT),
+    ALLOW_WHILE_ON_BODY = convert_to_eat_claim(KM_TAG_ALLOW_WHILE_ON_BODY),
+    TRUSTED_USER_PRESENCE_REQUIRED = convert_to_eat_claim(KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED),
+    TRUSTED_CONFIRMATION_REQUIRED = convert_to_eat_claim(KM_TAG_TRUSTED_CONFIRMATION_REQUIRED),
+    UNLOCKED_DEVICE_REQUIRED = convert_to_eat_claim(KM_TAG_UNLOCKED_DEVICE_REQUIRED),
+    ALL_APPLICATIONS = convert_to_eat_claim(KM_TAG_ALL_APPLICATIONS),
+    APPLICATION_ID = convert_to_eat_claim(KM_TAG_APPLICATION_ID),
+    ORIGIN = convert_to_eat_claim(KM_TAG_ORIGIN),
+    ROLLBACK_RESISTANT = convert_to_eat_claim(KM_TAG_ROLLBACK_RESISTANT),
+    OS_VERSION = convert_to_eat_claim(KM_TAG_OS_VERSION),
+    OS_PATCHLEVEL = convert_to_eat_claim(KM_TAG_OS_PATCHLEVEL),
+    ATTESTATION_APPLICATION_ID = convert_to_eat_claim(KM_TAG_ATTESTATION_APPLICATION_ID),
+    ATTESTATION_ID_BRAND = convert_to_eat_claim(KM_TAG_ATTESTATION_ID_BRAND),
+    ATTESTATION_ID_DEVICE = convert_to_eat_claim(KM_TAG_ATTESTATION_ID_DEVICE),
+    ATTESTATION_ID_PRODUCT = convert_to_eat_claim(KM_TAG_ATTESTATION_ID_PRODUCT),
+    ATTESTATION_ID_SERIAL = convert_to_eat_claim(KM_TAG_ATTESTATION_ID_SERIAL),
+    ATTESTATION_ID_MEID = convert_to_eat_claim(KM_TAG_ATTESTATION_ID_MEID),
+    ATTESTATION_ID_MANUFACTURER = convert_to_eat_claim(KM_TAG_ATTESTATION_ID_MANUFACTURER),
+    VENDOR_PATCHLEVEL = convert_to_eat_claim(KM_TAG_VENDOR_PATCHLEVEL),
+    BOOT_PATCHLEVEL = convert_to_eat_claim(KM_TAG_BOOT_PATCHLEVEL),
+    ATTESTATION_ID_MODEL = convert_to_eat_claim(KM_TAG_ATTESTATION_ID_MODEL),
+    DEVICE_UNIQUE_ATTESTATION = convert_to_eat_claim(KM_TAG_DEVICE_UNIQUE_ATTESTATION),
+    IDENTITY_CREDENTIAL_KEY = convert_to_eat_claim(KM_TAG_IDENTITY_CREDENTIAL_KEY),
+    STORAGE_KEY = convert_to_eat_claim(KM_TAG_STORAGE_KEY),
+    CONFIRMATION_TOKEN = convert_to_eat_claim(KM_TAG_CONFIRMATION_TOKEN),
+
+    // Claims specific to Android that do not exist as Keymint tags.
+
+    VERIFIED_BOOT_KEY = EAT_CLAIM_PRIVATE_NON_KM_BASE - 1,
+    DEVICE_LOCKED = EAT_CLAIM_PRIVATE_NON_KM_BASE - 2,
+    VERIFIED_BOOT_HASH = EAT_CLAIM_PRIVATE_NON_KM_BASE - 3,
+    ATTESTATION_VERSION = EAT_CLAIM_PRIVATE_NON_KM_BASE - 4,
+    KEYMASTER_VERSION = EAT_CLAIM_PRIVATE_NON_KM_BASE - 5,
+    OFFICIAL_BUILD = EAT_CLAIM_PRIVATE_NON_KM_BASE - 6,
+};
+
+enum class EatSecurityLevel {
+    UNRESTRICTED = 1,
+    RESTRICTED = 2,
+    SECURE_RESTRICTED = 3,
+    HARDWARE = 4,
+};
+
+enum class EatEcCurve {
+    P_224 = KM_EC_CURVE_P_224,
+    P_256 = KM_EC_CURVE_P_256,
+    P_384 = KM_EC_CURVE_P_384,
+    P_521 = KM_EC_CURVE_P_521,
+};
+
+static const char kEatSubmodNameSoftware[] = "software";
+static const char kEatSubmodNameTee[] = "tee";
+
+constexpr size_t kImeiBlobLength = 15;
+constexpr size_t kUeidLength = 15;
+constexpr uint8_t kImeiTypeByte = 0x03;
+
+/**
+ * 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 / 25 = ASN.1 attestation extension / EAT attestation extension
+ */
+static const char kAsn1TokenOid[] = "1.3.6.1.4.1.11129.2.1.17";
+static const char kEatTokenOid[] = "1.3.6.1.4.1.11129.2.1.25";
+
+// This build_attestation_record sets the keymaster version to the default
+// value, and chooses the correct attestation extension (ASN.1 or EAT) based
+// on that value.
+keymaster_error_t build_attestation_record(const AuthorizationSet& attestation_params,
+                                           AuthorizationSet software_enforced,
+                                           AuthorizationSet tee_enforced,
+                                           const AttestationContext& context,
+                                           UniquePtr<uint8_t[]>* asn1_key_desc,
+                                           size_t* asn1_key_desc_len);
+
+// Builds EAT record, with the same values as the attestation record above,
+// but encoded as a CBOR (EAT) structure rather than an ASN.1 structure.
+keymaster_error_t build_eat_record(const AuthorizationSet& attestation_params,
+                                   AuthorizationSet software_enforced,
+                                   AuthorizationSet tee_enforced,      //
+                                   const AttestationContext& context,  //
+                                   std::vector<uint8_t>* eat_token);
+
+/**
+ * Helper functions for attestation record tests. Caller takes ownership of
+ * |attestation_challenge->data| and |unique_id->data|, deallocate using delete[].
+ */
+keymaster_error_t parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
+                                           uint32_t* attestation_version,  //
+                                           keymaster_security_level_t* attestation_security_level,
+                                           uint32_t* keymaster_version,
+                                           keymaster_security_level_t* keymaster_security_level,
+                                           keymaster_blob_t* attestation_challenge,
+                                           AuthorizationSet* software_enforced,
+                                           AuthorizationSet* tee_enforced,
+                                           keymaster_blob_t* unique_id);
+
+/**
+ * Caller takes ownership of |verified_boot_key->data|, deallocate using delete[].
+ */
+keymaster_error_t parse_root_of_trust(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
+                                      keymaster_blob_t* verified_boot_key,
+                                      keymaster_verified_boot_t* verified_boot_state,
+                                      bool* device_locked);
+
+keymaster_error_t build_eat_submod(const AuthorizationSet& auth_list,
+                                   EatSecurityLevel security_level, cppbor::Map* submod);
+
+keymaster_error_t build_auth_list(const AuthorizationSet& auth_list, KM_AUTH_LIST* record);
+
+keymaster_error_t parse_eat_record(
+    const uint8_t* eat_key_desc, size_t eat_key_desc_len, uint32_t* attestation_version,
+    keymaster_security_level_t* attestation_security_level, uint32_t* keymaster_version,
+    keymaster_security_level_t* keymaster_security_level, keymaster_blob_t* attestation_challenge,
+    AuthorizationSet* software_enforced, AuthorizationSet* tee_enforced,
+    keymaster_blob_t* unique_id, keymaster_blob_t* verified_boot_key,
+    keymaster_verified_boot_t* verified_boot_state, bool* device_locked,
+    std::vector<int64_t>* unexpected_claims);
+
+keymaster_error_t parse_eat_submod(const cppbor::Map* submod_values,
+                                   AuthorizationSet* software_enforced,
+                                   AuthorizationSet* tee_enforced);
+
+keymaster_error_t extract_auth_list(const KM_AUTH_LIST* record, AuthorizationSet* auth_list);
+
+/**
+ * Convert a KeymasterContext::Version to the keymaster version number used in attestations.
+ */
+inline static uint version_to_attestation_km_version(KmVersion version) {
+    switch (version) {
+    default:
+    case KmVersion::KEYMASTER_1:
+    case KmVersion::KEYMASTER_1_1:
+        return 0;  // Attestation not actually supported.
+    case KmVersion::KEYMASTER_2:
+        return 2;
+    case KmVersion::KEYMASTER_3:
+        return 3;
+    case KmVersion::KEYMASTER_4:
+        return 4;
+    case KmVersion::KEYMASTER_4_1:
+        return 41;
+    case KmVersion::KEYMINT_1:
+        return 100;
+    }
+}
+
+/**
+ * Convert a KeymasterContext::Version to the corresponding attestation format version number.
+ */
+inline static uint version_to_attestation_version(KmVersion version) {
+    switch (version) {
+    default:
+    case KmVersion::KEYMASTER_1:
+        return 0;  // Attestation not actually supported.
+    case KmVersion::KEYMASTER_2:
+        return 1;
+    case KmVersion::KEYMASTER_3:
+        return 2;
+    case KmVersion::KEYMASTER_4:
+        return 3;
+    case KmVersion::KEYMASTER_4_1:
+        return 4;
+    case KmVersion::KEYMINT_1:
+        return 100;
+    }
+}
+
+}  // namespace keymaster
diff --git a/include/keymaster/km_openssl/attestation_utils.h b/include/keymaster/km_openssl/attestation_utils.h
index 063fb2c..ab4fa50 100644
--- a/include/keymaster/km_openssl/attestation_utils.h
+++ b/include/keymaster/km_openssl/attestation_utils.h
@@ -20,6 +20,7 @@
 
 #include <hardware/keymaster_defs.h>
 #include <keymaster/android_keymaster_utils.h>
+#include <keymaster/attestation_context.h>
 
 #include <openssl/x509v3.h>
 
@@ -28,15 +29,102 @@
 namespace keymaster {
 
 class AuthorizationSet;
-class AttestationRecordContext;
+class AttestationContext;
 class AsymmetricKey;
+class Key;
 
+struct AttestKeyInfo {
+    AttestKeyInfo() = default;
+    AttestKeyInfo(const UniquePtr<Key>& key, const KeymasterBlob* issuer_subject,
+                  keymaster_error_t* error);
+    AttestKeyInfo(AttestKeyInfo&&) = default;
+    AttestKeyInfo(const AttestKeyInfo&) = delete;
 
-keymaster_error_t generate_attestation(const AsymmetricKey& key,
-        const AuthorizationSet& attest_params, const keymaster_cert_chain_t& attestation_chain,
-        const keymaster_key_blob_t& attestation_signing_key,
-        const AttestationRecordContext& context, CertChainPtr* cert_chain_out);
+    void operator=(const AttestKeyInfo&) = delete;
 
-} // namespace keymaster
+    explicit operator bool() const { return signing_key.get() != nullptr; }
+
+    EVP_PKEY_Ptr signing_key;
+    const KeymasterBlob* issuer_subject;
+};
+
+/**
+ * Generate attestation certificate.
+ *
+ * @param key is an AsymmetricKey object containing the key to be attested.  The contained
+ *        authorization lists are used for the key description.
+ *
+ * @param attest_params contains parameters for the attestation, including:
+ *
+ *         TAG_ATTESTATION_CHALLENGE
+ *         TAG_ATTESTATION_APPLICATION_ID
+ *         TAG_ATTESTATION_ID_*
+ *         TAG_DEVICE_UNIQUE_ATTESTATION
+ *         TAG_RESET_SINCE_ROTATION
+ *
+ * @param attest_key optionally contains the attestation key and issuer subject to use.  If
+ *        attest_key.signing_key is non-null, that key will be used to sign the attestation and the
+ *        issuer subject that will be placed in the attestation certificate.  This is only used for
+ *        KeyMint.  If attest_key.signing_key is null, the signing key will be obtained from the
+ *        AttestationContext, and the issuer subject will be obtained from the cetificate chain
+ *        provided by the AttestationContext.
+ *
+ * @param context is the attestation context, used to generate unique IDs and obtain boot parameters
+ *        as well as provide information about the SecurityLevel and KM version.
+ *
+ * @param error must be non-null and will be used to return any errors.  In the event of an error
+ *        the returned certificate chain will be empty.
+ *
+ * @return Returns the completed certificate chain, ordered from leaf (which is the generated
+ *         attestation certificate) to root.
+ */
+CertificateChain generate_attestation(const AsymmetricKey& key,
+                                      const AuthorizationSet& attest_params,
+                                      AttestKeyInfo attest_key,
+                                      const AttestationContext& context,  //
+                                      keymaster_error_t* error);
+
+/**
+ * Generate attestation certificate.
+ *
+ * @param evp_key contains the key to be attested.  Must not be null.
+ *
+ * @param sw_enforced contains the software-enforced elements of the key description.
+ *
+ * @param hw_enforced contains the hardware-enforced elements of the key description.
+ *
+ * @param attest_params contains parameters for the attestation, including:
+ *
+ *         TAG_ATTESTATION_CHALLENGE
+ *         TAG_ATTESTATION_APPLICATION_ID
+ *         TAG_ATTESTATION_ID_*
+ *         TAG_DEVICE_UNIQUE_ATTESTATION
+ *         TAG_RESET_SINCE_ROTATION
+ *
+ * @param attest_key optionally contains the attestation key and issuer subject to use.  If
+ *        attest_key.signing_key is non-null, that key will be used to sign the attestation and the
+ *        issuer subject that will be placed in the attestation certificate.  This is only used for
+ *        KeyMint.  If attest_key.signign_key is null, the signing key will be obtained from the
+ *        AttestationContext, and the issuer subject will be obtained from the cetificate chain
+ *        provided by the AttestationContext.
+ *
+ * @param context is the attestation context, used to generate unique IDs and obtain boot parameters
+ *        as well as provide information about the SecurityLevel and KM version.
+ *
+ * @param error must be non-null and will be used to return any errors.  In the event of an error
+ *        the returned certificate chain will be empty.
+ *
+ * @return Returns the completed certificate chain, ordered from leaf (which is the generated
+ *         attestation certificate) to root.
+ */
+CertificateChain generate_attestation(const EVP_PKEY* evp_key,              //
+                                      const AuthorizationSet& sw_enforced,  //
+                                      const AuthorizationSet& hw_enforced,  //
+                                      const AuthorizationSet& attest_params,
+                                      AttestKeyInfo attest_key,
+                                      const AttestationContext& context,  //
+                                      keymaster_error_t* error);
+
+}  // namespace keymaster
 
 #endif  // KM_OPENSSL_ATTESTATION_UTILS_H_
diff --git a/include/keymaster/km_openssl/certificate_utils.h b/include/keymaster/km_openssl/certificate_utils.h
new file mode 100644
index 0000000..03b9c59
--- /dev/null
+++ b/include/keymaster/km_openssl/certificate_utils.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <openssl/x509v3.h>
+
+#include <hardware/keymaster_defs.h>
+
+#include <keymaster/km_openssl/openssl_utils.h>
+#include <keymaster/km_version.h>
+
+namespace keymaster {
+
+class AsymmetricKey;
+class AuthorizationSet;
+
+keymaster_error_t make_name_from_str(const char name[], X509_NAME_Ptr* name_out);
+
+keymaster_error_t make_name_from_der(const keymaster_blob_t& name, X509_NAME_Ptr* name_out);
+
+keymaster_error_t get_common_name(X509_NAME* name, UniquePtr<const char[]>* name_out);
+
+// CertificateParams encapsulates a set of certificate parameters that may be provided by the
+// caller, or may be defaulted.
+struct CertificateCallerParams {
+    BIGNUM_Ptr serial;
+    X509_NAME_Ptr subject_name;
+    int64_t active_date_time;  // Time since epoch in ms
+    int64_t expire_date_time;  // Time since epoch in ms
+    bool is_signing_key = false;
+    bool is_encryption_key = false;
+    bool is_agreement_key = false;
+};
+
+keymaster_error_t get_certificate_params(const AuthorizationSet& caller_params,
+                                         CertificateCallerParams* cert_params, KmVersion kmVersion);
+
+keymaster_error_t make_key_usage_extension(bool is_signing_key, bool is_encryption_key,
+                                           bool is_key_agreement_key,
+                                           X509_EXTENSION_Ptr* usage_extension_out);
+
+// Creates a rump certificate structure with serial, subject and issuer names, as well as activation
+// and expiry date.  Callers should pass an empty X509_Ptr and check the return value for
+// KM_ERROR_OK (0) before accessing the result.
+keymaster_error_t make_cert_rump(const uint32_t serial, const X509_NAME* issuer,
+                                 const CertificateCallerParams& cert_params, X509_Ptr* cert_out);
+
+keymaster_error_t make_cert(const EVP_PKEY* evp_pkey, const X509_NAME* issuer,
+                            const CertificateCallerParams& cert_params, X509_Ptr* cert_out);
+
+// Sign the certificate with the provided signing key.
+keymaster_error_t sign_cert(X509* certificate, const EVP_PKEY* signing_key);
+
+// Generate a certificate for the provided asymmetric key, with params.  The certificate will be
+// self-signed unless `fake_signature` is set, in which case a fake signature will be placed in the
+// certificate.  Specifically, the signature algorithm will be set to RSA PKCS#1 v1.5 with digest
+// SHA-256, but the signature field will contain a single zero byte.
+CertificateChain generate_self_signed_cert(const AsymmetricKey& key, const AuthorizationSet& params,
+                                           bool fake_signature, keymaster_error_t* error);
+
+keymaster_error_t encode_certificate(X509* certificate, keymaster_blob_t* derCert);
+
+}  // namespace keymaster
diff --git a/include/keymaster/km_openssl/ec_key.h b/include/keymaster/km_openssl/ec_key.h
index 9bc292e..328ad62 100644
--- a/include/keymaster/km_openssl/ec_key.h
+++ b/include/keymaster/km_openssl/ec_key.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_EC_KEY_H_
-#define SYSTEM_KEYMASTER_EC_KEY_H_
+#pragma once
 
 #include <openssl/ec.h>
 
@@ -28,10 +27,11 @@
 
 class EcKey : public AsymmetricKey {
   public:
-    EcKey(AuthorizationSet&& hw_enforced, AuthorizationSet&& sw_enforced,
-          const KeyFactory* key_factory)
-        : AsymmetricKey(move(hw_enforced), move(sw_enforced), key_factory) {}
-    virtual ~EcKey() {}
+    EcKey(AuthorizationSet hw_enforced, AuthorizationSet sw_enforced, const KeyFactory* factory)
+        : AsymmetricKey(move(hw_enforced), move(sw_enforced), factory) {}
+    EcKey(AuthorizationSet hw_enforced, AuthorizationSet sw_enforced, const KeyFactory* factory,
+          EC_KEY_Ptr ec_key)
+        : AsymmetricKey(move(hw_enforced), move(sw_enforced), factory), ec_key_(move(ec_key)) {}
 
     bool InternalToEvp(EVP_PKEY* pkey) const override;
     bool EvpToInternal(const EVP_PKEY* pkey) override;
@@ -39,7 +39,7 @@
     EC_KEY* key() const { return ec_key_.get(); }
 
   protected:
-    EcKey(EC_KEY* ec_key, AuthorizationSet&& hw_enforced, AuthorizationSet&& sw_enforced,
+    EcKey(EC_KEY* ec_key, AuthorizationSet hw_enforced, AuthorizationSet sw_enforced,
           const KeyFactory* key_factory)
         : AsymmetricKey(move(hw_enforced), move(sw_enforced), key_factory), ec_key_(ec_key) {}
 
@@ -48,5 +48,3 @@
 };
 
 }  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_EC_KEY_H_
diff --git a/include/keymaster/km_openssl/ec_key_factory.h b/include/keymaster/km_openssl/ec_key_factory.h
index 1ce2392..ca37d86 100644
--- a/include/keymaster/km_openssl/ec_key_factory.h
+++ b/include/keymaster/km_openssl/ec_key_factory.h
@@ -14,37 +14,42 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_EC_KEY_FACTORY_H_
-#define SYSTEM_KEYMASTER_EC_KEY_FACTORY_H_
+#pragma once
 
 #include <openssl/ec.h>
 #include <openssl/evp.h>
 
 #include <keymaster/asymmetric_key_factory.h>
 #include <keymaster/soft_key_factory.h>
-#include <keymaster/attestation_record.h>
 
 namespace keymaster {
 
 class EcKeyFactory : public AsymmetricKeyFactory, public SoftKeyFactoryMixin {
   public:
-    explicit EcKeyFactory(const SoftwareKeyBlobMaker* blob_maker) :
-                          SoftKeyFactoryMixin(blob_maker) {}
+    explicit EcKeyFactory(const SoftwareKeyBlobMaker& blob_maker, const KeymasterContext& context)
+        : AsymmetricKeyFactory(context), SoftKeyFactoryMixin(blob_maker) {}
 
     keymaster_algorithm_t keymaster_key_type() const override { return KM_ALGORITHM_EC; }
     int evp_key_type() const override { return EVP_PKEY_EC; }
 
     keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
-                                  KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
-                                  AuthorizationSet* sw_enforced) const override;
+                                  UniquePtr<Key> attest_key,            //
+                                  const KeymasterBlob& issuer_subject,  //
+                                  KeymasterKeyBlob* key_blob,
+                                  AuthorizationSet* hw_enforced,  //
+                                  AuthorizationSet* sw_enforced,
+                                  CertificateChain* cert_chain) const override;
     keymaster_error_t ImportKey(const AuthorizationSet& key_description,
                                 keymaster_key_format_t input_key_material_format,
                                 const KeymasterKeyBlob& input_key_material,
-                                KeymasterKeyBlob* output_key_blob, AuthorizationSet* hw_enforced,
-                                AuthorizationSet* sw_enforced) const override;
+                                UniquePtr<Key> attest_key,  //
+                                const KeymasterBlob& issuer_subject,
+                                KeymasterKeyBlob* output_key_blob,  //
+                                AuthorizationSet* hw_enforced,      //
+                                AuthorizationSet* sw_enforced,
+                                CertificateChain* cert_chain) const override;
 
-    keymaster_error_t CreateEmptyKey(AuthorizationSet&& hw_enforced,
-                                     AuthorizationSet&& sw_enforced,
+    keymaster_error_t CreateEmptyKey(AuthorizationSet&& hw_enforced, AuthorizationSet&& sw_enforced,
                                      UniquePtr<AsymmetricKey>* key) const override;
 
     keymaster_error_t UpdateImportKeyDescription(const AuthorizationSet& key_description,
@@ -64,5 +69,3 @@
 };
 
 }  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_EC_KEY_FACTORY_H_
diff --git a/include/keymaster/km_openssl/ecdh_operation.h b/include/keymaster/km_openssl/ecdh_operation.h
new file mode 100644
index 0000000..4f85afa
--- /dev/null
+++ b/include/keymaster/km_openssl/ecdh_operation.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SYSTEM_KEYMASTER_ECDH_OPERATION_H_
+#define SYSTEM_KEYMASTER_ECDH_OPERATION_H_
+
+#include <openssl/ec.h>
+#include <openssl/evp.h>
+
+#include <keymaster/UniquePtr.h>
+
+#include <keymaster/key.h>
+#include <keymaster/km_openssl/openssl_utils.h>
+#include <keymaster/operation.h>
+
+namespace keymaster {
+
+class EcdhOperation : public Operation {
+  public:
+    EcdhOperation(AuthorizationSet&& hw_enforced, AuthorizationSet&& sw_enforced, EVP_PKEY* key)
+        : Operation(KM_PURPOSE_AGREE_KEY, move(hw_enforced), move(sw_enforced)), ecdh_key_(key) {}
+
+    keymaster_error_t Abort() override { return KM_ERROR_OK; }
+
+    keymaster_error_t Begin(const AuthorizationSet& input_params,
+                            AuthorizationSet* output_params) override;
+    keymaster_error_t Update(const AuthorizationSet& additional_params, const Buffer& input,
+                             AuthorizationSet* output_params, Buffer* output,
+                             size_t* input_consumed) override;
+    keymaster_error_t Finish(const AuthorizationSet& additional_params, const Buffer& input,
+                             const Buffer& signature, AuthorizationSet* output_params,
+                             Buffer* output) override;
+
+  protected:
+    EVP_PKEY_Ptr ecdh_key_;
+};
+
+class EcdhOperationFactory : public OperationFactory {
+  private:
+    KeyType registry_key() const override { return KeyType(KM_ALGORITHM_EC, KM_PURPOSE_AGREE_KEY); }
+    OperationPtr CreateOperation(Key&& key, const AuthorizationSet& begin_params,
+                                 keymaster_error_t* error) override;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_ECDH_OPERATION_H_
diff --git a/include/keymaster/km_openssl/hmac_key.h b/include/keymaster/km_openssl/hmac_key.h
index f32ba4e..55d802a 100644
--- a/include/keymaster/km_openssl/hmac_key.h
+++ b/include/keymaster/km_openssl/hmac_key.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_HMAC_KEY_H_
-#define SYSTEM_KEYMASTER_HMAC_KEY_H_
+#pragma once
 
 #include "symmetric_key.h"
 
@@ -27,14 +26,13 @@
 
 class HmacKeyFactory : public SymmetricKeyFactory {
   public:
-    explicit HmacKeyFactory(const SoftwareKeyBlobMaker* blob_maker,
-                            const RandomSource* random_source) :
-                                    SymmetricKeyFactory(blob_maker, random_source) {}
+    explicit HmacKeyFactory(const SoftwareKeyBlobMaker& blob_maker,
+                            const RandomSource& random_source)
+        : SymmetricKeyFactory(blob_maker, random_source) {}
 
     keymaster_error_t LoadKey(KeymasterKeyBlob&& key_material,
                               const AuthorizationSet& additional_params,
-                              AuthorizationSet&& hw_enforced,
-                              AuthorizationSet&& sw_enforced,
+                              AuthorizationSet&& hw_enforced, AuthorizationSet&& sw_enforced,
                               UniquePtr<Key>* key) const override;
 
     OperationFactory* GetOperationFactory(keymaster_purpose_t purpose) const override;
@@ -56,5 +54,3 @@
 };
 
 }  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_HMAC_KEY_H_
diff --git a/include/keymaster/km_openssl/iso18033kdf.h b/include/keymaster/km_openssl/iso18033kdf.h
index ef96060..8c2952b 100644
--- a/include/keymaster/km_openssl/iso18033kdf.h
+++ b/include/keymaster/km_openssl/iso18033kdf.h
@@ -14,15 +14,14 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_ISO18033KDF_H_
-#define SYSTEM_KEYMASTER_ISO18033KDF_H_
+#pragma once
 
 #include <keymaster/km_openssl/kdf.h>
 
 #include <hardware/keymaster_defs.h>
 
-#include <keymaster/serializable.h>
 #include <keymaster/UniquePtr.h>
+#include <keymaster/serializable.h>
 
 namespace keymaster {
 
@@ -63,5 +62,3 @@
 };
 
 }  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_ISO18033KDF_H_
diff --git a/include/keymaster/km_openssl/nist_curve_key_exchange.h b/include/keymaster/km_openssl/nist_curve_key_exchange.h
index 8d2fa84..1c8ee2f 100644
--- a/include/keymaster/km_openssl/nist_curve_key_exchange.h
+++ b/include/keymaster/km_openssl/nist_curve_key_exchange.h
@@ -14,13 +14,12 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_NIST_CURVE_KEY_EXCHANGE_H_
-#define SYSTEM_KEYMASTER_NIST_CURVE_KEY_EXCHANGE_H_
+#pragma once
 
 #include "key_exchange.h"
 
-#include <keymaster/authorization_set.h>
 #include <hardware/keymaster_defs.h>
+#include <keymaster/authorization_set.h>
 
 #include <keymaster/UniquePtr.h>
 
@@ -68,5 +67,3 @@
 };
 
 }  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_NIST_CURVE_KEY_EXCHANGE_H_
diff --git a/include/keymaster/km_openssl/openssl_utils.h b/include/keymaster/km_openssl/openssl_utils.h
index 4483045..402c1f9 100644
--- a/include/keymaster/km_openssl/openssl_utils.h
+++ b/include/keymaster/km_openssl/openssl_utils.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_OPENSSL_UTILS_H_
-#define SYSTEM_KEYMASTER_OPENSSL_UTILS_H_
+#pragma once
 
 #include <openssl/bn.h>
 #include <openssl/ec.h>
@@ -30,7 +29,7 @@
 
 namespace keymaster {
 
-template<typename BlobType> struct TKeymasterBlob;
+template <typename BlobType> struct TKeymasterBlob;
 typedef TKeymasterBlob<keymaster_key_blob_t> KeymasterKeyBlob;
 
 class EvpMdCtxCleaner {
@@ -62,6 +61,7 @@
 DEFINE_OPENSSL_OBJECT_POINTER(EC_POINT)
 DEFINE_OPENSSL_OBJECT_POINTER(ENGINE)
 DEFINE_OPENSSL_OBJECT_POINTER(EVP_PKEY)
+DEFINE_OPENSSL_OBJECT_POINTER(EVP_PKEY_CTX)
 DEFINE_OPENSSL_OBJECT_POINTER(PKCS8_PRIV_KEY_INFO)
 DEFINE_OPENSSL_OBJECT_POINTER(RSA)
 DEFINE_OPENSSL_OBJECT_POINTER(X509)
@@ -95,10 +95,30 @@
 
 keymaster_error_t EvpKeyToKeyMaterial(const EVP_PKEY* evp_pkey, KeymasterKeyBlob* key_blob);
 
+keymaster_error_t GetEcdsa256KeyFromCert(const keymaster_blob_t* km_cert, uint8_t* x_coord,
+                                         size_t x_length, uint8_t* y_coord, size_t y_length);
+
 size_t ec_group_size_bits(EC_KEY* ec_key);
 
 keymaster_error_t GenerateRandom(uint8_t* buf, size_t length);
 
-}  // namespace keymaster
+inline const EVP_MD* KmDigestToEvpDigest(keymaster_digest_t digest) {
+    switch (digest) {
+    case KM_DIGEST_MD5:
+        return EVP_md5();
+    case KM_DIGEST_SHA1:
+        return EVP_sha1();
+    case KM_DIGEST_SHA_2_224:
+        return EVP_sha224();
+    case KM_DIGEST_SHA_2_256:
+        return EVP_sha256();
+    case KM_DIGEST_SHA_2_384:
+        return EVP_sha384();
+    case KM_DIGEST_SHA_2_512:
+        return EVP_sha512();
+    default:
+        return nullptr;
+    }
+}
 
-#endif  // SYSTEM_KEYMASTER_OPENSSL_UTILS_H_
+}  // namespace keymaster
diff --git a/include/keymaster/km_openssl/rsa_key.h b/include/keymaster/km_openssl/rsa_key.h
index 4936bc9..3783f9e 100644
--- a/include/keymaster/km_openssl/rsa_key.h
+++ b/include/keymaster/km_openssl/rsa_key.h
@@ -19,15 +19,19 @@
 
 #include <openssl/rsa.h>
 
+#include <keymaster/km_openssl/openssl_utils.h>
+
 #include "asymmetric_key.h"
 
 namespace keymaster {
 
 class RsaKey : public AsymmetricKey {
   public:
-    RsaKey(AuthorizationSet&& hw_enforced, AuthorizationSet&& sw_enforced,
-           const KeyFactory* key_factory)
-        : AsymmetricKey(move(hw_enforced), move(sw_enforced), key_factory) {}
+    RsaKey(AuthorizationSet hw_enforced, AuthorizationSet sw_enforced, const KeyFactory* factory)
+        : AsymmetricKey(move(hw_enforced), move(sw_enforced), factory) {}
+    RsaKey(AuthorizationSet hw_enforced, AuthorizationSet sw_enforced, const KeyFactory* factory,
+           RSA_Ptr rsa_key)
+        : AsymmetricKey(move(hw_enforced), move(sw_enforced), factory), rsa_key_(move(rsa_key)) {}
 
     bool InternalToEvp(EVP_PKEY* pkey) const override;
     bool EvpToInternal(const EVP_PKEY* pkey) override;
@@ -35,19 +39,15 @@
     bool SupportedMode(keymaster_purpose_t purpose, keymaster_padding_t padding);
     bool SupportedMode(keymaster_purpose_t purpose, keymaster_digest_t digest);
 
-    struct RSA_Delete {
-        void operator()(RSA* p) { RSA_free(p); }
-    };
-
     RSA* key() const { return rsa_key_.get(); }
 
   protected:
-    RsaKey(RSA* rsa, AuthorizationSet&& hw_enforced, AuthorizationSet&& sw_enforced,
+    RsaKey(RSA* rsa, AuthorizationSet hw_enforced, AuthorizationSet sw_enforced,
            const KeyFactory* key_factory)
         : AsymmetricKey(move(hw_enforced), move(sw_enforced), key_factory), rsa_key_(rsa) {}
 
   private:
-    UniquePtr<RSA, RSA_Delete> rsa_key_;
+    RSA_Ptr rsa_key_;
 };
 
 }  // namespace keymaster
diff --git a/include/keymaster/km_openssl/rsa_key_factory.h b/include/keymaster/km_openssl/rsa_key_factory.h
index ab0b3f5..3aacadc 100644
--- a/include/keymaster/km_openssl/rsa_key_factory.h
+++ b/include/keymaster/km_openssl/rsa_key_factory.h
@@ -14,34 +14,39 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_RSA_KEY_FACTORY_H_
-#define SYSTEM_KEYMASTER_RSA_KEY_FACTORY_H_
+#pragma once
 
 #include <openssl/evp.h>
 #include <openssl/rsa.h>
 
 #include <keymaster/asymmetric_key_factory.h>
 #include <keymaster/soft_key_factory.h>
-#include <keymaster/attestation_record.h>
 
 namespace keymaster {
 
 class RsaKeyFactory : public AsymmetricKeyFactory, public SoftKeyFactoryMixin {
   public:
-    explicit RsaKeyFactory(const SoftwareKeyBlobMaker* blob_maker) :
-            SoftKeyFactoryMixin(blob_maker) {}
+    explicit RsaKeyFactory(const SoftwareKeyBlobMaker& blob_maker, const KeymasterContext& context)
+        : AsymmetricKeyFactory(context), SoftKeyFactoryMixin(blob_maker) {}
 
     keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
-                                  KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
-                                  AuthorizationSet* sw_enforced) const override;
+                                  UniquePtr<Key> attest_key,
+                                  const KeymasterBlob& issuer_subject,  //
+                                  KeymasterKeyBlob* key_blob,
+                                  AuthorizationSet* hw_enforced,  //
+                                  AuthorizationSet* sw_enforced,
+                                  CertificateChain* cert_chain) const override;
     keymaster_error_t ImportKey(const AuthorizationSet& key_description,
                                 keymaster_key_format_t input_key_material_format,
                                 const KeymasterKeyBlob& input_key_material,
-                                KeymasterKeyBlob* output_key_blob, AuthorizationSet* hw_enforced,
-                                AuthorizationSet* sw_enforced) const override;
+                                UniquePtr<Key> attest_key,  //
+                                const KeymasterBlob& issuer_subject,
+                                KeymasterKeyBlob* output_key_blob,
+                                AuthorizationSet* hw_enforced,  //
+                                AuthorizationSet* sw_enforced,
+                                CertificateChain* cert_chain) const override;
 
-    keymaster_error_t CreateEmptyKey(AuthorizationSet&& hw_enforced,
-                                     AuthorizationSet&& sw_enforced,
+    keymaster_error_t CreateEmptyKey(AuthorizationSet&& hw_enforced, AuthorizationSet&& sw_enforced,
                                      UniquePtr<AsymmetricKey>* key) const override;
 
     OperationFactory* GetOperationFactory(keymaster_purpose_t purpose) const override;
@@ -59,5 +64,3 @@
 };
 
 }  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_RSA_KEY_FACTORY_H_
diff --git a/include/keymaster/km_openssl/rsa_operation.h b/include/keymaster/km_openssl/rsa_operation.h
index 578a3d2..99004f2 100644
--- a/include/keymaster/km_openssl/rsa_operation.h
+++ b/include/keymaster/km_openssl/rsa_operation.h
@@ -140,14 +140,22 @@
     RsaCryptOperation(AuthorizationSet&& hw_enforced, AuthorizationSet&& sw_enforced,
                       keymaster_purpose_t purpose, keymaster_digest_t digest,
                       keymaster_padding_t padding, EVP_PKEY* key)
-        : RsaOperation(move(hw_enforced), move(sw_enforced), purpose, digest, padding, key) {}
+        : RsaOperation(move(hw_enforced), move(sw_enforced), purpose, digest, padding, key),
+          mgf_digest_(KM_DIGEST_SHA1), mgf_digest_algorithm_(nullptr) {}
+    keymaster_digest_t oaepMgfDigest() { return mgf_digest_; }
+    void setOaepMgfDigest(keymaster_digest_t mgf_digest) { mgf_digest_ = mgf_digest; }
+    keymaster_error_t Begin(const AuthorizationSet& input_params,
+                            AuthorizationSet* output_params) override;
 
   protected:
     keymaster_error_t SetOaepDigestIfRequired(EVP_PKEY_CTX* pkey_ctx);
+    keymaster_error_t InitMgfDigest();
 
   private:
     int GetOpensslPadding(keymaster_error_t* error) override;
     bool require_digest() const override { return padding_ == KM_PAD_RSA_OAEP; }
+    keymaster_digest_t mgf_digest_;
+    const EVP_MD* mgf_digest_algorithm_;
 };
 
 /**
@@ -194,7 +202,7 @@
     const keymaster_digest_t* SupportedDigests(size_t* digest_count) const override;
 
   protected:
-    static EVP_PKEY* GetRsaKey(Key&& key, keymaster_error_t* error);
+    static EVP_PKEY* GetRsaKey(const Key& key, keymaster_error_t* error);
     virtual RsaOperation* CreateRsaOperation(Key&& key, const AuthorizationSet& begin_params,
                                              keymaster_error_t* error);
 
@@ -222,6 +230,10 @@
     RsaOperation* CreateRsaOperation(Key&& key, const AuthorizationSet& begin_params,
                                      keymaster_error_t* error) override;
     const keymaster_padding_t* SupportedPaddingModes(size_t* padding_mode_count) const override;
+
+  protected:
+    keymaster_error_t GetAndValidateMgfDigest(const AuthorizationSet& begin_params, const Key& key,
+                                              keymaster_digest_t* digest) const;
 };
 
 /**
diff --git a/include/keymaster/km_openssl/soft_keymaster_enforcement.h b/include/keymaster/km_openssl/soft_keymaster_enforcement.h
index 72b11ec..31022e7 100644
--- a/include/keymaster/km_openssl/soft_keymaster_enforcement.h
+++ b/include/keymaster/km_openssl/soft_keymaster_enforcement.h
@@ -44,6 +44,7 @@
                                         KeymasterBlob* sharingCheck) override;
     VerifyAuthorizationResponse
     VerifyAuthorization(const VerifyAuthorizationRequest& request) override;
+    keymaster_error_t GenerateTimestampToken(TimestampToken* token) override;
 
   private:
     bool have_saved_params_ = false;
diff --git a/include/keymaster/km_openssl/software_random_source.h b/include/keymaster/km_openssl/software_random_source.h
index ee472ef..ea8111b 100644
--- a/include/keymaster/km_openssl/software_random_source.h
+++ b/include/keymaster/km_openssl/software_random_source.h
@@ -15,22 +15,18 @@
 ** limitations under the License.
 */
 
-#ifndef KM_OPENSSL_SOFTWARE_RANDOM_SOURCE_H_
-#define KM_OPENSSL_SOFTWARE_RANDOM_SOURCE_H_
+#pragma once
 
 #include <keymaster/random_source.h>
 
 namespace keymaster {
 
 class SoftwareRandomSource : public RandomSource {
-public:
+  public:
     /**
      * Generates \p length random bytes, placing them in \p buf.
      */
     keymaster_error_t GenerateRandom(uint8_t* buffer, size_t length) const override;
-
 };
 
-}
-
-#endif  // KM_OPENSSL_SOFTWARE_RANDOM_SOURCE_H_
+}  // namespace keymaster
diff --git a/include/keymaster/km_openssl/symmetric_key.h b/include/keymaster/km_openssl/symmetric_key.h
index 5a5252d..a57d287 100644
--- a/include/keymaster/km_openssl/symmetric_key.h
+++ b/include/keymaster/km_openssl/symmetric_key.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_SYMMETRIC_KEY_H_
-#define SYSTEM_KEYMASTER_SYMMETRIC_KEY_H_
+#pragma once
 
 #include <keymaster/key_factory.h>
 #include <keymaster/random_source.h>
@@ -29,19 +28,26 @@
 
 class SymmetricKeyFactory : public KeyFactory, public SoftKeyFactoryMixin {
   public:
-    explicit SymmetricKeyFactory(const SoftwareKeyBlobMaker* blob_maker,
-                                 const RandomSource* random_source) :
-            SoftKeyFactoryMixin(blob_maker),
-            random_source_(*random_source) {}
+    explicit SymmetricKeyFactory(const SoftwareKeyBlobMaker& blob_maker,
+                                 const RandomSource& random_source)
+        : SoftKeyFactoryMixin(blob_maker), random_source_(random_source) {}
 
     keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
-                                  KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
-                                  AuthorizationSet* sw_enforced) const override;
+                                  UniquePtr<Key> attest_key,
+                                  const KeymasterBlob& issuer_subject,  //
+                                  KeymasterKeyBlob* key_blob,
+                                  AuthorizationSet* hw_enforced,  //
+                                  AuthorizationSet* sw_enforced,
+                                  CertificateChain* cert_chain) const override;
     keymaster_error_t ImportKey(const AuthorizationSet& key_description,
                                 keymaster_key_format_t input_key_material_format,
                                 const KeymasterKeyBlob& input_key_material,
-                                KeymasterKeyBlob* output_key_blob, AuthorizationSet* hw_enforced,
-                                AuthorizationSet* sw_enforced) const override;
+                                UniquePtr<Key> attest_key,
+                                const KeymasterBlob& issuer_subject,  //
+                                KeymasterKeyBlob* output_key_blob,
+                                AuthorizationSet* hw_enforced,  //
+                                AuthorizationSet* sw_enforced,
+                                CertificateChain* cert_chain) const override;
 
     virtual const keymaster_key_format_t* SupportedImportFormats(size_t* count) const override;
     virtual const keymaster_key_format_t* SupportedExportFormats(size_t* count) const override {
@@ -77,10 +83,7 @@
 
   protected:
     SymmetricKey(KeymasterKeyBlob&& key_material, AuthorizationSet&& hw_enforced,
-                 AuthorizationSet&& sw_enforced,
-                 const KeyFactory* key_factory);
+                 AuthorizationSet&& sw_enforced, const KeyFactory* key_factory);
 };
 
 }  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_AES_KEY_H_
diff --git a/include/keymaster/km_openssl/triple_des_key.h b/include/keymaster/km_openssl/triple_des_key.h
index 0a6810d..a03d595 100644
--- a/include/keymaster/km_openssl/triple_des_key.h
+++ b/include/keymaster/km_openssl/triple_des_key.h
@@ -25,8 +25,8 @@
 
 class TripleDesKeyFactory : public SymmetricKeyFactory {
   public:
-    explicit TripleDesKeyFactory(const SoftwareKeyBlobMaker* blob_maker,
-                                 const RandomSource* random_source)
+    explicit TripleDesKeyFactory(const SoftwareKeyBlobMaker& blob_maker,
+                                 const RandomSource& random_source)
         : SymmetricKeyFactory(blob_maker, random_source) {}
 
     keymaster_algorithm_t registry_key() const { return KM_ALGORITHM_TRIPLE_DES; }
diff --git a/include/keymaster/km_version.h b/include/keymaster/km_version.h
new file mode 100644
index 0000000..c328a27
--- /dev/null
+++ b/include/keymaster/km_version.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace keymaster {
+
+/**
+ * Version enumerates the list of Keymaster/KeyMint versions that we may support.  As old
+ * versions are deprecated and removed they should be removed from this enum, which will make it
+ * possible to easily find the version-dependent code and remove dead branches.
+ */
+enum class KmVersion {
+    KEYMASTER_1 = 10,
+    KEYMASTER_1_1 = 11,
+    KEYMASTER_2 = 20,
+    KEYMASTER_3 = 30,
+    KEYMASTER_4 = 40,
+    KEYMASTER_4_1 = 41,
+    KEYMINT_1 = 100,
+};
+
+};  // namespace keymaster
diff --git a/include/keymaster/legacy_support/ec_keymaster0_key.h b/include/keymaster/legacy_support/ec_keymaster0_key.h
deleted file mode 100644
index ab5ae4f..0000000
--- a/include/keymaster/legacy_support/ec_keymaster0_key.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2015 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_KEYMASTER_EC_KEYMASTER0_KEY_H_
-#define SYSTEM_KEYMASTER_EC_KEYMASTER0_KEY_H_
-
-#include <openssl/ec_key.h>
-
-#include <keymaster/km_openssl/ec_key.h>
-#include <keymaster/km_openssl/ec_key_factory.h>
-
-namespace keymaster {
-
-class Keymaster0Engine;
-
-/**
- * An EcdsaKeyFactory which can delegate key generation, importing and loading operations to a
- * keymaster0-backed OpenSSL engine.
- */
-class EcdsaKeymaster0KeyFactory : public EcKeyFactory {
-    typedef EcKeyFactory super;
-
-  public:
-    EcdsaKeymaster0KeyFactory(const SoftwareKeyBlobMaker* blob_maker,
-                              const Keymaster0Engine* engine);
-
-    keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
-                                  KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
-                                  AuthorizationSet* sw_enforced) const override;
-
-    keymaster_error_t ImportKey(const AuthorizationSet& key_description,
-                                keymaster_key_format_t input_key_material_format,
-                                const KeymasterKeyBlob& input_key_material,
-                                KeymasterKeyBlob* output_key_blob, AuthorizationSet* hw_enforced,
-                                AuthorizationSet* sw_enforced) const override;
-
-    keymaster_error_t LoadKey(KeymasterKeyBlob&& key_material,
-                              const AuthorizationSet& additional_params,
-                              AuthorizationSet&& hw_enforced,
-                              AuthorizationSet&& sw_enforced,
-                              UniquePtr<Key>* key) const override;
-
-  private:
-    const Keymaster0Engine* engine_;
-};
-
-class EcKeymaster0Key : public EcKey {
-  public:
-    EcKeymaster0Key(EC_KEY* ec_key, AuthorizationSet&& hw_enforced,
-                    AuthorizationSet&& sw_enforced, const KeyFactory* key_factory)
-        : EcKey(ec_key, move(hw_enforced), move(sw_enforced), key_factory) {}
-};
-
-}  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_EC_KEYMASTER0_KEY_H_
diff --git a/include/keymaster/legacy_support/ec_keymaster1_key.h b/include/keymaster/legacy_support/ec_keymaster1_key.h
index 5a2c1d8..d695c74 100644
--- a/include/keymaster/legacy_support/ec_keymaster1_key.h
+++ b/include/keymaster/legacy_support/ec_keymaster1_key.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_EC_KEYMASTER1_KEY_H_
-#define SYSTEM_KEYMASTER_EC_KEYMASTER1_KEY_H_
+#pragma once
 
 #include <openssl/ecdsa.h>
 
@@ -38,23 +37,31 @@
  */
 class EcdsaKeymaster1KeyFactory : public EcKeyFactory {
   public:
-    EcdsaKeymaster1KeyFactory(const SoftwareKeyBlobMaker* blob_maker,
+    EcdsaKeymaster1KeyFactory(const SoftwareKeyBlobMaker& blob_maker,
+                              const KeymasterContext& context,  //
                               const Keymaster1Engine* engine);
 
     keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
-                                  KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
-                                  AuthorizationSet* sw_enforced) const override;
+                                  UniquePtr<Key> attest_key,            //
+                                  const KeymasterBlob& issuer_subject,  //
+                                  KeymasterKeyBlob* key_blob,           //
+                                  AuthorizationSet* hw_enforced,        //
+                                  AuthorizationSet* sw_enforced,
+                                  CertificateChain* cert_chain) const override;
 
     keymaster_error_t ImportKey(const AuthorizationSet& key_description,
                                 keymaster_key_format_t input_key_material_format,
                                 const KeymasterKeyBlob& input_key_material,
-                                KeymasterKeyBlob* output_key_blob, AuthorizationSet* hw_enforced,
-                                AuthorizationSet* sw_enforced) const override;
+                                UniquePtr<Key> attest_key,  //
+                                const KeymasterBlob& issuer_subject,
+                                KeymasterKeyBlob* output_key_blob,  //
+                                AuthorizationSet* hw_enforced,      //
+                                AuthorizationSet* sw_enforced,
+                                CertificateChain* cert_chain) const override;
 
     keymaster_error_t LoadKey(KeymasterKeyBlob&& key_material,
                               const AuthorizationSet& additional_params,
-                              AuthorizationSet&& hw_enforced,
-                              AuthorizationSet&& sw_enforced,
+                              AuthorizationSet&& hw_enforced, AuthorizationSet&& sw_enforced,
                               UniquePtr<Key>* key) const override;
 
     OperationFactory* GetOperationFactory(keymaster_purpose_t purpose) const override;
@@ -74,5 +81,3 @@
 };
 
 }  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_ECDSA_KEYMASTER1_KEY_H_
diff --git a/include/keymaster/legacy_support/keymaster0_engine.h b/include/keymaster/legacy_support/keymaster0_engine.h
deleted file mode 100644
index ca3908b..0000000
--- a/include/keymaster/legacy_support/keymaster0_engine.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2015 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_KEYMASTER_KEYMASTER0_ENGINE_H_
-#define SYSTEM_KEYMASTER_KEYMASTER0_ENGINE_H_
-
-#include <memory>
-
-#include <openssl/ec.h>
-#include <openssl/engine.h>
-#include <openssl/ex_data.h>
-#include <openssl/rsa.h>
-
-#include <hardware/keymaster0.h>
-#include <hardware/keymaster_defs.h>
-
-namespace keymaster {
-
-template<typename BlobType> struct TKeymasterBlob;
-typedef TKeymasterBlob<keymaster_key_blob_t> KeymasterKeyBlob;
-
-/* Keymaster0Engine is a BoringSSL ENGINE that implements RSA & EC by forwarding the requested
- * operations to a keymaster0 module. */
-class Keymaster0Engine {
-  public:
-    /**
-     * Create a Keymaster0Engine, wrapping the provided keymaster0_device.  The engine takes
-     * ownership of the device, and will close it during destruction.
-     */
-    explicit Keymaster0Engine(const keymaster0_device_t* keymaster0_device);
-    ~Keymaster0Engine();
-
-    bool supports_ec() const { return supports_ec_; }
-
-    bool GenerateRsaKey(uint64_t public_exponent, uint32_t public_modulus,
-                        KeymasterKeyBlob* key_material) const;
-    bool GenerateEcKey(uint32_t key_size, KeymasterKeyBlob* key_material) const;
-
-    bool ImportKey(keymaster_key_format_t key_format, const KeymasterKeyBlob& to_import,
-                   KeymasterKeyBlob* imported_key_material) const;
-    bool DeleteKey(const KeymasterKeyBlob& blob) const;
-    bool DeleteAllKeys() const;
-
-    RSA* BlobToRsaKey(const KeymasterKeyBlob& blob) const;
-    EC_KEY* BlobToEcKey(const KeymasterKeyBlob& blob) const;
-
-    const keymaster_key_blob_t* RsaKeyToBlob(const RSA* rsa) const;
-    const keymaster_key_blob_t* EcKeyToBlob(const EC_KEY* rsa) const;
-
-    const keymaster0_device_t* device() { return keymaster0_device_; }
-
-    EVP_PKEY* GetKeymaster0PublicKey(const KeymasterKeyBlob& blob) const;
-
-  private:
-    Keymaster0Engine(const Keymaster0Engine&);  // Uncopyable
-    void operator=(const Keymaster0Engine&);    // Unassignable
-
-    static int keyblob_dup(CRYPTO_EX_DATA* to, const CRYPTO_EX_DATA* from, void** from_d, int index,
-                           long argl, void* argp);
-    static void keyblob_free(void* parent, void* ptr, CRYPTO_EX_DATA* data, int index, long argl,
-                             void* argp);
-    static int rsa_private_transform(RSA* rsa, uint8_t* out, const uint8_t* in, size_t len);
-    static int ecdsa_sign(const uint8_t* digest, size_t digest_len, uint8_t* sig,
-                          unsigned int* sig_len, EC_KEY* ec_key);
-
-    struct Malloc_Delete {
-        void operator()(void* p) { free(p); }
-    };
-
-    bool Keymaster0Sign(const void* signing_params, const keymaster_key_blob_t& key_blob,
-                        const uint8_t* data, const size_t data_length,
-                        std::unique_ptr<uint8_t[], Malloc_Delete>* signature,
-                        size_t* signature_length) const;
-
-    int RsaPrivateTransform(RSA* rsa, uint8_t* out, const uint8_t* in, size_t len) const;
-    int EcdsaSign(const uint8_t* digest, size_t digest_len, uint8_t* sig, unsigned int* sig_len,
-                  EC_KEY* ec_key) const;
-
-    const keymaster0_device_t* keymaster0_device_;
-    ENGINE* const engine_;
-    int rsa_index_, ec_key_index_;
-    bool supports_ec_;
-    RSA_METHOD rsa_method_;
-    ECDSA_METHOD ecdsa_method_;
-
-    static Keymaster0Engine* instance_;
-};
-
-}  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_KEYMASTER0_ENGINE_H_
diff --git a/include/keymaster/legacy_support/keymaster1_engine.h b/include/keymaster/legacy_support/keymaster1_engine.h
index 9fe9ee9..004dbe2 100644
--- a/include/keymaster/legacy_support/keymaster1_engine.h
+++ b/include/keymaster/legacy_support/keymaster1_engine.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_KEYMASTER1_ENGINE_H_
-#define SYSTEM_KEYMASTER_KEYMASTER1_ENGINE_H_
+#pragma once
 
 #include <memory>
 
@@ -31,7 +30,6 @@
 #include <keymaster/authorization_set.h>
 #include <keymaster/km_openssl/openssl_utils.h>
 
-
 namespace keymaster {
 
 class Keymaster1Engine {
@@ -96,7 +94,9 @@
                                        keymaster_blob_t* output);
 
     static int duplicate_key_data(CRYPTO_EX_DATA* to, const CRYPTO_EX_DATA* from, void** from_d,
+                                  // NOLINTNEXTLINE(google-runtime-int)
                                   int index, long argl, void* argp);
+    // NOLINTNEXTLINE(google-runtime-int)
     static void free_key_data(void* parent, void* ptr, CRYPTO_EX_DATA* data, int index, long argl,
                               void* argp);
 
@@ -119,5 +119,3 @@
 };
 
 }  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_KEYMASTER1_ENGINE_H_
diff --git a/include/keymaster/legacy_support/keymaster1_legacy_support.h b/include/keymaster/legacy_support/keymaster1_legacy_support.h
index 5ecc4b8..a09b5e5 100644
--- a/include/keymaster/legacy_support/keymaster1_legacy_support.h
+++ b/include/keymaster/legacy_support/keymaster1_legacy_support.h
@@ -15,30 +15,29 @@
 ** limitations under the License.
 */
 
-#ifndef LEGACY_SUPPORT_KEYMASTER1_LEGACY_SUPPORT_H_
-#define LEGACY_SUPPORT_KEYMASTER1_LEGACY_SUPPORT_H_
+#pragma once
 
 #include <map>
 #include <vector>
 
-#include <hardware/keymaster_defs.h>
 #include <hardware/keymaster1.h>
+#include <hardware/keymaster_defs.h>
 
+#include <keymaster/UniquePtr.h>
 #include <keymaster/android_keymaster_utils.h>
 #include <keymaster/authorization_set.h>
 #include <keymaster/key_factory.h>
-#include <keymaster/UniquePtr.h>
 
 #include "ec_keymaster1_key.h"
+#include "keymaster1_engine.h"
 #include "keymaster_passthrough_engine.h"
 #include "keymaster_passthrough_key.h"
-#include "keymaster1_engine.h"
 #include "rsa_keymaster1_key.h"
 
 namespace keymaster {
 
 class Keymaster1LegacySupport {
-public:
+  public:
     typedef std::pair<keymaster_algorithm_t, keymaster_purpose_t> AlgPurposePair;
     typedef std::map<AlgPurposePair, std::vector<keymaster_digest_t>> DigestMap;
 
@@ -49,57 +48,61 @@
     bool RequiresSoftwareDigesting(const keymaster_digest_t digest,
                                    const AuthProxy& key_description) const;
 
-private:
+  private:
     DigestMap device_digests_;
     bool supports_all_;
-
 };
 
 class SoftwareKeyBlobMaker;
 
-template<typename KM1_SOFTDIGEST_FACTORY>
-class Keymaster1ArbitrationFactory : public KeyFactory {
-public:
-    template<typename... SOFT_FACTORY_CONSRUCTOR_ARGS>
+template <typename KM1_SOFTDIGEST_FACTORY> class Keymaster1ArbitrationFactory : public KeyFactory {
+  public:
+    template <typename... SOFT_FACTORY_CONSRUCTOR_ARGS>
     Keymaster1ArbitrationFactory(const KeymasterPassthroughEngine* ptengine,
-                                 keymaster_algorithm_t algorithm,
-                                 const keymaster1_device_t* dev,
+                                 keymaster_algorithm_t algorithm, const keymaster1_device_t* dev,
                                  SOFT_FACTORY_CONSRUCTOR_ARGS&&... args)
-            : software_digest_factory_(forward<SOFT_FACTORY_CONSRUCTOR_ARGS>(args)...),
-              passthrough_factory_(ptengine, algorithm),
-              legacy_support_(dev){}
+        : software_digest_factory_(forward<SOFT_FACTORY_CONSRUCTOR_ARGS>(args)...),
+          passthrough_factory_(ptengine, algorithm), legacy_support_(dev) {}
     keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
-                                  KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
-                                  AuthorizationSet* sw_enforced) const {
+                                  UniquePtr<Key> attest_key,  //
+                                  const KeymasterBlob& issuer_subject,
+                                  KeymasterKeyBlob* key_blob,     //
+                                  AuthorizationSet* hw_enforced,  //
+                                  AuthorizationSet* sw_enforced,
+                                  CertificateChain* cert_chain) const {
         if (legacy_support_.RequiresSoftwareDigesting(key_description)) {
-            return software_digest_factory_.GenerateKey(key_description, key_blob, hw_enforced,
-                                                 sw_enforced);
+            return software_digest_factory_.GenerateKey(key_description, move(attest_key),
+                                                        issuer_subject, key_blob, hw_enforced,
+                                                        sw_enforced, cert_chain);
         } else {
-            return passthrough_factory_.GenerateKey(key_description, key_blob, hw_enforced,
-                                                    sw_enforced);
+            return passthrough_factory_.GenerateKey(key_description, move(attest_key),
+                                                    issuer_subject, key_blob, hw_enforced,
+                                                    sw_enforced, cert_chain);
         }
     }
 
     keymaster_error_t ImportKey(const AuthorizationSet& key_description,
                                 keymaster_key_format_t input_key_material_format,
                                 const KeymasterKeyBlob& input_key_material,
-                                KeymasterKeyBlob* output_key_blob, AuthorizationSet* hw_enforced,
-                                AuthorizationSet* sw_enforced) const {
+                                UniquePtr<Key> attest_key,  //
+                                const KeymasterBlob& issuer_subject,
+                                KeymasterKeyBlob* output_key_blob,  //
+                                AuthorizationSet* hw_enforced,      //
+                                AuthorizationSet* sw_enforced, CertificateChain* cert_chain) const {
         if (legacy_support_.RequiresSoftwareDigesting(key_description)) {
-            return software_digest_factory_.ImportKey(key_description, input_key_material_format,
-                                                      input_key_material, output_key_blob,
-                                                      hw_enforced, sw_enforced);
+            return software_digest_factory_.ImportKey(
+                key_description, input_key_material_format, input_key_material, move(attest_key),
+                issuer_subject, output_key_blob, hw_enforced, sw_enforced, cert_chain);
         } else {
-            return passthrough_factory_.ImportKey(key_description, input_key_material_format,
-                                                  input_key_material, output_key_blob,
-                                                  hw_enforced, sw_enforced);
+            return passthrough_factory_.ImportKey(
+                key_description, input_key_material_format, input_key_material, move(attest_key),
+                issuer_subject, output_key_blob, hw_enforced, sw_enforced, cert_chain);
         }
     }
 
     keymaster_error_t LoadKey(KeymasterKeyBlob&& key_material,
                               const AuthorizationSet& additional_params,
-                              AuthorizationSet&& hw_enforced,
-                              AuthorizationSet&& sw_enforced,
+                              AuthorizationSet&& hw_enforced, AuthorizationSet&& sw_enforced,
                               UniquePtr<Key>* key) const override {
         keymaster_digest_t digest;
         if (!additional_params.GetTagValue(TAG_DIGEST, &digest)) {
@@ -124,7 +127,7 @@
     }
 
     // Informational methods.
-    const keymaster_key_format_t* SupportedImportFormats(size_t* format_count) const  override {
+    const keymaster_key_format_t* SupportedImportFormats(size_t* format_count) const override {
         *format_count = 0;
         return nullptr;
     }
@@ -133,36 +136,30 @@
         return nullptr;
     }
 
-private:
+  private:
     KM1_SOFTDIGEST_FACTORY software_digest_factory_;
     KeymasterPassthroughKeyFactory passthrough_factory_;
     Keymaster1LegacySupport legacy_support_;
 };
 
-template<>
-keymaster_error_t
-Keymaster1ArbitrationFactory<EcdsaKeymaster1KeyFactory>::GenerateKey(
-        const AuthorizationSet& key_description,
-        KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
-        AuthorizationSet* sw_enforced) const;
+template <>
+keymaster_error_t Keymaster1ArbitrationFactory<EcdsaKeymaster1KeyFactory>::GenerateKey(
+    const AuthorizationSet& key_description,  //
+    UniquePtr<Key> attest_key,                //
+    const KeymasterBlob& issuer_subject,      //
+    KeymasterKeyBlob* key_blob,               //
+    AuthorizationSet* hw_enforced,            //
+    AuthorizationSet* sw_enforced,            //
+    CertificateChain* cert_chain) const;
 
+template <>
+keymaster_error_t Keymaster1ArbitrationFactory<EcdsaKeymaster1KeyFactory>::LoadKey(
+    KeymasterKeyBlob&& key_material, const AuthorizationSet& additional_params,
+    AuthorizationSet&& hw_enforced, AuthorizationSet&& sw_enforced, UniquePtr<Key>* key) const;
 
-template<>
-keymaster_error_t
-Keymaster1ArbitrationFactory<EcdsaKeymaster1KeyFactory>::LoadKey(KeymasterKeyBlob&& key_material,
-        const AuthorizationSet& additional_params,
-        AuthorizationSet&& hw_enforced,
-        AuthorizationSet&& sw_enforced,
-        UniquePtr<Key>* key) const;
+template <>
+keymaster_error_t Keymaster1ArbitrationFactory<RsaKeymaster1KeyFactory>::LoadKey(
+    KeymasterKeyBlob&& key_material, const AuthorizationSet& additional_params,
+    AuthorizationSet&& hw_enforced, AuthorizationSet&& sw_enforced, UniquePtr<Key>* key) const;
 
-template<>
-keymaster_error_t
-Keymaster1ArbitrationFactory<RsaKeymaster1KeyFactory>::LoadKey(KeymasterKeyBlob&& key_material,
-        const AuthorizationSet& additional_params,
-        AuthorizationSet&& hw_enforced,
-        AuthorizationSet&& sw_enforced,
-        UniquePtr<Key>* key) const;
-
-} // namespace keymaster
-
-#endif  // LEGACY_SUPPORT_KEYMASTER1_LEGACY_SUPPORT_H_
+}  // namespace keymaster
diff --git a/include/keymaster/legacy_support/keymaster_passthrough_engine.h b/include/keymaster/legacy_support/keymaster_passthrough_engine.h
index a986ffe..5d43cbe 100644
--- a/include/keymaster/legacy_support/keymaster_passthrough_engine.h
+++ b/include/keymaster/legacy_support/keymaster_passthrough_engine.h
@@ -15,8 +15,7 @@
 ** limitations under the License.
 */
 
-#ifndef SYSTEM_KEYMASTER_KEYMASTER2_ENGINE_H_
-#define SYSTEM_KEYMASTER_KEYMASTER2_ENGINE_H_
+#pragma once
 
 #include <memory>
 
@@ -41,32 +40,30 @@
   public:
     virtual ~KeymasterPassthroughEngine() {}
     virtual keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
-                                  KeymasterKeyBlob* key_material, AuthorizationSet* hw_enforced,
-                                  AuthorizationSet* sw_enforced) const = 0;
+                                          KeymasterKeyBlob* key_material,
+                                          AuthorizationSet* hw_enforced,
+                                          AuthorizationSet* sw_enforced) const = 0;
 
     virtual keymaster_error_t ImportKey(const AuthorizationSet& key_description,
-                                keymaster_key_format_t input_key_material_format,
-                                const KeymasterKeyBlob& input_key_material,
-                                KeymasterKeyBlob* output_key_blob, AuthorizationSet* hw_enforced,
-                                AuthorizationSet* sw_enforced) const = 0;
-    virtual keymaster_error_t ExportKey(keymaster_key_format_t format,
-            const KeymasterKeyBlob& blob,
-            const KeymasterBlob& client_id,
-            const KeymasterBlob& app_data,
-            KeymasterBlob* export_data) const = 0;
+                                        keymaster_key_format_t input_key_material_format,
+                                        const KeymasterKeyBlob& input_key_material,
+                                        KeymasterKeyBlob* output_key_blob,
+                                        AuthorizationSet* hw_enforced,
+                                        AuthorizationSet* sw_enforced) const = 0;
+    virtual keymaster_error_t ExportKey(keymaster_key_format_t format, const KeymasterKeyBlob& blob,
+                                        const KeymasterBlob& client_id,
+                                        const KeymasterBlob& app_data,
+                                        KeymasterBlob* export_data) const = 0;
     virtual keymaster_error_t DeleteKey(const KeymasterKeyBlob& blob) const = 0;
     virtual keymaster_error_t DeleteAllKeys() const = 0;
     virtual OperationFactory* GetOperationFactory(keymaster_purpose_t purpose,
                                                   keymaster_algorithm_t algorithm) const = 0;
 
-    static UniquePtr<KeymasterPassthroughEngine>
-    createInstance(const keymaster1_device_t* dev);
-    static UniquePtr<KeymasterPassthroughEngine>
-    createInstance(const keymaster2_device_t* dev);
+    static UniquePtr<KeymasterPassthroughEngine> createInstance(const keymaster1_device_t* dev);
+    static UniquePtr<KeymasterPassthroughEngine> createInstance(const keymaster2_device_t* dev);
+
   protected:
     KeymasterPassthroughEngine() {}
 };
 
-} // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_KEYMASTER2_ENGINE_H_
+}  // namespace keymaster
diff --git a/include/keymaster/legacy_support/keymaster_passthrough_key.h b/include/keymaster/legacy_support/keymaster_passthrough_key.h
index da51758..e262181 100644
--- a/include/keymaster/legacy_support/keymaster_passthrough_key.h
+++ b/include/keymaster/legacy_support/keymaster_passthrough_key.h
@@ -15,50 +15,55 @@
 ** limitations under the License.
 */
 
-#ifndef SYSTEM_KEYMASTER_KEYMASTER_PASSTHROUGH_KEY_H_
-#define SYSTEM_KEYMASTER_KEYMASTER_PASSTHROUGH_KEY_H_
+#pragma once
 
-#include <keymaster/key.h>
 #include <keymaster/android_keymaster_utils.h>
-#include <keymaster/logger.h>
-#include <keymaster/key_factory.h>
 #include <keymaster/authorization_set.h>
+#include <keymaster/key.h>
+#include <keymaster/key_factory.h>
+#include <keymaster/logger.h>
 
 #include "keymaster_passthrough_engine.h"
 
 namespace keymaster {
 
-//class SoftKeymasterContext;
+// class SoftKeymasterContext;
 
 /**
- * KeymasterPassthroughKeyFactory is a KeyFactory that creates and loads keys which are actually backed
- * by a hardware keymaster2 module.
+ * KeymasterPassthroughKeyFactory is a KeyFactory that creates and loads keys which are actually
+ * backed by a hardware keymaster2 module.
  */
 class KeymasterPassthroughKeyFactory : public KeyFactory {
     using engine_t = KeymasterPassthroughEngine;
+
   public:
     KeymasterPassthroughKeyFactory(const engine_t* engine, keymaster_algorithm_t algorithm)
-          : KeyFactory(), engine_(engine), algorithm_(algorithm) {}
+        : KeyFactory(), engine_(engine), algorithm_(algorithm) {}
 
     keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
+                                  UniquePtr<Key> /* attest_key */,
+                                  const KeymasterBlob& /* issuer_subject */,
                                   KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
-                                  AuthorizationSet* sw_enforced) const override {
+                                  AuthorizationSet* sw_enforced,
+                                  CertificateChain* /* cert_chain */) const override {
         return engine_->GenerateKey(key_description, key_blob, hw_enforced, sw_enforced);
     }
 
     keymaster_error_t ImportKey(const AuthorizationSet& key_description,
                                 keymaster_key_format_t input_key_material_format,
                                 const KeymasterKeyBlob& input_key_material,
+                                UniquePtr<Key> /* attest_key */,
+                                const KeymasterBlob& /* issuer_subject */,
                                 KeymasterKeyBlob* output_key_blob, AuthorizationSet* hw_enforced,
-                                AuthorizationSet* sw_enforced) const override {
+                                AuthorizationSet* sw_enforced,
+                                CertificateChain* /* cert_chain */) const override {
         return engine_->ImportKey(key_description, input_key_material_format, input_key_material,
                                   output_key_blob, hw_enforced, sw_enforced);
     }
 
     keymaster_error_t LoadKey(KeymasterKeyBlob&& key_material,
                               const AuthorizationSet& additional_params,
-                              AuthorizationSet&& hw_enforced,
-                              AuthorizationSet&& sw_enforced,
+                              AuthorizationSet&& hw_enforced, AuthorizationSet&& sw_enforced,
                               UniquePtr<Key>* key) const override;
 
     OperationFactory* GetOperationFactory(keymaster_purpose_t purpose) const override {
@@ -76,16 +81,15 @@
 class KeymasterPassthroughKey : public Key {
   public:
     KeymasterPassthroughKey(KeymasterKeyBlob&& key_material, AuthorizationSet&& hw_enforced,
-                       AuthorizationSet&& sw_enforced,
-                       const KeyFactory* key_factory, keymaster_error_t* error,
-                       const AuthorizationSet& additional_parameters,
-                       const KeymasterPassthroughEngine* engine)
+                            AuthorizationSet&& sw_enforced, const KeyFactory* key_factory,
+                            keymaster_error_t* error, const AuthorizationSet& additional_parameters,
+                            const KeymasterPassthroughEngine* engine)
         : Key(move(hw_enforced), move(sw_enforced), key_factory),
           additional_parameters_(additional_parameters), engine_(engine) {
         key_material_ = move(key_material);
         if (*error != KM_ERROR_OK) return;
-        if (additional_parameters.is_valid() != additional_parameters_.is_valid()
-                && additional_parameters_.is_valid() == AuthorizationSet::ALLOCATION_FAILURE) {
+        if (additional_parameters.is_valid() != additional_parameters_.is_valid() &&
+            additional_parameters_.is_valid() == AuthorizationSet::ALLOCATION_FAILURE) {
             *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
         }
     }
@@ -100,5 +104,3 @@
 };
 
 }  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_KEYMASTER_PASSTHROUGH_KEY_H_
diff --git a/include/keymaster/legacy_support/rsa_keymaster0_key.h b/include/keymaster/legacy_support/rsa_keymaster0_key.h
deleted file mode 100644
index faf13ed..0000000
--- a/include/keymaster/legacy_support/rsa_keymaster0_key.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2015 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_KEYMASTER_RSA_KEYMASTER0_KEY_H_
-#define SYSTEM_KEYMASTER_RSA_KEYMASTER0_KEY_H_
-
-#include <openssl/rsa.h>
-
-#include <keymaster/km_openssl/rsa_key.h>
-#include <keymaster/km_openssl/rsa_key_factory.h>
-
-namespace keymaster {
-
-class Keymaster0Engine;
-
-/**
- * An RsaKeyFactory which can delegate key generation, importing and loading operations to a
- * keymaster0-backed OpenSSL engine.
- */
-class RsaKeymaster0KeyFactory : public RsaKeyFactory {
-    typedef RsaKeyFactory super;
-
-  public:
-    RsaKeymaster0KeyFactory(const SoftwareKeyBlobMaker* blob_maker,
-                            const Keymaster0Engine* engine);
-
-    keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
-                                  KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
-                                  AuthorizationSet* sw_enforced) const override;
-
-    keymaster_error_t ImportKey(const AuthorizationSet& key_description,
-                                keymaster_key_format_t input_key_material_format,
-                                const KeymasterKeyBlob& input_key_material,
-                                KeymasterKeyBlob* output_key_blob, AuthorizationSet* hw_enforced,
-                                AuthorizationSet* sw_enforced) const override;
-
-    keymaster_error_t LoadKey(KeymasterKeyBlob&& key_material,
-                              const AuthorizationSet& additional_params,
-                              AuthorizationSet&& hw_enforced,
-                              AuthorizationSet&& sw_enforced,
-                              UniquePtr<Key>* key) const override;
-
-  private:
-    const Keymaster0Engine* engine_;
-};
-
-class RsaKeymaster0Key : public RsaKey {
-  public:
-    RsaKeymaster0Key(RSA* rsa_key, AuthorizationSet&& hw_enforced,
-                     AuthorizationSet&& sw_enforced,
-                     const KeyFactory* key_factory)
-        : RsaKey(rsa_key, move(hw_enforced), move(sw_enforced), key_factory) {}
-};
-
-}  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_RSA_KEYMASTER0_KEY_H_
diff --git a/include/keymaster/legacy_support/rsa_keymaster1_key.h b/include/keymaster/legacy_support/rsa_keymaster1_key.h
index 43c5e10..e114aef 100644
--- a/include/keymaster/legacy_support/rsa_keymaster1_key.h
+++ b/include/keymaster/legacy_support/rsa_keymaster1_key.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_RSA_KEYMASTER1_KEY_H_
-#define SYSTEM_KEYMASTER_RSA_KEYMASTER1_KEY_H_
+#pragma once
 
 #include <openssl/rsa.h>
 
@@ -39,23 +38,30 @@
  */
 class RsaKeymaster1KeyFactory : public RsaKeyFactory {
   public:
-    RsaKeymaster1KeyFactory(const SoftwareKeyBlobMaker* blob_maker,
+    RsaKeymaster1KeyFactory(const SoftwareKeyBlobMaker& blob_maker, const KeymasterContext& context,
                             const Keymaster1Engine* engine);
 
     keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
-                                  KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
-                                  AuthorizationSet* sw_enforced) const override;
+                                  UniquePtr<Key> attest_key,            //
+                                  const KeymasterBlob& issuer_subject,  //
+                                  KeymasterKeyBlob* key_blob,
+                                  AuthorizationSet* hw_enforced,  //
+                                  AuthorizationSet* sw_enforced,
+                                  CertificateChain* cert_chain) const override;
 
     keymaster_error_t ImportKey(const AuthorizationSet& key_description,
                                 keymaster_key_format_t input_key_material_format,
                                 const KeymasterKeyBlob& input_key_material,
-                                KeymasterKeyBlob* output_key_blob, AuthorizationSet* hw_enforced,
-                                AuthorizationSet* sw_enforced) const override;
+                                UniquePtr<Key> attest_key,  //
+                                const KeymasterBlob& issuer_subject,
+                                KeymasterKeyBlob* output_key_blob,
+                                AuthorizationSet* hw_enforced,  //
+                                AuthorizationSet* sw_enforced,
+                                CertificateChain* cert_chain) const override;
 
     keymaster_error_t LoadKey(KeymasterKeyBlob&& key_material,
                               const AuthorizationSet& additional_params,
-                              AuthorizationSet&& hw_enforced,
-                              AuthorizationSet&& sw_enforced,
+                              AuthorizationSet&& hw_enforced, AuthorizationSet&& sw_enforced,
                               UniquePtr<Key>* key) const override;
 
     OperationFactory* GetOperationFactory(keymaster_purpose_t purpose) const override;
@@ -71,12 +77,9 @@
 
 class RsaKeymaster1Key : public RsaKey {
   public:
-    RsaKeymaster1Key(RSA* rsa_key, AuthorizationSet&& hw_enforced,
-                     AuthorizationSet&& sw_enforced,
+    RsaKeymaster1Key(RSA* rsa_key, AuthorizationSet&& hw_enforced, AuthorizationSet&& sw_enforced,
                      const KeyFactory* key_factory)
         : RsaKey(rsa_key, move(hw_enforced), move(sw_enforced), key_factory) {}
 };
 
 }  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_RSA_KEYMASTER1_KEY_H_
diff --git a/include/keymaster/mem.h b/include/keymaster/mem.h
new file mode 100644
index 0000000..6d5de1b
--- /dev/null
+++ b/include/keymaster/mem.h
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace keymaster {
+
+using std::forward;
+using std::move;
+
+/*
+ * Array Manipulation functions.  This set of templated inline functions provides some nice tools
+ * for operating on c-style arrays.  C-style arrays actually do have a defined size associated with
+ * them, as long as they are not allowed to decay to a pointer.  These template methods exploit this
+ * to allow size-based array operations without explicitly specifying the size.  If passed a pointer
+ * rather than an array, they'll fail to compile.
+ */
+
+/**
+ * Return the size in bytes of the array \p a.
+ */
+template <typename T, size_t N> inline size_t array_size(const T (&a)[N]) {
+    return sizeof(a);
+}
+
+/**
+ * Return the number of elements in array \p a.
+ */
+template <typename T, size_t N> inline size_t array_length(const T (&)[N]) {
+    return N;
+}
+
+/**
+ * Duplicate the array \p a.  The memory for the new array is allocated and the caller takes
+ * responsibility.
+ */
+template <typename T> inline T* dup_array(const T* a, size_t n) {
+    T* dup = new (std::nothrow) T[n];
+    if (dup)
+        for (size_t i = 0; i < n; ++i)
+            dup[i] = a[i];
+    return dup;
+}
+
+/**
+ * Duplicate the array \p a.  The memory for the new array is allocated and the caller takes
+ * responsibility.  Note that the dup is necessarily returned as a pointer, so size is lost.  Call
+ * array_length() on the original array to discover the size.
+ */
+template <typename T, size_t N> inline T* dup_array(const T (&a)[N]) {
+    return dup_array(a, N);
+}
+
+/**
+ * Duplicate the buffer \p buf.  The memory for the new buffer is allocated and the caller takes
+ * responsibility.
+ */
+uint8_t* dup_buffer(const void* buf, size_t size);
+
+/**
+ * Copy the contents of array \p arr to \p dest.
+ */
+template <typename T, size_t N> inline void copy_array(const T (&arr)[N], T* dest) {
+    for (size_t i = 0; i < N; ++i)
+        dest[i] = arr[i];
+}
+
+/**
+ * Search array \p a for value \p val, returning true if found.  Note that this function is
+ * early-exit, meaning that it should not be used in contexts where timing analysis attacks could be
+ * a concern.
+ */
+template <typename T, size_t N> inline bool array_contains(const T (&a)[N], T val) {
+    for (size_t i = 0; i < N; ++i) {
+        if (a[i] == val) {
+            return true;
+        }
+    }
+    return false;
+}
+
+/**
+ * Variant of memset() that uses GCC-specific pragmas to disable optimizations, so effect is not
+ * optimized away.  This is important because we often need to wipe blocks of sensitive data from
+ * memory.  As an additional convenience, this implementation avoids writing to NULL pointers.
+ */
+#ifdef __clang__
+#define OPTNONE __attribute__((optnone))
+#else  // not __clang__
+#define OPTNONE __attribute__((optimize("O0")))
+#endif  // not __clang__
+inline OPTNONE void* memset_s(void* s, int c, size_t n) {
+    if (!s) return s;
+    return memset(s, c, n);
+}
+#undef OPTNONE
+
+/**
+ * Variant of memcmp that has the same runtime regardless of whether the data matches (i.e. doesn't
+ * short-circuit).  Not an exact equivalent to memcmp because it doesn't return <0 if p1 < p2, just
+ * 0 for match and non-zero for non-match.
+ */
+int memcmp_s(const void* p1, const void* p2, size_t length);
+
+/**
+ * Eraser clears buffers.  Construct it with a buffer or object and the destructor will ensure that
+ * it is zeroed.
+ */
+class Eraser {
+  public:
+    /* Not implemented.  If this gets used, we want a link error. */
+    template <typename T> explicit Eraser(T* t);
+
+    template <typename T>
+    explicit Eraser(T& t) : buf_(reinterpret_cast<uint8_t*>(&t)), size_(sizeof(t)) {}
+
+    template <size_t N> explicit Eraser(uint8_t (&arr)[N]) : buf_(arr), size_(N) {}
+
+    Eraser(void* buf, size_t size) : buf_(static_cast<uint8_t*>(buf)), size_(size) {}
+    ~Eraser() { memset_s(buf_, 0, size_); }
+
+  private:
+    Eraser(const Eraser&);
+    void operator=(const Eraser&);
+
+    uint8_t* buf_;
+    size_t size_;
+};
+
+/**
+ * ArrayWrapper is a trivial wrapper around a C-style array that provides begin() and end()
+ * methods. This is primarily to facilitate range-based iteration on arrays.  It does not copy, nor
+ * does it take ownership; it just holds pointers.
+ */
+template <typename T> class ArrayWrapper {
+  public:
+    ArrayWrapper(T* array, size_t size) : begin_(array), end_(array + size) {}
+
+    T* begin() { return begin_; }
+    T* end() { return end_; }
+
+  private:
+    T* begin_;
+    T* end_;
+};
+
+template <typename T> ArrayWrapper<T> array_range(T* begin, size_t length) {
+    return ArrayWrapper<T>(begin, length);
+}
+
+template <typename T, size_t n> ArrayWrapper<T> array_range(T (&a)[n]) {
+    return ArrayWrapper<T>(a, n);
+}
+
+struct Malloc_Delete {
+    void operator()(void* p) { free(p); }
+};
+
+}  // namespace keymaster
diff --git a/include/keymaster/new.h b/include/keymaster/new.h
deleted file mode 100644
index 17537e0..0000000
--- a/include/keymaster/new.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-**
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef INCLUDE_KEYMASTER_NEW_
-#define INCLUDE_KEYMASTER_NEW_
-
-#include <stddef.h>
-
-namespace std {
-struct nothrow_t;
-extern const nothrow_t nothrow;
-}  // namespace std
-
-#ifndef _NOEXCEPT
-#define _NOEXCEPT
-#endif
-
-void* operator new(size_t __sz, const std::nothrow_t&) _NOEXCEPT;
-void* operator new[](size_t __sz, const std::nothrow_t&) _NOEXCEPT;
-void operator delete(void* ptr);
-void operator delete[](void* ptr);
-
-#endif  // INCLUDE_KEYMASTER_NEW_
diff --git a/include/keymaster/operation.h b/include/keymaster/operation.h
index 656ba9d..e80e37a 100644
--- a/include/keymaster/operation.h
+++ b/include/keymaster/operation.h
@@ -106,6 +106,28 @@
     virtual keymaster_operation_handle_t operation_handle() const { return operation_handle_; }
 
     AuthProxy authorizations() const { return AuthProxy(hw_enforced_, sw_enforced_); }
+    AuthorizationSet hw_enforced() const { return hw_enforced_; }
+    AuthorizationSet sw_enforced() const { return sw_enforced_; }
+
+    // Creates and initializes |confirmation_verifier_buffer_| that can be retrieved with
+    // get_confirmation_verifier_buffer().
+    //
+    // Returns false on allocation failure.
+    bool create_confirmation_verifier_buffer() {
+        if (!confirmation_verifier_buffer_) {
+            Buffer* buffer = new (std::nothrow)
+                Buffer(kConfirmationTokenMessageTag, kConfirmationTokenMessageTagSize);
+            if (buffer == nullptr) {
+                return false;
+            }
+            confirmation_verifier_buffer_.reset(buffer);
+        }
+        return true;
+    }
+
+    // If a Buffer for ConfirmationUI verification was created with
+    // create_confirmation_verifier_buffer(), returns it. If not, returns |nullptr|.
+    Buffer* get_confirmation_verifier_buffer() { return confirmation_verifier_buffer_.get(); }
 
     virtual keymaster_error_t Begin(const AuthorizationSet& input_params,
                                     AuthorizationSet* output_params) = 0;
@@ -128,6 +150,7 @@
     AuthorizationSet hw_enforced_;
     AuthorizationSet sw_enforced_;
     uint64_t key_id_;
+    UniquePtr<Buffer> confirmation_verifier_buffer_;
 };
 
 }  // namespace keymaster
diff --git a/include/keymaster/operation_table.h b/include/keymaster/operation_table.h
index 5b5c068..0e2bc4b 100644
--- a/include/keymaster/operation_table.h
+++ b/include/keymaster/operation_table.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_OPERATION_TABLE_H
-#define SYSTEM_KEYMASTER_OPERATION_TABLE_H
+#pragma once
 
 #include <keymaster/UniquePtr.h>
 
@@ -27,11 +26,9 @@
 class Operation;
 using OperationPtr = UniquePtr<Operation>;
 
-
 class OperationTable {
   public:
-    explicit OperationTable(size_t table_size) :
-            table_size_(table_size) {}
+    explicit OperationTable(size_t table_size) : table_size_(table_size) {}
 
     keymaster_error_t Add(OperationPtr&& operation);
     Operation* Find(keymaster_operation_handle_t op_handle);
@@ -43,5 +40,3 @@
 };
 
 }  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_OPERATION_TABLE_H
diff --git a/include/keymaster/pure_soft_secure_key_storage.h b/include/keymaster/pure_soft_secure_key_storage.h
new file mode 100644
index 0000000..563db61
--- /dev/null
+++ b/include/keymaster/pure_soft_secure_key_storage.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <keymaster/secure_key_storage.h>
+
+namespace keymaster {
+
+class PureSoftSecureStorageMap;
+
+/**
+ * This is the pure software emulation of secure key storage.
+ */
+class PureSoftSecureKeyStorage : public SecureKeyStorage {
+  public:
+    explicit PureSoftSecureKeyStorage(uint32_t max_slot);
+    ~PureSoftSecureKeyStorage() override;
+
+    /**
+     * Writes the key blob along with the keyid as the index into pure software emulated secure
+     * key storage.
+     */
+    keymaster_error_t WriteKey(const km_id_t keyid, const KeymasterKeyBlob& blob) override;
+
+    /**
+     * Checks if the key blob with key id exists in pure software secure key storage.
+     */
+    keymaster_error_t KeyExists(const km_id_t keyid, bool* exists) override;
+
+    /**
+     * Deletes the key blob with key id from pure software secure key storage.
+     */
+    keymaster_error_t DeleteKey(const km_id_t keyid) override;
+
+    /**
+     * Deletes all the key blob from pure software secure key storage.
+     */
+    keymaster_error_t DeleteAllKeys() override;
+
+    /**
+     * Checks if the pure software secure key storage still has available slot.
+     */
+    keymaster_error_t HasSlot(bool* has_slot) override;
+
+  private:
+    PureSoftSecureStorageMap* pure_soft_secure_storage_map_;
+};
+
+}  // namespace keymaster
diff --git a/include/keymaster/random_source.h b/include/keymaster/random_source.h
index a9c45ad..2d0a492 100644
--- a/include/keymaster/random_source.h
+++ b/include/keymaster/random_source.h
@@ -15,25 +15,22 @@
 ** limitations under the License.
 */
 
-#ifndef INCLUDE_KEYMASTER_RANDOM_SOURCE_H_
-#define INCLUDE_KEYMASTER_RANDOM_SOURCE_H_
+#pragma once
 
-#include <stdint.h>
 #include <hardware/keymaster_defs.h>
+#include <stdint.h>
 
 namespace keymaster {
 
 class RandomSource {
-protected:
-    virtual ~RandomSource () {}
+  protected:
+    virtual ~RandomSource() {}
 
-public:
+  public:
     /**
      * Generates \p length random bytes, placing them in \p buf.
      */
     virtual keymaster_error_t GenerateRandom(uint8_t* buffer, size_t length) const = 0;
 };
 
-} // namespace keymaster
-
-#endif  // INCLUDE_KEYMASTER_RANDOM_SOURCE_H_
+}  // namespace keymaster
diff --git a/include/keymaster/remote_provisioning_context.h b/include/keymaster/remote_provisioning_context.h
new file mode 100644
index 0000000..a5c4d1d
--- /dev/null
+++ b/include/keymaster/remote_provisioning_context.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <array>
+#include <optional>
+#include <string>
+#include <tuple>
+#include <vector>
+
+#include <cppbor.h>
+#include <keymaster/cppcose/cppcose.h>
+
+namespace keymaster {
+
+class RemoteProvisioningContext {
+  public:
+    RemoteProvisioningContext() {}
+    virtual ~RemoteProvisioningContext(){};
+    virtual std::vector<uint8_t> DeriveBytesFromHbk(const std::string& context,
+                                                    size_t numBytes) const = 0;
+    virtual std::unique_ptr<cppbor::Map> CreateDeviceInfo() const = 0;
+    virtual std::pair<std::vector<uint8_t>, cppbor::Array> GenerateBcc(bool testMode) const = 0;
+
+    // Generate an HMAC-SHA256 over the given input. This is used to verify a given
+    // input hasn't changed across multiple calls to the remote provisioning HAL.
+    virtual std::optional<cppcose::HmacSha256>
+    GenerateHmacSha256(const cppcose::bytevec& input) const = 0;
+
+    std::vector<uint8_t> devicePrivKey_;
+    cppbor::Array bcc_;
+
+  private:
+    // Uncopyable.
+    RemoteProvisioningContext(const RemoteProvisioningContext&);
+    void operator=(const RemoteProvisioningContext&);
+};
+
+}  // namespace keymaster
diff --git a/include/keymaster/remote_provisioning_utils.h b/include/keymaster/remote_provisioning_utils.h
new file mode 100644
index 0000000..e3781de
--- /dev/null
+++ b/include/keymaster/remote_provisioning_utils.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cppbor.h>
+#include <cppbor_parse.h>
+
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/cppcose/cppcose.h>
+
+namespace keymaster {
+
+// These are the negations of the actual error codes
+constexpr keymaster_error_t kStatusFailed = static_cast<keymaster_error_t>(-1);
+constexpr keymaster_error_t kStatusInvalidMac = static_cast<keymaster_error_t>(-2);
+constexpr keymaster_error_t kStatusProductionKeyInTestRequest = static_cast<keymaster_error_t>(-3);
+constexpr keymaster_error_t kStatusTestKeyInProductionRequest = static_cast<keymaster_error_t>(-4);
+constexpr keymaster_error_t kStatusInvalidEek = static_cast<keymaster_error_t>(-5);
+
+template <typename T> class StatusOr {
+  public:
+    StatusOr(uint32_t status_code)  // NOLINT(google-explicit-constructor)
+        : status_code_(status_code) {}
+    StatusOr(T val)
+        : status_code_(0), value_(std::move(val)) {}  // NOLINT(google-explicit-constructor)
+
+    bool isOk() { return status_code_ == 0; }
+
+    T* operator->() & {
+        assert(isOk());
+        return &value_.value();
+    }
+    T& operator*() & {
+        assert(isOk());
+        return value_.value();
+    }
+    T&& operator*() && {
+        assert(isOk());
+        return std::move(value_).value();
+    }
+
+    uint32_t moveError() {
+        assert(!isOk());
+        return status_code_;
+    }
+
+    T moveValue() { return std::move(value_).value(); }
+
+  private:
+    uint32_t status_code_;
+    std::optional<T> value_;
+};
+
+StatusOr<std::pair<std::vector<uint8_t> /* EEK pub */, std::vector<uint8_t> /* EEK ID */>>
+validateAndExtractEekPubAndId(bool testMode, const KeymasterBlob& endpointEncryptionCertChain);
+
+StatusOr<std::vector<uint8_t> /* pubkeys */>
+validateAndExtractPubkeys(bool testMode, uint32_t numKeys, KeymasterBlob* keysToSign,
+                          cppcose::HmacSha256Function macFunction);
+
+cppbor::Array buildCertReqRecipients(const std::vector<uint8_t>& pubkey,
+                                     const std::vector<uint8_t>& kid);
+
+}  // namespace keymaster
diff --git a/include/keymaster/secure_key_storage.h b/include/keymaster/secure_key_storage.h
new file mode 100644
index 0000000..d4d3ad6
--- /dev/null
+++ b/include/keymaster/secure_key_storage.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <hardware/keymaster_defs.h>
+
+namespace keymaster {
+
+typedef uint64_t km_id_t;
+template <typename BlobType> struct TKeymasterBlob;
+typedef TKeymasterBlob<keymaster_key_blob_t> KeymasterKeyBlob;
+
+/**
+ * This is the reference implementation of secure key storage of Keymaster. It implements
+ * key storage on top TEE's secure storage service. All data is stored in the secure hardware,
+ * such as RPMB filesystem.
+ */
+class SecureKeyStorage {
+  public:
+    SecureKeyStorage() {}
+    virtual ~SecureKeyStorage(){};
+
+    /**
+     * Writes the key blob into secure key storage and uses the key ID as the index of this
+     * key blob. The key ID must be the same id created by KeymasterEnforcement.CreateKeyId,
+     * which means the generated id must be stable in that the same key blob bits yield the
+     * same keyid.
+     */
+    virtual keymaster_error_t WriteKey(const km_id_t keyid, const KeymasterKeyBlob& blob) = 0;
+
+    /**
+     * Checks if the key blob with key id exists in secure key storage. On success, writes to
+     * exists.
+     */
+    virtual keymaster_error_t KeyExists(const km_id_t keyid, bool* exists) = 0;
+
+    /**
+     * Deletes the key blob with key id from secure key storage.
+     */
+    virtual keymaster_error_t DeleteKey(const km_id_t keyid) = 0;
+
+    /**
+     * Deletes all the key blob from secure key storage.
+     */
+    virtual keymaster_error_t DeleteAllKeys() = 0;
+
+    /**
+     * Checks if the secure key storage still has available slot. On success, writes to has_slot.
+     */
+    virtual keymaster_error_t HasSlot(bool* has_slot) = 0;
+};
+
+}  // namespace keymaster
diff --git a/include/keymaster/serializable.h b/include/keymaster/serializable.h
index 575b691..fdc97f1 100644
--- a/include/keymaster/serializable.h
+++ b/include/keymaster/serializable.h
@@ -14,18 +14,15 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_SERIALIZABLE_H_
-#define SYSTEM_KEYMASTER_SERIALIZABLE_H_
+#pragma once
 
+#include <stddef.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 
-#include <keymaster/new.h>
-#include <stddef.h>
-// #include <new>
-
 #include <keymaster/UniquePtr.h>
+#include <keymaster/mem.h>
 
 namespace keymaster {
 
@@ -69,7 +66,7 @@
  * Convert a pointer into a value.  This is used to make sure compiler won't optimize away pointer
  * overflow checks. (See http://www.kb.cert.org/vuls/id/162289)
  */
-template <typename T> inline uintptr_t __pval(const T *p) {
+template <typename T> inline uintptr_t __pval(const T* p) {
     return reinterpret_cast<uintptr_t>(p);
 }
 
@@ -159,8 +156,7 @@
 template <typename T>
 inline bool copy_uint32_from_buf(const uint8_t** buf_ptr, const uint8_t* end, T* value) {
     uint32_t val;
-    if (!copy_from_buf(buf_ptr, end, &val, sizeof(val)))
-        return false;
+    if (!copy_from_buf(buf_ptr, end, &val, sizeof(val))) return false;
     *value = static_cast<T>(val);
     return true;
 }
@@ -182,20 +178,17 @@
 template <typename T>
 inline bool copy_uint32_array_from_buf(const uint8_t** buf_ptr, const uint8_t* end,
                                        UniquePtr<T[]>* data, size_t* count) {
-    if (!copy_uint32_from_buf(buf_ptr, end, count))
-        return false;
+    if (!copy_uint32_from_buf(buf_ptr, end, count)) return false;
 
     uintptr_t array_end = __pval(*buf_ptr) + *count * sizeof(uint32_t);
-    if (*count >= UINT32_MAX / sizeof(uint32_t) ||
-        array_end < __pval(*buf_ptr) || array_end > __pval(end))
+    if (*count >= UINT32_MAX / sizeof(uint32_t) || array_end < __pval(*buf_ptr) ||
+        array_end > __pval(end))
         return false;
 
     data->reset(new (std::nothrow) T[*count]);
-    if (!data->get())
-        return false;
+    if (!data->get()) return false;
     for (size_t i = 0; i < *count; ++i)
-        if (!copy_uint32_from_buf(buf_ptr, end, &(*data)[i]))
-            return false;
+        if (!copy_uint32_from_buf(buf_ptr, end, &(*data)[i])) return false;
     return true;
 }
 
@@ -207,6 +200,24 @@
     Buffer() : buffer_(nullptr), buffer_size_(0), read_position_(0), write_position_(0) {}
     explicit Buffer(size_t size) : buffer_(nullptr) { Reinitialize(size); }
     Buffer(const void* buf, size_t size) : buffer_(nullptr) { Reinitialize(buf, size); }
+    Buffer(Buffer&& b) { *this = move(b); }
+    Buffer(const Buffer&) = delete;
+
+    ~Buffer() { Clear(); }
+
+    Buffer& operator=(Buffer&& other) {
+        if (this == &other) return *this;
+        buffer_ = move(other.buffer_);
+        buffer_size_ = other.buffer_size_;
+        other.buffer_size_ = 0;
+        read_position_ = other.read_position_;
+        other.read_position_ = 0;
+        write_position_ = other.write_position_;
+        other.write_position_ = 0;
+        return *this;
+    }
+
+    void operator=(const Buffer& other) = delete;
 
     // Grow the buffer so that at least \p size bytes can be written.
     bool reserve(size_t size);
@@ -252,10 +263,6 @@
     bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end);
 
   private:
-    // Disallow copy construction and assignment.
-    void operator=(const Buffer& other);
-    Buffer(const Buffer&);
-
     UniquePtr<uint8_t[]> buffer_;
     size_t buffer_size_;
     size_t read_position_;
@@ -263,5 +270,3 @@
 };
 
 }  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_SERIALIZABLE_H_
diff --git a/include/keymaster/soft_key_factory.h b/include/keymaster/soft_key_factory.h
index ee494cb..f59f4ee 100644
--- a/include/keymaster/soft_key_factory.h
+++ b/include/keymaster/soft_key_factory.h
@@ -14,11 +14,9 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_SOFTWARE_KEY_FACTORY_H_
-#define SYSTEM_KEYMASTER_SOFTWARE_KEY_FACTORY_H_
+#pragma once
 
 #include "key_factory.h"
-#include <keymaster/attestation_record.h>
 
 namespace keymaster {
 
@@ -43,8 +41,8 @@
 
 class SoftKeyFactoryMixin {
   public:
-    explicit SoftKeyFactoryMixin(const SoftwareKeyBlobMaker* blob_maker)
-        : blob_maker_(*blob_maker) {}
+    explicit SoftKeyFactoryMixin(const SoftwareKeyBlobMaker& blob_maker)
+        : blob_maker_(blob_maker) {}
     virtual ~SoftKeyFactoryMixin() {}
 
   protected:
@@ -52,5 +50,3 @@
 };
 
 }  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_SOFTWARE_KEY_FACTORY_H_
diff --git a/include/keymaster/soft_keymaster_device.h b/include/keymaster/soft_keymaster_device.h
index ad757b5..67a9372 100644
--- a/include/keymaster/soft_keymaster_device.h
+++ b/include/keymaster/soft_keymaster_device.h
@@ -14,20 +14,18 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_SOFT_KEYMASTER_DEVICE_H_
-#define SYSTEM_KEYMASTER_SOFT_KEYMASTER_DEVICE_H_
+#pragma once
 
 #include <cstdlib>
 #include <map>
 #include <vector>
 
-#include <hardware/keymaster0.h>
 #include <hardware/keymaster1.h>
 #include <hardware/keymaster2.h>
 
+#include <keymaster/UniquePtr.h>
 #include <keymaster/android_keymaster.h>
 #include <keymaster/contexts/soft_keymaster_context.h>
-#include <keymaster/UniquePtr.h>
 
 namespace keymaster {
 
@@ -46,17 +44,11 @@
  */
 class SoftKeymasterDevice {
   public:
-    SoftKeymasterDevice();
+    explicit SoftKeymasterDevice(KmVersion version);
 
     explicit SoftKeymasterDevice(SoftKeymasterContext* context);
 
     /**
-     * Set SoftKeymasterDevice to wrap the speicified HW keymaster0 device.  Takes ownership of the
-     * specified device (will call keymaster0_device->common.close());
-     */
-    keymaster_error_t SetHardwareDevice(keymaster0_device_t* keymaster0_device);
-
-    /**
      * Set SoftKeymasterDevice to wrap specified HW keymaster1 device.  Takes ownership of the
      * specified device (will call keymaster1_device->common.close());
      */
@@ -250,5 +242,3 @@
 };
 
 }  // namespace keymaster
-
-#endif  // EXTERNAL_KEYMASTER_TRUSTY_KEYMASTER_DEVICE_H_
diff --git a/include/keymaster/soft_keymaster_logger.h b/include/keymaster/soft_keymaster_logger.h
index 3be83b8..9d65c00 100644
--- a/include/keymaster/soft_keymaster_logger.h
+++ b/include/keymaster/soft_keymaster_logger.h
@@ -14,21 +14,17 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_SOFT_KEYMASTER_LOGGER_H_
-#define SYSTEM_KEYMASTER_SOFT_KEYMASTER_LOGGER_H_
+#pragma once
 
 #include <keymaster/logger.h>
 
 namespace keymaster {
 
-class SoftKeymasterLogger : public Logger
-{
-public:
+class SoftKeymasterLogger : public Logger {
+  public:
     SoftKeymasterLogger() { set_instance(this); }
 
     virtual int log_msg(LogLevel level, const char* fmt, va_list args) const;
 };
 
-} // namespace keymaster
-
-#endif // SYSTEM_KEYMASTER_SOFT_KEYMASTER_LOGGER_H_
+}  // namespace keymaster
diff --git a/include/keymaster/wrapped_key.h b/include/keymaster/wrapped_key.h
index fe50e86..3331460 100644
--- a/include/keymaster/wrapped_key.h
+++ b/include/keymaster/wrapped_key.h
@@ -19,8 +19,8 @@
 
 #include <hardware/keymaster_defs.h>
 
-#include <keymaster/attestation_record.h>
 #include <keymaster/authorization_set.h>
+#include <keymaster/km_openssl/attestation_record.h>
 
 namespace keymaster {
 
diff --git a/key_blob_utils/auth_encrypted_key_blob.cpp b/key_blob_utils/auth_encrypted_key_blob.cpp
index f5bf9c8..8d81157 100644
--- a/key_blob_utils/auth_encrypted_key_blob.cpp
+++ b/key_blob_utils/auth_encrypted_key_blob.cpp
@@ -16,122 +16,329 @@
 
 #include <keymaster/key_blob_utils/auth_encrypted_key_blob.h>
 
+#include <openssl/digest.h>
+#include <openssl/evp.h>
+#include <openssl/hkdf.h>
+
 #include <keymaster/android_keymaster_utils.h>
 #include <keymaster/authorization_set.h>
 #include <keymaster/key_blob_utils/ocb_utils.h>
+#include <keymaster/km_openssl/openssl_err.h>
 #include <keymaster/logger.h>
-
+#include <keymaster/random_source.h>
 
 namespace keymaster {
 
-const uint32_t CURRENT_BLOB_VERSION = 0;
+namespace {
 
-keymaster_error_t SerializeAuthEncryptedBlob(const KeymasterKeyBlob& encrypted_key_material,
-                                             const AuthorizationSet& hw_enforced,
-                                             const AuthorizationSet& sw_enforced,
+constexpr uint8_t kAesGcmDescriptor[] = "AES-256-GCM-HKDF-SHA-256, version 1";
+constexpr size_t kAesGcmNonceLength = 12;
+constexpr size_t kAesGcmTagLength = 16;
+constexpr size_t kAes256KeyLength = 256 / 8;
 
-                                             const Buffer& nonce, const Buffer& tag,
-                                             KeymasterKeyBlob* key_blob) {
-    size_t size = 1 /* version byte */ + nonce.SerializedSize() +
-                  encrypted_key_material.SerializedSize() + tag.SerializedSize() +
-                  hw_enforced.SerializedSize() + sw_enforced.SerializedSize();
+Buffer generate_nonce(const RandomSource& random, size_t size, keymaster_error_t* error) {
+    if (!error) return {};
+    *error = KM_ERROR_OK;
 
-    if (!key_blob->Reset(size))
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    Buffer nonce;
+    if (!nonce.Reinitialize(size)) {
+        *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        return {};
+    }
 
-    uint8_t* buf = key_blob->writable_data();
-    const uint8_t* end = key_blob->key_material + key_blob->key_material_size;
+    random.GenerateRandom(nonce.peek_write(), size);
+    nonce.advance_write(size);
+    return nonce;
+}
 
-    *buf++ = CURRENT_BLOB_VERSION;
-    buf = nonce.Serialize(buf, end);
-    buf = encrypted_key_material.Serialize(buf, end);
-    buf = tag.Serialize(buf, end);
+Buffer BuildAesGcmInfo(const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+                       const AuthorizationSet& hidden, keymaster_error_t* error) {
+    if (!error) return {};
+    *error = KM_ERROR_OK;
+
+    size_t info_len = sizeof(kAesGcmDescriptor) + hidden.SerializedSize() +
+                      hw_enforced.SerializedSize() + sw_enforced.SerializedSize();
+    Buffer info(info_len);
+
+    info.write(kAesGcmDescriptor, sizeof(kAesGcmDescriptor));
+    uint8_t* buf = info.peek_write();
+    const uint8_t* end = info.peek_write() + info.available_write();
+    buf = hidden.Serialize(buf, end);
     buf = hw_enforced.Serialize(buf, end);
     buf = sw_enforced.Serialize(buf, end);
-    if (buf != key_blob->key_material + key_blob->key_material_size)
-        return KM_ERROR_UNKNOWN_ERROR;
 
-    return KM_ERROR_OK;
-}
-
-static keymaster_error_t DeserializeUnversionedBlob(const KeymasterKeyBlob& key_blob,
-                                                    KeymasterKeyBlob* encrypted_key_material,
-                                                    AuthorizationSet* hw_enforced,
-                                                    AuthorizationSet* sw_enforced, Buffer* nonce,
-                                                    Buffer* tag) {
-    const uint8_t* tmp = key_blob.key_material;
-    const uint8_t** buf_ptr = &tmp;
-    const uint8_t* end = tmp + key_blob.key_material_size;
-
-    if (!nonce->reserve(OCB_NONCE_LENGTH) || !tag->reserve(OCB_TAG_LENGTH))
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
-    if (!copy_from_buf(buf_ptr, end, nonce->peek_write(), OCB_NONCE_LENGTH) ||
-        !encrypted_key_material->Deserialize(buf_ptr, end) ||
-        !copy_from_buf(buf_ptr, end, tag->peek_write(), OCB_TAG_LENGTH) ||
-        !hw_enforced->Deserialize(buf_ptr, end) ||  //
-        !sw_enforced->Deserialize(buf_ptr, end)) {
-        LOG_D("Failed to deserialize unversioned blob (may be a HW-backed key)", 0);
-        return KM_ERROR_INVALID_KEY_BLOB;
+    if (!buf || buf != end || !info.advance_write(buf - info.peek_write())) {
+        LOG_S("Buffer management error", 0);
+        *error = KM_ERROR_UNKNOWN_ERROR;
+        return {};
     }
-    if (!nonce->advance_write(OCB_NONCE_LENGTH) || !tag->advance_write(OCB_TAG_LENGTH))
-        return KM_ERROR_UNKNOWN_ERROR;
-    return KM_ERROR_OK;
+
+    return info;
 }
 
-keymaster_error_t DeserializeAuthEncryptedBlob(const KeymasterKeyBlob& key_blob,
-                                               KeymasterKeyBlob* encrypted_key_material,
-                                               AuthorizationSet* hw_enforced,
-                                               AuthorizationSet* sw_enforced, Buffer* nonce,
-                                               Buffer* tag) {
-    if (!key_blob.key_material || key_blob.key_material_size == 0)
-        return KM_ERROR_INVALID_KEY_BLOB;
+Buffer DeriveAesGcmKeyEncryptionKey(const AuthorizationSet& hw_enforced,
+                                    const AuthorizationSet& sw_enforced,
+                                    const AuthorizationSet& hidden,
+                                    const KeymasterKeyBlob& master_key, keymaster_error_t* error) {
+    if (!error) return {};
+    *error = KM_ERROR_OK;
+
+    Buffer prk(EVP_MAX_MD_SIZE);
+    size_t out_len = EVP_MAX_MD_SIZE;
+    if (!HKDF_extract(prk.peek_write(), &out_len, EVP_sha256(), master_key.key_material,
+                      master_key.key_material_size, nullptr /* salt */, 0 /* salt_len */)) {
+        *error = TranslateLastOpenSslError();
+        return {};
+    }
+
+    Buffer info = BuildAesGcmInfo(hw_enforced, sw_enforced, hidden, error);
+    if (KM_ERROR_OK != *error) return {};
+
+    if (!prk.advance_write(out_len) || !prk.available_read() || !info.available_read()) {
+        *error = KM_ERROR_UNKNOWN_ERROR;
+        return {};
+    }
+
+    Buffer keyEncryptionKey(kAes256KeyLength);
+    if (!HKDF_expand(keyEncryptionKey.peek_write(), keyEncryptionKey.available_write(),  //
+                     EVP_sha256(),                                                       //
+                     prk.peek_read(), prk.available_read(),                              //
+                     info.peek_read(), info.available_read())) {
+        *error = TranslateLastOpenSslError();
+        return {};
+    }
+
+    return keyEncryptionKey;
+}
+
+EncryptedKey AesGcmEncryptKey(const AuthorizationSet& hw_enforced,  //
+                              const AuthorizationSet& sw_enforced,  //
+                              const AuthorizationSet& hidden,       //
+                              const KeymasterKeyBlob& master_key,   //
+                              const KeymasterKeyBlob& plaintext,    //
+                              AuthEncryptedBlobFormat format,       //
+                              Buffer nonce,                         //
+                              keymaster_error_t* error) {
+    if (!error) return {};
+    *error = KM_ERROR_OK;
+
+    Buffer kek = DeriveAesGcmKeyEncryptionKey(hw_enforced, sw_enforced, hidden, master_key, error);
+    if (KM_ERROR_OK != *error) return {};
+
+    bssl::UniquePtr<EVP_CIPHER_CTX> ctx(EVP_CIPHER_CTX_new());
+    if (!ctx) {
+        *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        return {};
+    }
+
+    int ciphertext_len = plaintext.size();
+    int unused_len = 0;
+    EncryptedKey retval;
+    retval.format = format;
+    retval.ciphertext = KeymasterKeyBlob(ciphertext_len);
+    retval.nonce = move(nonce);
+    retval.tag = Buffer(kAesGcmTagLength);
+
+    if (!(EVP_EncryptInit_ex(ctx.get(), EVP_aes_256_gcm(), nullptr /* engine */, kek.peek_read(),
+                             retval.nonce.peek_read()) &&
+          EVP_EncryptUpdate(ctx.get(), retval.ciphertext.writable_data(), &ciphertext_len,
+                            plaintext.key_material, plaintext.size()) &&
+          EVP_EncryptFinal_ex(ctx.get(), retval.ciphertext.writable_data() /* not written to */,
+                              &unused_len) &&
+          EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, kAesGcmTagLength,
+                              retval.tag.peek_write()))) {
+        *error = TranslateLastOpenSslError();
+        return {};
+    }
+
+    if (plaintext.size() != static_cast<size_t>(ciphertext_len) || 0 != unused_len ||
+        !retval.tag.advance_write(kAesGcmTagLength)) {
+        *error = KM_ERROR_UNKNOWN_ERROR;
+    }
+
+    return retval;
+}
+
+KeymasterKeyBlob AesGcmDecryptKey(const DeserializedKey& key, const AuthorizationSet& hidden,
+                                  const KeymasterKeyBlob& master_key, keymaster_error_t* error) {
+    if (!error) return {};
+    *error = KM_ERROR_OK;
+
+    Buffer kek =
+        DeriveAesGcmKeyEncryptionKey(key.hw_enforced, key.sw_enforced, hidden, master_key, error);
+    if (KM_ERROR_OK != *error) return {};
+
+    bssl::UniquePtr<EVP_CIPHER_CTX> ctx(EVP_CIPHER_CTX_new());
+    if (!ctx) {
+        *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        return {};
+    }
+
+    int plaintext_len = key.encrypted_key.ciphertext.size();
+    int unused_len = 0;
+    KeymasterKeyBlob plaintext(plaintext_len);
+    if (!(EVP_DecryptInit_ex(ctx.get(), EVP_aes_256_gcm(), nullptr /* engine */, kek.peek_read(),
+                             key.encrypted_key.nonce.peek_read()) &&
+          EVP_DecryptUpdate(ctx.get(), plaintext.writable_data(), &plaintext_len,
+                            key.encrypted_key.ciphertext.key_material,
+                            key.encrypted_key.ciphertext.size()) &&
+          EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, kAesGcmTagLength,
+                              const_cast<uint8_t*>(key.encrypted_key.tag.peek_read())))) {
+        *error = TranslateLastOpenSslError();
+        return {};
+    }
+
+    if (!EVP_DecryptFinal_ex(ctx.get(), plaintext.writable_data() /* not written to */,
+                             &unused_len)) {
+        *error = KM_ERROR_INVALID_KEY_BLOB;
+        return {};
+    }
+
+    if (key.encrypted_key.ciphertext.size() != plaintext.size() || 0 != unused_len) {
+        *error = KM_ERROR_UNKNOWN_ERROR;
+    }
+
+    return plaintext;
+}
+
+}  // namespace
+
+KeymasterKeyBlob SerializeAuthEncryptedBlob(const EncryptedKey& encrypted_key,
+                                            const AuthorizationSet& hw_enforced,
+                                            const AuthorizationSet& sw_enforced,
+                                            keymaster_error_t* error) {
+    if (!error) return {};
+    *error = KM_ERROR_OK;
+
+    size_t size = 1 /* version byte */ + encrypted_key.nonce.SerializedSize() +
+                  encrypted_key.ciphertext.SerializedSize() + encrypted_key.tag.SerializedSize() +
+                  hw_enforced.SerializedSize() + sw_enforced.SerializedSize();
+
+    KeymasterKeyBlob retval;
+    if (!retval.Reset(size)) {
+        *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        return {};
+    }
+
+    uint8_t* buf = retval.writable_data();
+    const uint8_t* end = retval.end();
+
+    *buf++ = encrypted_key.format;
+    buf = encrypted_key.nonce.Serialize(buf, end);
+    buf = encrypted_key.ciphertext.Serialize(buf, end);
+    buf = encrypted_key.tag.Serialize(buf, end);
+    buf = hw_enforced.Serialize(buf, end);
+    buf = sw_enforced.Serialize(buf, end);
+    if (buf != retval.end()) *error = KM_ERROR_UNKNOWN_ERROR;
+
+    return retval;
+}
+
+DeserializedKey DeserializeAuthEncryptedBlob(const KeymasterKeyBlob& key_blob,
+                                             keymaster_error_t* error) {
+    if (!error) return {};
+    *error = KM_ERROR_OK;
+
+    if (!key_blob.key_material || key_blob.key_material_size == 0) {
+        *error = KM_ERROR_INVALID_KEY_BLOB;
+        return {};
+    }
 
     const uint8_t* tmp = key_blob.key_material;
     const uint8_t** buf_ptr = &tmp;
     const uint8_t* end = tmp + key_blob.key_material_size;
 
-    if (end <= *buf_ptr)
-        return KM_ERROR_INVALID_KEY_BLOB;
-
-    uint8_t version = *(*buf_ptr)++;
-    if (version != CURRENT_BLOB_VERSION ||  //
-        !nonce->Deserialize(buf_ptr, end) || nonce->available_read() != OCB_NONCE_LENGTH ||
-        !encrypted_key_material->Deserialize(buf_ptr, end) ||  //
-        !tag->Deserialize(buf_ptr, end) || tag->available_read() != OCB_TAG_LENGTH ||
-        !hw_enforced->Deserialize(buf_ptr, end) ||  //
-        !sw_enforced->Deserialize(buf_ptr, end)) {
-        // This blob failed to parse.  Either it's corrupted or it's a blob generated by an earlier
-        // version of keymaster using a previous blob format which did not include the version byte
-        // or the nonce or tag length fields.  So we try to parse it as that previous version.
-        //
-        // Note that it's not really a problem if we erronously parse a corrupted blob, because
-        // decryption will fail the authentication check.
-        //
-        // A bigger potential problem is: What if a valid unversioned blob appears to parse
-        // correctly as a versioned blob?  It would then be rejected during decryption, causing a
-        // valid key to become unusable.  If this is a disk encryption key, upgrading to a keymaster
-        // version with the new format would destroy the user's data.
-        //
-        // What is the probability that an unversioned key could be successfully parsed as a version
-        // 0 key?  The first 12 bytes of an unversioned key are the nonce, which, in the only
-        // keymaster version released with unversioned keys, is chosen randomly.  In order for an
-        // unversioned key to parse as a version 0 key, the following must be true about the first
-        // five of those random bytes:
-        //
-        // 1.  The first byte must be zero.  This will happen with probability 1/2^8.
-        //
-        // 2.  The second through fifth bytes must contain an unsigned integer value equal to
-        //     NONCE_LENGTH.  This will happen with probability 1/2^32.
-        //
-        // Based on those two checks alone, the probability of interpreting an unversioned blob as a
-        // version 0 blob is 1/2^40.  That's small enough to be negligible, but there are additional
-        // checks which lower it further.
-        LOG_D("Failed to deserialize versioned key blob.  Assuming unversioned.", 0);
-        return DeserializeUnversionedBlob(key_blob, encrypted_key_material, hw_enforced,
-                                          sw_enforced, nonce, tag);
+    if (end <= *buf_ptr) {
+        *error = KM_ERROR_INVALID_KEY_BLOB;
+        return {};
     }
-    return KM_ERROR_OK;
+
+    DeserializedKey retval;
+    retval.encrypted_key.format = static_cast<AuthEncryptedBlobFormat>(*(*buf_ptr)++);
+    if (!retval.encrypted_key.nonce.Deserialize(buf_ptr, end) ||       //
+        !retval.encrypted_key.ciphertext.Deserialize(buf_ptr, end) ||  //
+        !retval.encrypted_key.tag.Deserialize(buf_ptr, end) ||         //
+        !retval.hw_enforced.Deserialize(buf_ptr, end) ||               //
+        !retval.sw_enforced.Deserialize(buf_ptr, end) ||               //
+        *buf_ptr != end) {
+        *error = KM_ERROR_INVALID_KEY_BLOB;
+        return {};
+    }
+
+    switch (retval.encrypted_key.format) {
+    case AES_OCB:
+        if (retval.encrypted_key.nonce.available_read() != OCB_NONCE_LENGTH ||
+            retval.encrypted_key.tag.available_read() != OCB_TAG_LENGTH) {
+            *error = KM_ERROR_INVALID_KEY_BLOB;
+            return {};
+        }
+        return retval;
+
+    case AES_GCM_WITH_SW_ENFORCED:
+        if (retval.encrypted_key.nonce.available_read() != kAesGcmNonceLength ||
+            retval.encrypted_key.tag.available_read() != kAesGcmTagLength) {
+            *error = KM_ERROR_INVALID_KEY_BLOB;
+            return {};
+        }
+        return retval;
+    }
+
+    *error = KM_ERROR_INVALID_KEY_BLOB;
+    return {};
+}
+
+EncryptedKey EncryptKey(const KeymasterKeyBlob& plaintext, AuthEncryptedBlobFormat format,
+                        const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+                        const AuthorizationSet& hidden, const KeymasterKeyBlob& master_key,
+                        const RandomSource& random, keymaster_error_t* error) {
+    if (!error) return {};
+    *error = KM_ERROR_OK;
+
+    switch (format) {
+    case AES_OCB: {
+        EncryptedKey retval;
+        retval.format = format;
+        retval.nonce = generate_nonce(random, OCB_NONCE_LENGTH, error);
+        retval.tag.Reinitialize(OCB_TAG_LENGTH);
+        if (KM_ERROR_OK != *error) return {};
+        *error = OcbEncryptKey(hw_enforced, sw_enforced, hidden, master_key, plaintext,
+                               retval.nonce, &retval.ciphertext, &retval.tag);
+        return retval;
+    }
+
+    case AES_GCM_WITH_SW_ENFORCED: {
+        auto nonce = generate_nonce(random, kAesGcmNonceLength, error);
+        if (KM_ERROR_OK != *error) return {};
+        return AesGcmEncryptKey(hw_enforced, sw_enforced, hidden, master_key, plaintext, format,
+                                move(nonce), error);
+    }
+    }
+
+    *error = KM_ERROR_UNKNOWN_ERROR;
+    LOG_E("Invalid key blob format %d", format);
+    return {};
+}
+
+KeymasterKeyBlob DecryptKey(const DeserializedKey& key, const AuthorizationSet& hidden,
+                            const KeymasterKeyBlob& master_key, keymaster_error_t* error) {
+    if (!error) return {};
+    *error = KM_ERROR_OK;
+
+    KeymasterKeyBlob retval;
+
+    switch (key.encrypted_key.format) {
+    case AES_OCB:
+        *error = OcbDecryptKey(key.hw_enforced, key.sw_enforced, hidden, master_key,
+                               key.encrypted_key.ciphertext, key.encrypted_key.nonce,
+                               key.encrypted_key.tag, &retval);
+        break;
+
+    case AES_GCM_WITH_SW_ENFORCED:
+        retval = AesGcmDecryptKey(key, hidden, master_key, error);
+        break;
+    }
+
+    return retval;
 }
 
 }  // namespace keymaster
diff --git a/key_blob_utils/integrity_assured_key_blob.cpp b/key_blob_utils/integrity_assured_key_blob.cpp
index 014855e..11d9cf2 100644
--- a/key_blob_utils/integrity_assured_key_blob.cpp
+++ b/key_blob_utils/integrity_assured_key_blob.cpp
@@ -24,7 +24,6 @@
 #include <keymaster/android_keymaster_utils.h>
 #include <keymaster/authorization_set.h>
 #include <keymaster/km_openssl/openssl_err.h>
-#include <keymaster/new.h>
 
 namespace keymaster {
 
@@ -33,8 +32,7 @@
 static const char HMAC_KEY[] = "IntegrityAssuredBlob0";
 
 inline size_t min(size_t a, size_t b) {
-    if (a < b)
-        return a;
+    if (a < b) return a;
     return b;
 }
 
@@ -51,8 +49,7 @@
                                      const AuthorizationSet& hidden, uint8_t hmac[HMAC_SIZE]) {
     size_t hidden_bytes_size = hidden.SerializedSize();
     UniquePtr<uint8_t[]> hidden_bytes(new (std::nothrow) uint8_t[hidden_bytes_size]);
-    if (!hidden_bytes.get())
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!hidden_bytes.get()) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
     hidden.Serialize(hidden_bytes.get(), hidden_bytes.get() + hidden_bytes_size);
 
     HMAC_CTX ctx;
@@ -86,8 +83,7 @@
                   sw_enforced.SerializedSize() +   //
                   HMAC_SIZE;
 
-    if (!key_blob->Reset(size))
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!key_blob->Reset(size)) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
     uint8_t* p = key_blob->writable_data();
     *p++ = BLOB_VERSION;
@@ -106,14 +102,12 @@
     const uint8_t* p = key_blob.begin();
     const uint8_t* end = key_blob.end();
 
-    if (p > end || p + HMAC_SIZE > end)
-        return KM_ERROR_INVALID_KEY_BLOB;
+    if (p > end || p + HMAC_SIZE > end) return KM_ERROR_INVALID_KEY_BLOB;
 
     uint8_t computed_hmac[HMAC_SIZE];
     keymaster_error_t error = ComputeHmac(key_blob.begin(), key_blob.key_material_size - HMAC_SIZE,
                                           hidden, computed_hmac);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     if (CRYPTO_memcmp(key_blob.end() - HMAC_SIZE, computed_hmac, HMAC_SIZE) != 0)
         return KM_ERROR_INVALID_KEY_BLOB;
@@ -129,11 +123,9 @@
     const uint8_t* p = key_blob.begin();
     const uint8_t* end = key_blob.end() - HMAC_SIZE;
 
-    if (p > end)
-        return KM_ERROR_INVALID_KEY_BLOB;
+    if (p > end) return KM_ERROR_INVALID_KEY_BLOB;
 
-    if (*p != BLOB_VERSION)
-        return KM_ERROR_INVALID_KEY_BLOB;
+    if (*p != BLOB_VERSION) return KM_ERROR_INVALID_KEY_BLOB;
     ++p;
 
     if (!key_material->Deserialize(&p, end) ||  //
@@ -144,4 +136,4 @@
     return KM_ERROR_OK;
 }
 
-}  // namespace keymaster;
+}  // namespace keymaster
diff --git a/key_blob_utils/ocb_utils.cpp b/key_blob_utils/ocb_utils.cpp
index d58d2df..1dcb0cb 100644
--- a/key_blob_utils/ocb_utils.cpp
+++ b/key_blob_utils/ocb_utils.cpp
@@ -26,7 +26,6 @@
 #include <keymaster/android_keymaster_utils.h>
 #include <keymaster/authorization_set.h>
 #include <keymaster/km_openssl/openssl_err.h>
-#include <keymaster/new.h>
 
 namespace keymaster {
 
@@ -52,8 +51,7 @@
     *derivation_data_length =
         hidden.SerializedSize() + hw_enforced.SerializedSize() + sw_enforced.SerializedSize();
     derivation_data->reset(new (std::nothrow) uint8_t[*derivation_data_length]);
-    if (!derivation_data->get())
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!derivation_data->get()) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
     uint8_t* buf = derivation_data->get();
     uint8_t* end = derivation_data->get() + *derivation_data_length;
@@ -73,17 +71,14 @@
     UniquePtr<uint8_t[]> derivation_data;
     keymaster_error_t error = BuildDerivationData(hw_enforced, sw_enforced, hidden,
                                                   &derivation_data, &derivation_data_length);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     SHA256_CTX sha256_ctx;
     UniquePtr<uint8_t[]> hash_buf(new (std::nothrow) uint8_t[SHA256_DIGEST_LENGTH]);
-    if (!hash_buf.get())
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!hash_buf.get()) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
     Eraser hash_eraser(hash_buf.get(), SHA256_DIGEST_LENGTH);
     UniquePtr<uint8_t[]> derived_key(new (std::nothrow) uint8_t[AES_BLOCK_SIZE]);
-    if (!derived_key.get())
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!derived_key.get()) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
     Eraser derived_key_eraser(derived_key.get(), AES_BLOCK_SIZE);
 
     if (!ctx->get() || !hash_buf.get() || !derived_key.get())
@@ -121,20 +116,17 @@
                                 KeymasterKeyBlob* ciphertext, Buffer* tag) {
     assert(ciphertext && tag);
 
-    if (nonce.available_read() != OCB_NONCE_LENGTH)
-        return KM_ERROR_INVALID_ARGUMENT;
+    if (nonce.available_read() != OCB_NONCE_LENGTH) return KM_ERROR_INVALID_ARGUMENT;
+    if (tag->available_write() != OCB_TAG_LENGTH) return KM_ERROR_INVALID_ARGUMENT;
 
     AeCtx ctx;
-    if (!ctx.get())
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!ctx.get()) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
     keymaster_error_t error =
         InitializeKeyWrappingContext(hw_enforced, sw_enforced, hidden, master_key, &ctx);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
-    if (!ciphertext->Reset(plaintext.key_material_size))
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!ciphertext->Reset(plaintext.key_material_size)) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
     int ae_err = ae_encrypt(ctx.get(), nonce.peek_read(), plaintext.key_material,
                             plaintext.key_material_size, nullptr /* additional data */,
@@ -144,8 +136,7 @@
         LOG_E("Error %d while encrypting key", ae_err);
         return KM_ERROR_UNKNOWN_ERROR;
     }
-    if (!tag->advance_write(OCB_TAG_LENGTH))
-        return KM_ERROR_UNKNOWN_ERROR;
+    if (!tag->advance_write(OCB_TAG_LENGTH)) return KM_ERROR_UNKNOWN_ERROR;
     assert(ae_err == static_cast<int>(plaintext.key_material_size));
     return KM_ERROR_OK;
 }
@@ -161,16 +152,13 @@
         return KM_ERROR_INVALID_ARGUMENT;
 
     AeCtx ctx;
-    if (!ctx.get())
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!ctx.get()) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
     keymaster_error_t error =
         InitializeKeyWrappingContext(hw_enforced, sw_enforced, hidden, master_key, &ctx);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
-    if (!plaintext->Reset(ciphertext.key_material_size))
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!plaintext->Reset(ciphertext.key_material_size)) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
     int ae_err = ae_decrypt(ctx.get(), nonce.peek_read(), ciphertext.key_material,
                             ciphertext.key_material_size, nullptr /* additional data */,
diff --git a/key_blob_utils/software_keyblobs.cpp b/key_blob_utils/software_keyblobs.cpp
index 60719bb..764ebcb 100644
--- a/key_blob_utils/software_keyblobs.cpp
+++ b/key_blob_utils/software_keyblobs.cpp
@@ -21,16 +21,16 @@
 
 #include <hardware/keymaster_defs.h>
 
+#include <keymaster/UniquePtr.h>
 #include <keymaster/android_keymaster_utils.h>
 #include <keymaster/authorization_set.h>
 #include <keymaster/key.h>
 #include <keymaster/key_blob_utils/auth_encrypted_key_blob.h>
 #include <keymaster/key_blob_utils/integrity_assured_key_blob.h>
 #include <keymaster/key_blob_utils/ocb_utils.h>
-#include <keymaster/km_openssl/openssl_utils.h>
 #include <keymaster/km_openssl/openssl_err.h>
+#include <keymaster/km_openssl/openssl_utils.h>
 #include <keymaster/logger.h>
-#include <keymaster/UniquePtr.h>
 
 #include <openssl/aes.h>
 
@@ -42,7 +42,7 @@
 namespace {
 
 bool UpgradeIntegerTag(keymaster_tag_t tag, uint32_t value, AuthorizationSet* set,
-                              bool* set_changed) {
+                       bool* set_changed) {
     int index = set->find(tag);
     if (index == -1) {
         keymaster_key_param_t param;
@@ -53,8 +53,7 @@
         return true;
     }
 
-    if (set->params[index].integer > value)
-        return false;
+    if (set->params[index].integer > value) return false;
 
     if (set->params[index].integer != value) {
         set->params[index].integer = value;
@@ -75,7 +74,7 @@
     return KM_ERROR_OK;
 }
 
-} // anonymous namespace
+}  // anonymous namespace
 
 keymaster_error_t BuildHiddenAuthorizations(const AuthorizationSet& input_set,
                                             AuthorizationSet* hidden,
@@ -91,8 +90,7 @@
     return TranslateAuthorizationSetError(hidden->is_valid());
 }
 
-keymaster_error_t FakeKeyAuthorizations(EVP_PKEY* pubkey,
-                                        AuthorizationSet* hw_enforced,
+keymaster_error_t FakeKeyAuthorizations(EVP_PKEY* pubkey, AuthorizationSet* hw_enforced,
                                         AuthorizationSet* sw_enforced) {
     hw_enforced->Clear();
     sw_enforced->Clear();
@@ -119,12 +117,10 @@
         sw_enforced->push_back(TAG_PURPOSE, KM_PURPOSE_DECRYPT);
 
         RSA_Ptr rsa(EVP_PKEY_get1_RSA(pubkey));
-        if (!rsa)
-            return TranslateLastOpenSslError();
+        if (!rsa) return TranslateLastOpenSslError();
         hw_enforced->push_back(TAG_KEY_SIZE, RSA_size(rsa.get()) * 8);
         uint64_t public_exponent = BN_get_word(rsa->e);
-        if (public_exponent == 0xffffffffL)
-            return KM_ERROR_INVALID_KEY_BLOB;
+        if (public_exponent == 0xffffffffL) return KM_ERROR_INVALID_KEY_BLOB;
         hw_enforced->push_back(TAG_RSA_PUBLIC_EXPONENT, public_exponent);
         break;
     }
@@ -143,13 +139,11 @@
         sw_enforced->push_back(TAG_PURPOSE, KM_PURPOSE_VERIFY);
 
         UniquePtr<EC_KEY, EC_KEY_Delete> ec_key(EVP_PKEY_get1_EC_KEY(pubkey));
-        if (!ec_key.get())
-            return TranslateLastOpenSslError();
+        if (!ec_key.get()) return TranslateLastOpenSslError();
         size_t key_size_bits;
         keymaster_error_t error =
             ec_get_group_size(EC_KEY_get0_group(ec_key.get()), &key_size_bits);
-        if (error != KM_ERROR_OK)
-            return error;
+        if (error != KM_ERROR_OK) return error;
         hw_enforced->push_back(TAG_KEY_SIZE, key_size_bits);
         break;
     }
@@ -164,16 +158,16 @@
     return KM_ERROR_OK;
 }
 
-
 // Note: This parsing code in below is from system/security/softkeymaster/keymaster_openssl.cpp's
 // unwrap_key function, modified for the preferred function signature and formatting.  It does some
 // odd things, but they have been left unchanged to avoid breaking compatibility.
 static const uint8_t SOFT_KEY_MAGIC[] = {'P', 'K', '#', '8'};
-keymaster_error_t ParseOldSoftkeymasterBlob(
-    const KeymasterKeyBlob& blob, KeymasterKeyBlob* key_material, AuthorizationSet* hw_enforced,
-    AuthorizationSet* sw_enforced) {
-    long publicLen = 0;
-    long privateLen = 0;
+keymaster_error_t ParseOldSoftkeymasterBlob(const KeymasterKeyBlob& blob,
+                                            KeymasterKeyBlob* key_material,
+                                            AuthorizationSet* hw_enforced,
+                                            AuthorizationSet* sw_enforced) {
+    long publicLen = 0;   // NOLINT(google-runtime-int)
+    long privateLen = 0;  // NOLINT(google-runtime-int)
     const uint8_t* p = blob.key_material;
     const uint8_t* end = blob.key_material + blob.key_material_size;
 
@@ -185,15 +179,16 @@
         return KM_ERROR_INVALID_KEY_BLOB;
     }
 
-    if (memcmp(p, SOFT_KEY_MAGIC, sizeof(SOFT_KEY_MAGIC)) != 0)
-        return KM_ERROR_INVALID_KEY_BLOB;
+    if (memcmp(p, SOFT_KEY_MAGIC, sizeof(SOFT_KEY_MAGIC)) != 0) return KM_ERROR_INVALID_KEY_BLOB;
     p += sizeof(SOFT_KEY_MAGIC);
 
-    for (size_t i = 0; i < sizeof(type); i++)
+    for (size_t i = 0; i < sizeof(type); i++) {
         type = (type << 8) | *p++;
+    }
 
-    for (size_t i = 0; i < sizeof(type); i++)
+    for (size_t i = 0; i < sizeof(type); i++) {
         publicLen = (publicLen << 8) | *p++;
+    }
 
     if (p + publicLen > end) {
         LOG_W("public key length encoding error: size=%ld, end=%td", publicLen, end - p);
@@ -227,11 +222,9 @@
     // auths for a HW-backed key.
     hw_enforced->Clear();
     keymaster_error_t error = FakeKeyAuthorizations(pkey.get(), sw_enforced, sw_enforced);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
-    if (!key_material->Reset(privateLen))
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!key_material->Reset(privateLen)) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
     memcpy(key_material->writable_data(), key_start, privateLen);
 
     return KM_ERROR_OK;
@@ -240,23 +233,19 @@
 static uint8_t master_key_bytes[AES_BLOCK_SIZE] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 const KeymasterKeyBlob MASTER_KEY(master_key_bytes, array_length(master_key_bytes));
 
-keymaster_error_t ParseOcbAuthEncryptedBlob(const KeymasterKeyBlob& blob,
-                                            const AuthorizationSet& hidden,
-                                            KeymasterKeyBlob* key_material,
-                                            AuthorizationSet* hw_enforced,
-                                            AuthorizationSet* sw_enforced) {
-    Buffer nonce, tag;
-    KeymasterKeyBlob encrypted_key_material;
-    keymaster_error_t error = DeserializeAuthEncryptedBlob(blob, &encrypted_key_material,
-                                                           hw_enforced, sw_enforced, &nonce, &tag);
-    if (error != KM_ERROR_OK)
-        return error;
+keymaster_error_t ParseAuthEncryptedBlob(const KeymasterKeyBlob& blob,
+                                         const AuthorizationSet& hidden,
+                                         KeymasterKeyBlob* key_material,
+                                         AuthorizationSet* hw_enforced,
+                                         AuthorizationSet* sw_enforced) {
+    keymaster_error_t error;
+    DeserializedKey key = DeserializeAuthEncryptedBlob(blob, &error);
+    if (error != KM_ERROR_OK) return error;
 
-    if (nonce.available_read() != OCB_NONCE_LENGTH || tag.available_read() != OCB_TAG_LENGTH)
-        return KM_ERROR_INVALID_KEY_BLOB;
-
-    return OcbDecryptKey(*hw_enforced, *sw_enforced, hidden, MASTER_KEY, encrypted_key_material,
-                         nonce, tag, key_material);
+    *key_material = DecryptKey(key, hidden, MASTER_KEY, &error);
+    *hw_enforced = move(key.hw_enforced);
+    *sw_enforced = move(key.sw_enforced);
+    return error;
 }
 
 keymaster_error_t SetKeyBlobAuthorizations(const AuthorizationSet& key_description,
@@ -268,26 +257,112 @@
     for (auto& entry : key_description) {
         switch (entry.tag) {
         // These cannot be specified by the client.
-        case KM_TAG_ROOT_OF_TRUST:
+        case KM_TAG_BOOT_PATCHLEVEL:
         case KM_TAG_ORIGIN:
+        case KM_TAG_OS_PATCHLEVEL:
+        case KM_TAG_OS_VERSION:
+        case KM_TAG_ROOT_OF_TRUST:
+        case KM_TAG_VENDOR_PATCHLEVEL:
             LOG_E("Root of trust and origin tags may not be specified", 0);
             return KM_ERROR_INVALID_TAG;
 
-        // These don't work.
+        case KM_TAG_ALLOW_WHILE_ON_BODY:
+            // Not supported, but is specified to noop in that case (vs error).
+            LOG_W("No on-body detection supported, skipping tag %d", entry.tag);
+            break;
+
+        // These aren't supported by SoftKeymaster.
+        case KM_TAG_DEVICE_UNIQUE_ATTESTATION:
+        case KM_TAG_ECIES_SINGLE_HASH_MODE:
+        case KM_TAG_EXPORTABLE:
+        case KM_TAG_IDENTITY_CREDENTIAL_KEY:
+        case KM_TAG_KDF:
         case KM_TAG_ROLLBACK_RESISTANT:
-            LOG_E("KM_TAG_ROLLBACK_RESISTANT not supported", 0);
+        case KM_TAG_STORAGE_KEY:
+            LOG_E("Tag %d not supported by SoftKeymaster", entry.tag);
             return KM_ERROR_UNSUPPORTED_TAG;
 
+        // If the hardware enforce list contains this tag, means we are
+        // pretending to be some secure hardware which has secure storage.
+        case KM_TAG_ROLLBACK_RESISTANCE:
+            if (hw_enforced->GetTagCount(entry.tag) != 0)
+                break;
+            else {
+                LOG_E("Tag %d not supported by SoftKeymaster", entry.tag);
+                return KM_ERROR_UNSUPPORTED_TAG;
+            }
+
         // These are hidden.
-        case KM_TAG_APPLICATION_ID:
         case KM_TAG_APPLICATION_DATA:
+        case KM_TAG_APPLICATION_ID:
+            break;
+
+        // These should not be in key descriptions because they're for operation parameters.
+        case KM_TAG_ASSOCIATED_DATA:
+        case KM_TAG_AUTH_TOKEN:
+        case KM_TAG_CONFIRMATION_TOKEN:
+        case KM_TAG_INVALID:
+        case KM_TAG_MAC_LENGTH:
+        case KM_TAG_NONCE:
+            LOG_E("Tag %d not allowed in key generation/import", entry.tag);
+            break;
+
+        // These are provided to support attesation key generation, but should not be included in
+        // the key characteristics.
+        case KM_TAG_ATTESTATION_APPLICATION_ID:
+        case KM_TAG_ATTESTATION_CHALLENGE:
+        case KM_TAG_ATTESTATION_ID_BRAND:
+        case KM_TAG_ATTESTATION_ID_DEVICE:
+        case KM_TAG_ATTESTATION_ID_IMEI:
+        case KM_TAG_ATTESTATION_ID_MANUFACTURER:
+        case KM_TAG_ATTESTATION_ID_MEID:
+        case KM_TAG_ATTESTATION_ID_MODEL:
+        case KM_TAG_ATTESTATION_ID_PRODUCT:
+        case KM_TAG_ATTESTATION_ID_SERIAL:
+        case KM_TAG_CERTIFICATE_SERIAL:
+        case KM_TAG_CERTIFICATE_SUBJECT:
+        case KM_TAG_CERTIFICATE_NOT_BEFORE:
+        case KM_TAG_CERTIFICATE_NOT_AFTER:
+        case KM_TAG_RESET_SINCE_ID_ROTATION:
             break;
 
         // Everything else we just copy into sw_enforced, unless the KeyFactory has placed it in
         // hw_enforced, in which case we defer to its decision.
-        default:
-            if (hw_enforced->GetTagCount(entry.tag) == 0)
-                sw_enforced->push_back(entry);
+        case KM_TAG_ACTIVE_DATETIME:
+        case KM_TAG_ALGORITHM:
+        case KM_TAG_ALL_APPLICATIONS:
+        case KM_TAG_ALL_USERS:
+        case KM_TAG_AUTH_TIMEOUT:
+        case KM_TAG_BLOB_USAGE_REQUIREMENTS:
+        case KM_TAG_BLOCK_MODE:
+        case KM_TAG_BOOTLOADER_ONLY:
+        case KM_TAG_CALLER_NONCE:
+        case KM_TAG_CREATION_DATETIME:
+        case KM_TAG_DIGEST:
+        case KM_TAG_EARLY_BOOT_ONLY:
+        case KM_TAG_EC_CURVE:
+        case KM_TAG_INCLUDE_UNIQUE_ID:
+        case KM_TAG_KEY_SIZE:
+        case KM_TAG_MAX_BOOT_LEVEL:
+        case KM_TAG_MAX_USES_PER_BOOT:
+        case KM_TAG_MIN_MAC_LENGTH:
+        case KM_TAG_MIN_SECONDS_BETWEEN_OPS:
+        case KM_TAG_NO_AUTH_REQUIRED:
+        case KM_TAG_ORIGINATION_EXPIRE_DATETIME:
+        case KM_TAG_PADDING:
+        case KM_TAG_PURPOSE:
+        case KM_TAG_RSA_OAEP_MGF_DIGEST:
+        case KM_TAG_RSA_PUBLIC_EXPONENT:
+        case KM_TAG_TRUSTED_CONFIRMATION_REQUIRED:
+        case KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED:
+        case KM_TAG_UNIQUE_ID:
+        case KM_TAG_UNLOCKED_DEVICE_REQUIRED:
+        case KM_TAG_USAGE_COUNT_LIMIT:
+        case KM_TAG_USAGE_EXPIRE_DATETIME:
+        case KM_TAG_USER_AUTH_TYPE:
+        case KM_TAG_USER_ID:
+        case KM_TAG_USER_SECURE_ID:
+            if (hw_enforced->GetTagCount(entry.tag) == 0) sw_enforced->push_back(entry);
             break;
         }
     }
@@ -306,11 +381,37 @@
     return TranslateAuthorizationSetError(sw_enforced->is_valid());
 }
 
+keymaster_error_t ExtendKeyBlobAuthorizations(AuthorizationSet* hw_enforced,
+                                              AuthorizationSet* sw_enforced,
+                                              std::optional<uint32_t> vendor_patchlevel,
+                                              std::optional<uint32_t> boot_patchlevel) {
+    // If hw_enforced is non-empty, we're pretending to be some sort of secure hardware.
+    AuthorizationSet* pseudo_hw_enforced = (hw_enforced->empty()) ? sw_enforced : hw_enforced;
+    if (vendor_patchlevel.has_value()) {
+        pseudo_hw_enforced->push_back(TAG_VENDOR_PATCHLEVEL, vendor_patchlevel.value());
+    }
+    if (boot_patchlevel.has_value()) {
+        pseudo_hw_enforced->push_back(TAG_BOOT_PATCHLEVEL, boot_patchlevel.value());
+    }
+    return TranslateAuthorizationSetError(sw_enforced->is_valid());
+}
 
-keymaster_error_t UpgradeSoftKeyBlob(const UniquePtr<Key>& key,
-                                 const uint32_t os_version, const uint32_t os_patchlevel,
-                                 const AuthorizationSet& upgrade_params,
-                                 KeymasterKeyBlob* upgraded_key) {
+keymaster_error_t UpgradeSoftKeyBlob(const UniquePtr<Key>& key, const uint32_t os_version,
+                                     const uint32_t os_patchlevel,
+                                     const AuthorizationSet& upgrade_params,
+                                     KeymasterKeyBlob* upgraded_key) {
+    return FullUpgradeSoftKeyBlob(key, os_version, os_patchlevel,
+                                  /* vendor_patchlevel= */ std::nullopt,
+                                  /* boot_patchlevel= */ std::nullopt,  //
+                                  upgrade_params, upgraded_key);
+}
+
+keymaster_error_t FullUpgradeSoftKeyBlob(const UniquePtr<Key>& key, const uint32_t os_version,
+                                         uint32_t os_patchlevel,
+                                         std::optional<uint32_t> vendor_patchlevel,
+                                         std::optional<uint32_t> boot_patchlevel,
+                                         const AuthorizationSet& upgrade_params,
+                                         KeymasterKeyBlob* upgraded_key) {
     bool set_changed = false;
 
     if (os_version == 0) {
@@ -328,20 +429,27 @@
     }
 
     if (!UpgradeIntegerTag(TAG_OS_VERSION, os_version, &key->sw_enforced(), &set_changed) ||
-        !UpgradeIntegerTag(TAG_OS_PATCHLEVEL, os_patchlevel, &key->sw_enforced(), &set_changed))
+        !UpgradeIntegerTag(TAG_OS_PATCHLEVEL, os_patchlevel, &key->sw_enforced(), &set_changed) ||
+        (vendor_patchlevel.has_value() &&
+         !UpgradeIntegerTag(TAG_VENDOR_PATCHLEVEL, vendor_patchlevel.value(), &key->sw_enforced(),
+                            &set_changed)) ||
+        (boot_patchlevel.has_value() &&
+         !UpgradeIntegerTag(TAG_BOOT_PATCHLEVEL, boot_patchlevel.value(), &key->sw_enforced(),
+                            &set_changed))) {
         // One of the version fields would have been a downgrade. Not allowed.
         return KM_ERROR_INVALID_ARGUMENT;
+    }
 
-    if (!set_changed)
+    if (!set_changed) {
         // Dont' need an upgrade.
         return KM_ERROR_OK;
+    }
 
     AuthorizationSet hidden;
     auto error = BuildHiddenAuthorizations(upgrade_params, &hidden, softwareRootOfTrust);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
     return SerializeIntegrityAssuredBlob(key->key_material(), hidden, key->hw_enforced(),
                                          key->sw_enforced(), upgraded_key);
 }
 
-} // namespace keymaster
+}  // namespace keymaster
diff --git a/km_openssl/aes_key.cpp b/km_openssl/aes_key.cpp
index 0e1a756..5df9e9e 100644
--- a/km_openssl/aes_key.cpp
+++ b/km_openssl/aes_key.cpp
@@ -18,8 +18,6 @@
 
 #include <assert.h>
 
-#include <keymaster/new.h>
-
 #include <openssl/err.h>
 #include <openssl/rand.h>
 
@@ -46,8 +44,7 @@
                                          AuthorizationSet&& hw_enforced,
                                          AuthorizationSet&& sw_enforced,
                                          UniquePtr<Key>* key) const {
-    if (!key)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    if (!key) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     uint32_t min_mac_length = 0;
     if (hw_enforced.Contains(TAG_BLOCK_MODE, KM_MODE_GCM) ||
@@ -62,10 +59,9 @@
     }
 
     keymaster_error_t error = KM_ERROR_OK;
-    key->reset(new (std::nothrow) AesKey(move(key_material), move(hw_enforced), move(sw_enforced),
-                                         this));
-    if (!key->get())
-        error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    key->reset(new (std::nothrow)
+                   AesKey(move(key_material), move(hw_enforced), move(sw_enforced), this));
+    if (!key->get()) error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
     return error;
 }
 
@@ -76,8 +72,7 @@
         if (!key_description.GetTagValue(TAG_MIN_MAC_LENGTH, &min_tag_length))
             return KM_ERROR_MISSING_MIN_MAC_LENGTH;
 
-        if (min_tag_length % 8 != 0)
-            return KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH;
+        if (min_tag_length % 8 != 0) return KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH;
 
         if (min_tag_length < kMinGcmTagLength || min_tag_length > kMaxGcmTagLength)
             return KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH;
diff --git a/km_openssl/asymmetric_key.cpp b/km_openssl/asymmetric_key.cpp
index 511e43a..8516c65 100644
--- a/km_openssl/asymmetric_key.cpp
+++ b/km_openssl/asymmetric_key.cpp
@@ -16,42 +16,33 @@
 
 #include <keymaster/km_openssl/asymmetric_key.h>
 
-#include <keymaster/new.h>
-
 #include <openssl/asn1.h>
 #include <openssl/stack.h>
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
 
 #include <keymaster/android_keymaster_utils.h>
-#include <keymaster/attestation_record.h>
 #include <keymaster/keymaster_context.h>
 #include <keymaster/km_openssl/openssl_err.h>
 #include <keymaster/km_openssl/openssl_utils.h>
 
-
 namespace keymaster {
 
 keymaster_error_t AsymmetricKey::formatted_key_material(keymaster_key_format_t format,
                                                         UniquePtr<uint8_t[]>* material,
                                                         size_t* size) const {
-    if (format != KM_KEY_FORMAT_X509)
-        return KM_ERROR_UNSUPPORTED_KEY_FORMAT;
+    if (format != KM_KEY_FORMAT_X509) return KM_ERROR_UNSUPPORTED_KEY_FORMAT;
 
-    if (material == nullptr || size == nullptr)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    if (material == nullptr || size == nullptr) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     EVP_PKEY_Ptr pkey(EVP_PKEY_new());
-    if (!InternalToEvp(pkey.get()))
-        return TranslateLastOpenSslError();
+    if (!InternalToEvp(pkey.get())) return TranslateLastOpenSslError();
 
     int key_data_length = i2d_PUBKEY(pkey.get(), nullptr);
-    if (key_data_length <= 0)
-        return TranslateLastOpenSslError();
+    if (key_data_length <= 0) return TranslateLastOpenSslError();
 
-    material->reset(new(std::nothrow) uint8_t[key_data_length]);
-    if (material->get() == nullptr)
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    material->reset(new (std::nothrow) uint8_t[key_data_length]);
+    if (material->get() == nullptr) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
     uint8_t* tmp = material->get();
     if (i2d_PUBKEY(pkey.get(), &tmp) != key_data_length) {
diff --git a/km_openssl/asymmetric_key_factory.cpp b/km_openssl/asymmetric_key_factory.cpp
index b34924a..cf68c68 100644
--- a/km_openssl/asymmetric_key_factory.cpp
+++ b/km_openssl/asymmetric_key_factory.cpp
@@ -45,23 +45,21 @@
                                                 UniquePtr<Key>* key) const {
     UniquePtr<AsymmetricKey> asym_key;
     keymaster_error_t error = CreateEmptyKey(move(hw_enforced), move(sw_enforced), &asym_key);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     const uint8_t* tmp = key_material.key_material;
     asym_key->key_material() = move(key_material);
 
-    EVP_PKEY* pkey =
-        d2i_PrivateKey(evp_key_type(), nullptr /* pkey */, &tmp,
-                       asym_key->key_material().key_material_size);
-    if (!pkey)
-        return TranslateLastOpenSslError();
+    EVP_PKEY* pkey = d2i_PrivateKey(evp_key_type(), nullptr /* pkey */, &tmp,
+                                    asym_key->key_material().key_material_size);
+    if (!pkey) return TranslateLastOpenSslError();
     UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey_deleter(pkey);
 
-    if (!asym_key->EvpToInternal(pkey))
+    if (!asym_key->EvpToInternal(pkey)) {
         error = TranslateLastOpenSslError();
-    else
-        key->reset(asym_key.release());
+    } else {
+        *key = std::move(asym_key);
+    }
 
     return error;
 }
diff --git a/km_openssl/attestation_record.cpp b/km_openssl/attestation_record.cpp
index 8fcaa03..92aaeae 100644
--- a/km_openssl/attestation_record.cpp
+++ b/km_openssl/attestation_record.cpp
@@ -14,20 +14,31 @@
  * limitations under the License.
  */
 
-#include <keymaster/attestation_record.h>
+#include <keymaster/km_openssl/attestation_record.h>
 
 #include <assert.h>
+#include <math.h>
 
+#include <unordered_map>
+
+#include <cppbor_parse.h>
 #include <openssl/asn1t.h>
 
 #include <keymaster/android_keymaster_utils.h>
+#include <keymaster/attestation_context.h>
 #include <keymaster/km_openssl/openssl_err.h>
 #include <keymaster/km_openssl/openssl_utils.h>
 
+#define ASSERT_OR_RETURN_ERROR(stmt, error)                                                        \
+    do {                                                                                           \
+        assert(stmt);                                                                              \
+        if (!(stmt)) {                                                                             \
+            return error;                                                                          \
+        }                                                                                          \
+    } while (0)
+
 namespace keymaster {
 
-constexpr uint kCurrentKeymasterVersion = 4;
-constexpr uint kCurrentAttestationVersion = 3;
 constexpr size_t kMaximumAttestationChallengeLength = 128;
 
 IMPLEMENT_ASN1_FUNCTIONS(KM_ROOT_OF_TRUST);
@@ -35,14 +46,9 @@
 IMPLEMENT_ASN1_FUNCTIONS(KM_KEY_DESCRIPTION);
 
 static const keymaster_tag_t kDeviceAttestationTags[] = {
-    KM_TAG_ATTESTATION_ID_BRAND,
-    KM_TAG_ATTESTATION_ID_DEVICE,
-    KM_TAG_ATTESTATION_ID_PRODUCT,
-    KM_TAG_ATTESTATION_ID_SERIAL,
-    KM_TAG_ATTESTATION_ID_IMEI,
-    KM_TAG_ATTESTATION_ID_MEID,
-    KM_TAG_ATTESTATION_ID_MANUFACTURER,
-    KM_TAG_ATTESTATION_ID_MODEL,
+    KM_TAG_ATTESTATION_ID_BRAND,        KM_TAG_ATTESTATION_ID_DEVICE, KM_TAG_ATTESTATION_ID_PRODUCT,
+    KM_TAG_ATTESTATION_ID_SERIAL,       KM_TAG_ATTESTATION_ID_IMEI,   KM_TAG_ATTESTATION_ID_MEID,
+    KM_TAG_ATTESTATION_ID_MANUFACTURER, KM_TAG_ATTESTATION_ID_MODEL,
 };
 
 struct KM_AUTH_LIST_Delete {
@@ -57,6 +63,25 @@
     void operator()(KM_ROOT_OF_TRUST* p) { KM_ROOT_OF_TRUST_free(p); }
 };
 
+static cppbor::Bstr blob_to_bstr(const keymaster_blob_t& blob) {
+    return cppbor::Bstr(std::pair(blob.data, blob.data_length));
+}
+
+static keymaster_error_t bstr_to_blob(const cppbor::Bstr* bstr, keymaster_blob_t* blob) {
+    ASSERT_OR_RETURN_ERROR(bstr, KM_ERROR_INVALID_TAG);
+    const std::vector<uint8_t>& vec = bstr->value();
+    uint8_t* data = (uint8_t*)calloc(vec.size(), sizeof(uint8_t));
+    if (data == nullptr) {
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    std::copy(vec.begin(), vec.end(), data);
+    blob->data = data;
+    blob->data_length = vec.size();
+
+    return KM_ERROR_OK;
+}
+
 static uint32_t get_uint32_value(const keymaster_key_param_t& param) {
     switch (keymaster_tag_get_type(param.tag)) {
     case KM_ENUM:
@@ -66,44 +91,427 @@
     case KM_UINT_REP:
         return param.integer;
     default:
-        assert(false);
-        return 0xFFFFFFFF;
+        ASSERT_OR_RETURN_ERROR(false, 0xFFFFFFFF);
     }
 }
 
+static int64_t get_uint32_value(EatSecurityLevel level) {
+    return static_cast<int64_t>(level);
+}
+
 // Insert value in either the dest_integer or the dest_integer_set, whichever is provided.
 static keymaster_error_t insert_integer(ASN1_INTEGER* value, ASN1_INTEGER** dest_integer,
                                         ASN1_INTEGER_SET** dest_integer_set) {
-    assert((dest_integer == nullptr) ^ (dest_integer_set == nullptr));
-    assert(value);
+    ASSERT_OR_RETURN_ERROR((dest_integer == nullptr) ^ (dest_integer_set == nullptr),
+                           KM_ERROR_UNEXPECTED_NULL_POINTER);
+    ASSERT_OR_RETURN_ERROR(value, KM_ERROR_INVALID_ARGUMENT);
 
     if (dest_integer_set) {
-        if (!*dest_integer_set)
+        if (!*dest_integer_set) {
             *dest_integer_set = sk_ASN1_INTEGER_new_null();
-        if (!*dest_integer_set)
+        }
+        if (!*dest_integer_set) {
             return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-        if (!sk_ASN1_INTEGER_push(*dest_integer_set, value))
+        }
+        if (!sk_ASN1_INTEGER_push(*dest_integer_set, value)) {
             return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        }
         return KM_ERROR_OK;
 
     } else if (dest_integer) {
-        if (*dest_integer)
+        if (*dest_integer) {
             ASN1_INTEGER_free(*dest_integer);
+        }
         *dest_integer = value;
         return KM_ERROR_OK;
     }
 
-    assert(false);  // Should never get here.
+    ASSERT_OR_RETURN_ERROR(false, KM_ERROR_UNKNOWN_ERROR);  // Should never get here.
+}
+
+// Add a repeating enum to a map going mapping its key to list of values.
+static void add_repeating_enum(EatClaim key, uint32_t value,
+                               std::unordered_map<EatClaim, cppbor::Array>* fields_map) {
+    auto field = fields_map->find(key);
+    if (field != fields_map->end()) {
+        field->second.add(value);
+    } else {
+        fields_map->insert({key, cppbor::Array().add(value)});
+    }
+}
+
+static keymaster_error_t
+insert_unknown_tag(const keymaster_key_param_t& param, cppbor::Map* dest_map,
+                   std::unordered_map<EatClaim, cppbor::Array>* fields_map) {
+    EatClaim private_eat_tag = static_cast<EatClaim>(convert_to_eat_claim(param.tag));
+    switch (keymaster_tag_get_type(param.tag)) {
+    case KM_ENUM:
+        dest_map->add(private_eat_tag, param.enumerated);
+        break;
+    case KM_ENUM_REP:
+        add_repeating_enum(private_eat_tag, param.enumerated, fields_map);
+        break;
+    case KM_UINT:
+        dest_map->add(private_eat_tag, param.integer);
+        break;
+    case KM_UINT_REP:
+        add_repeating_enum(private_eat_tag, param.integer, fields_map);
+        break;
+    case KM_ULONG:
+        dest_map->add(private_eat_tag, param.long_integer);
+        break;
+    case KM_ULONG_REP:
+        add_repeating_enum(private_eat_tag, param.long_integer, fields_map);
+        break;
+    case KM_DATE:
+        dest_map->add(private_eat_tag, param.date_time);
+        break;
+    case KM_BOOL:
+        dest_map->add(private_eat_tag, true);
+        break;
+    case KM_BIGNUM:
+    case KM_BYTES:
+        dest_map->add(private_eat_tag, blob_to_bstr(param.blob));
+        break;
+    default:
+        ASSERT_OR_RETURN_ERROR(false, KM_ERROR_INVALID_TAG);
+    }
     return KM_ERROR_OK;
 }
 
-// Put the contents of the keymaster AuthorizationSet auth_list in to the ASN.1 record structure,
+/**
+ * Convert an IMEI encoded as a string of numbers into the UEID format defined in
+ * https://tools.ietf.org/html/draft-ietf-rats-eat.
+ * The resulting format is a bstr encoded as follows:
+ * - Type byte: 0x03
+ * - IMEI (without check digit), encoded as byte string of length 14 with each byte as the digit's
+ *   value. The IMEI value encoded SHALL NOT include Luhn checksum or SVN information.
+ */
+keymaster_error_t imei_to_ueid(const keymaster_blob_t& imei_blob, cppbor::Bstr* out) {
+    ASSERT_OR_RETURN_ERROR(imei_blob.data_length == kImeiBlobLength, KM_ERROR_INVALID_TAG);
+
+    uint8_t ueid[kUeidLength];
+    ueid[0] = kImeiTypeByte;
+    // imei_blob corresponds to android.telephony.TelephonyManager#getDeviceId(), which is the
+    // 15-digit IMEI (including the check digit), encoded as a string.
+    for (size_t i = 1; i < kUeidLength; i++) {
+        // Convert each character to its numeric value.
+        ueid[i] = imei_blob.data[i - 1] - '0';  // Intentionally skip check digit at last position.
+    }
+
+    *out = cppbor::Bstr(std::pair(ueid, sizeof(ueid)));
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t ueid_to_imei_blob(const cppbor::Bstr* ueid, keymaster_blob_t* out) {
+    ASSERT_OR_RETURN_ERROR(ueid, KM_ERROR_INVALID_TAG);
+    const std::vector<uint8_t>& ueid_vec = ueid->value();
+    ASSERT_OR_RETURN_ERROR(ueid_vec.size() == kUeidLength, KM_ERROR_INVALID_TAG);
+    ASSERT_OR_RETURN_ERROR(ueid_vec[0] == kImeiTypeByte, KM_ERROR_INVALID_TAG);
+
+    uint8_t* imei_string = (uint8_t*)calloc(kImeiBlobLength, sizeof(uint8_t));
+    // Fill string from left to right, and calculate Luhn check digit.
+    int luhn_digit_sum = 0;
+    for (size_t i = 0; i < kImeiBlobLength - 1; i++) {
+        uint8_t digit_i = ueid_vec[i + 1];
+        // Convert digit to its string value.
+        imei_string[i] = '0' + digit_i;
+        luhn_digit_sum += i % 2 == 0 ? digit_i : digit_i * 2 / 10 + (digit_i * 2) % 10;
+    }
+    imei_string[kImeiBlobLength - 1] = '0' + (10 - luhn_digit_sum % 10) % 10;
+
+    *out = {.data = imei_string, .data_length = kImeiBlobLength};
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t ec_key_size_to_eat_curve(uint32_t key_size_bits, int* curve) {
+    switch (key_size_bits) {
+    default:
+        return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+
+    case 224:
+        *curve = (int)EatEcCurve::P_224;
+        break;
+
+    case 256:
+        *curve = (int)EatEcCurve::P_256;
+        break;
+
+    case 384:
+        *curve = (int)EatEcCurve::P_384;
+        break;
+
+    case 521:
+        *curve = (int)EatEcCurve::P_521;
+        break;
+    }
+
+    return KM_ERROR_OK;
+}
+
+bool is_valid_attestation_challenge(const keymaster_blob_t& attestation_challenge) {
+    // TODO(171864369): Limit apps targeting >= API 30 to attestations in the range of
+    // [0, 128] bytes.
+    return (attestation_challenge.data_length <= kMaximumAttestationChallengeLength);
+}
+
+Buffer generate_unique_id(const AttestationContext& context,  //
+                          const AuthorizationSet& sw_enforced,
+                          const AuthorizationSet& attestation_params,  //
+                          keymaster_error_t* error) {
+    uint64_t creation_datetime;
+    // Only check sw_enforced for TAG_CREATION_DATETIME, since it shouldn't be in tee_enforced,
+    // since this implementation has no secure wall clock.
+    if (!sw_enforced.GetTagValue(TAG_CREATION_DATETIME, &creation_datetime)) {
+        LOG_E("Unique ID cannot be created without creation datetime", 0);
+        *error = KM_ERROR_INVALID_KEY_BLOB;
+        return {};
+    }
+
+    keymaster_blob_t application_id = {nullptr, 0};
+    sw_enforced.GetTagValue(TAG_APPLICATION_ID, &application_id);
+
+    return context.GenerateUniqueId(creation_datetime, application_id,
+                                    attestation_params.GetTagValue(TAG_RESET_SINCE_ID_ROTATION),
+                                    error);
+}
+
+// Put the contents of the keymaster AuthorizationSet auth_list into the EAT record structure.
+keymaster_error_t build_eat_submod(const AuthorizationSet& auth_list,
+                                   const EatSecurityLevel security_level, cppbor::Map* submod) {
+    ASSERT_OR_RETURN_ERROR(submod, KM_ERROR_UNEXPECTED_NULL_POINTER);
+
+    if (auth_list.empty()) return KM_ERROR_OK;
+
+    submod->add(EatClaim::SECURITY_LEVEL, get_uint32_value(security_level));
+
+    // Keep repeating fields in a separate map for easy lookup.
+    // Add them to submod map in postprocessing.
+    std::unordered_map<EatClaim, cppbor::Array> repeating_fields =
+        std::unordered_map<EatClaim, cppbor::Array>();
+
+    for (auto entry : auth_list) {
+
+        switch (entry.tag) {
+
+        default:
+            // Unknown tags should only be included if they're software-enforced.
+            if (security_level == EatSecurityLevel::UNRESTRICTED) {
+                keymaster_error_t error = insert_unknown_tag(entry, submod, &repeating_fields);
+                if (error != KM_ERROR_OK) {
+                    return error;
+                }
+            }
+            break;
+
+        /* Tags ignored because they should never exist */
+        case KM_TAG_INVALID:
+
+        /* Tags ignored because they're not used. */
+        case KM_TAG_ALL_USERS:
+        case KM_TAG_EXPORTABLE:
+        case KM_TAG_ECIES_SINGLE_HASH_MODE:
+        case KM_TAG_KDF:
+
+        /* Tags ignored because they're used only to provide information to operations */
+        case KM_TAG_ASSOCIATED_DATA:
+        case KM_TAG_NONCE:
+        case KM_TAG_AUTH_TOKEN:
+        case KM_TAG_MAC_LENGTH:
+        case KM_TAG_ATTESTATION_CHALLENGE:
+        case KM_TAG_RESET_SINCE_ID_ROTATION:
+
+        /* Tags ignored because they have no meaning off-device */
+        case KM_TAG_USER_ID:
+        case KM_TAG_USER_SECURE_ID:
+        case KM_TAG_BLOB_USAGE_REQUIREMENTS:
+
+        /* Tags ignored because they're not usable by app keys */
+        case KM_TAG_BOOTLOADER_ONLY:
+        case KM_TAG_INCLUDE_UNIQUE_ID:
+        case KM_TAG_MAX_USES_PER_BOOT:
+        case KM_TAG_MIN_SECONDS_BETWEEN_OPS:
+        case KM_TAG_UNIQUE_ID:
+
+        /* Tags ignored because they contain data that should not be exported */
+        case KM_TAG_APPLICATION_DATA:
+        case KM_TAG_APPLICATION_ID:
+        case KM_TAG_ROOT_OF_TRUST:
+            continue;
+
+        /* Non-repeating enumerations */
+        case KM_TAG_ALGORITHM:
+            submod->add(EatClaim::ALGORITHM, get_uint32_value(entry));
+            break;
+        case KM_TAG_EC_CURVE:
+            submod->add(EatClaim::EC_CURVE, get_uint32_value(entry));
+            break;
+        case KM_TAG_USER_AUTH_TYPE:
+            submod->add(EatClaim::USER_AUTH_TYPE, get_uint32_value(entry));
+            break;
+        case KM_TAG_ORIGIN:
+            submod->add(EatClaim::ORIGIN, get_uint32_value(entry));
+            break;
+
+        /* Repeating enumerations */
+        case KM_TAG_PURPOSE:
+            add_repeating_enum(EatClaim::PURPOSE, get_uint32_value(entry), &repeating_fields);
+            break;
+        case KM_TAG_PADDING:
+            add_repeating_enum(EatClaim::PADDING, get_uint32_value(entry), &repeating_fields);
+            break;
+        case KM_TAG_DIGEST:
+            add_repeating_enum(EatClaim::DIGEST, get_uint32_value(entry), &repeating_fields);
+            break;
+        case KM_TAG_BLOCK_MODE:
+            add_repeating_enum(EatClaim::BLOCK_MODE, get_uint32_value(entry), &repeating_fields);
+            break;
+
+        /* Non-repeating unsigned integers */
+        case KM_TAG_KEY_SIZE:
+            submod->add(EatClaim::KEY_SIZE, get_uint32_value(entry));
+            break;
+        case KM_TAG_AUTH_TIMEOUT:
+            submod->add(EatClaim::AUTH_TIMEOUT, get_uint32_value(entry));
+            break;
+        case KM_TAG_OS_VERSION:
+            submod->add(EatClaim::OS_VERSION, get_uint32_value(entry));
+            break;
+        case KM_TAG_OS_PATCHLEVEL:
+            submod->add(EatClaim::OS_PATCHLEVEL, get_uint32_value(entry));
+            break;
+        case KM_TAG_VENDOR_PATCHLEVEL:
+            submod->add(EatClaim::VENDOR_PATCHLEVEL, get_uint32_value(entry));
+            break;
+        case KM_TAG_BOOT_PATCHLEVEL:
+            submod->add(EatClaim::BOOT_PATCHLEVEL, get_uint32_value(entry));
+            break;
+        case KM_TAG_MIN_MAC_LENGTH:
+            submod->add(EatClaim::MIN_MAC_LENGTH, get_uint32_value(entry));
+            break;
+
+        /* Non-repeating long unsigned integers */
+        case KM_TAG_RSA_PUBLIC_EXPONENT:
+            submod->add(EatClaim::RSA_PUBLIC_EXPONENT, entry.long_integer);
+            break;
+
+        /* Dates */
+        case KM_TAG_ACTIVE_DATETIME:
+            submod->add(EatClaim::ACTIVE_DATETIME, entry.date_time);
+            break;
+        case KM_TAG_ORIGINATION_EXPIRE_DATETIME:
+            submod->add(EatClaim::ORIGINATION_EXPIRE_DATETIME, entry.date_time);
+            break;
+        case KM_TAG_USAGE_EXPIRE_DATETIME:
+            submod->add(EatClaim::USAGE_EXPIRE_DATETIME, entry.date_time);
+            break;
+        case KM_TAG_CREATION_DATETIME:
+            submod->add(EatClaim::IAT, entry.date_time);
+            break;
+
+        /* Booleans */
+        case KM_TAG_NO_AUTH_REQUIRED:
+            submod->add(EatClaim::NO_AUTH_REQUIRED, true);
+            break;
+        case KM_TAG_ALL_APPLICATIONS:
+            submod->add(EatClaim::ALL_APPLICATIONS, true);
+            break;
+        case KM_TAG_ROLLBACK_RESISTANT:
+            submod->add(EatClaim::ROLLBACK_RESISTANT, true);
+            break;
+        case KM_TAG_ALLOW_WHILE_ON_BODY:
+            submod->add(EatClaim::ALLOW_WHILE_ON_BODY, true);
+            break;
+        case KM_TAG_UNLOCKED_DEVICE_REQUIRED:
+            submod->add(EatClaim::UNLOCKED_DEVICE_REQUIRED, true);
+            break;
+        case KM_TAG_CALLER_NONCE:
+            submod->add(EatClaim::CALLER_NONCE, true);
+            break;
+        case KM_TAG_TRUSTED_CONFIRMATION_REQUIRED:
+            submod->add(EatClaim::TRUSTED_CONFIRMATION_REQUIRED, true);
+            break;
+        case KM_TAG_EARLY_BOOT_ONLY:
+            submod->add(EatClaim::EARLY_BOOT_ONLY, true);
+            break;
+        case KM_TAG_DEVICE_UNIQUE_ATTESTATION:
+            submod->add(EatClaim::DEVICE_UNIQUE_ATTESTATION, true);
+            break;
+        case KM_TAG_IDENTITY_CREDENTIAL_KEY:
+            submod->add(EatClaim::IDENTITY_CREDENTIAL_KEY, true);
+            break;
+        case KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED:
+            submod->add(EatClaim::TRUSTED_USER_PRESENCE_REQUIRED, true);
+            break;
+        case KM_TAG_STORAGE_KEY:
+            submod->add(EatClaim::STORAGE_KEY, true);
+            break;
+
+        /* Byte arrays*/
+        case KM_TAG_ATTESTATION_APPLICATION_ID:
+            submod->add(EatClaim::ATTESTATION_APPLICATION_ID, blob_to_bstr(entry.blob));
+            break;
+        case KM_TAG_ATTESTATION_ID_BRAND:
+            submod->add(EatClaim::ATTESTATION_ID_BRAND, blob_to_bstr(entry.blob));
+            break;
+        case KM_TAG_ATTESTATION_ID_DEVICE:
+            submod->add(EatClaim::ATTESTATION_ID_DEVICE, blob_to_bstr(entry.blob));
+            break;
+        case KM_TAG_ATTESTATION_ID_PRODUCT:
+            submod->add(EatClaim::ATTESTATION_ID_PRODUCT, blob_to_bstr(entry.blob));
+            break;
+        case KM_TAG_ATTESTATION_ID_SERIAL:
+            submod->add(EatClaim::ATTESTATION_ID_SERIAL, blob_to_bstr(entry.blob));
+            break;
+        case KM_TAG_ATTESTATION_ID_IMEI: {
+            cppbor::Bstr ueid("");
+            keymaster_error_t error = imei_to_ueid(entry.blob, &ueid);
+            if (error != KM_ERROR_OK) return error;
+            submod->add(EatClaim::UEID, ueid);
+            break;
+        }
+        case KM_TAG_ATTESTATION_ID_MEID:
+            submod->add(EatClaim::ATTESTATION_ID_MEID, blob_to_bstr(entry.blob));
+            break;
+        case KM_TAG_ATTESTATION_ID_MANUFACTURER:
+            submod->add(EatClaim::ATTESTATION_ID_MANUFACTURER, blob_to_bstr(entry.blob));
+            break;
+        case KM_TAG_ATTESTATION_ID_MODEL:
+            submod->add(EatClaim::ATTESTATION_ID_MODEL, blob_to_bstr(entry.blob));
+            break;
+        case KM_TAG_CONFIRMATION_TOKEN:
+            submod->add(EatClaim::CONFIRMATION_TOKEN, blob_to_bstr(entry.blob));
+            break;
+        }
+    }
+
+    // Move values from repeating enums into the submod map.
+    for (auto const& repeating_field : repeating_fields) {
+        EatClaim key = static_cast<EatClaim>(repeating_field.first);
+        submod->add(key, std::move(repeating_fields.at(key)));
+    }
+
+    int ec_curve;
+    uint32_t key_size;
+    if (auth_list.Contains(TAG_ALGORITHM, KM_ALGORITHM_EC) && !auth_list.Contains(TAG_EC_CURVE) &&
+        auth_list.GetTagValue(TAG_KEY_SIZE, &key_size)) {
+        // This must be a keymaster1 key. It's an EC key with no curve.  Insert the curve.
+
+        keymaster_error_t error = ec_key_size_to_eat_curve(key_size, &ec_curve);
+        if (error != KM_ERROR_OK) return error;
+
+        submod->add(EatClaim::EC_CURVE, ec_curve);
+    }
+
+    return KM_ERROR_OK;
+}
+
+// Put the contents of the keymaster AuthorizationSet auth_list into the ASN.1 record structure,
 // record.
 keymaster_error_t build_auth_list(const AuthorizationSet& auth_list, KM_AUTH_LIST* record) {
-    assert(record);
+    ASSERT_OR_RETURN_ERROR(record, KM_ERROR_UNEXPECTED_NULL_POINTER);
 
-    if (auth_list.empty())
-        return KM_ERROR_OK;
+    if (auth_list.empty()) return KM_ERROR_OK;
 
     for (auto entry : auth_list) {
 
@@ -129,6 +537,13 @@
         case KM_TAG_MAC_LENGTH:
         case KM_TAG_ATTESTATION_CHALLENGE:
         case KM_TAG_RESET_SINCE_ID_ROTATION:
+        case KM_TAG_KDF:
+
+        /* Tags ignored because they're used only to provide for certificate generation */
+        case KM_TAG_CERTIFICATE_SERIAL:
+        case KM_TAG_CERTIFICATE_SUBJECT:
+        case KM_TAG_CERTIFICATE_NOT_BEFORE:
+        case KM_TAG_CERTIFICATE_NOT_AFTER:
 
         /* Tags ignored because they have no meaning off-device */
         case KM_TAG_USER_ID:
@@ -138,12 +553,16 @@
         /* Tags ignored because they're not usable by app keys */
         case KM_TAG_BOOTLOADER_ONLY:
         case KM_TAG_INCLUDE_UNIQUE_ID:
+        case KM_TAG_MAX_BOOT_LEVEL:
         case KM_TAG_MAX_USES_PER_BOOT:
         case KM_TAG_MIN_SECONDS_BETWEEN_OPS:
+        case KM_TAG_STORAGE_KEY:
         case KM_TAG_UNIQUE_ID:
 
         /* Tags ignored because they contain data that should not be exported */
         case KM_TAG_APPLICATION_DATA:
+        case KM_TAG_APPLICATION_ID:
+        case KM_TAG_CONFIRMATION_TOKEN:
         case KM_TAG_ROOT_OF_TRUST:
             continue;
 
@@ -171,12 +590,12 @@
         case KM_TAG_DIGEST:
             integer_set = &record->digest;
             break;
-        case KM_TAG_KDF:
-            integer_set = &record->kdf;
-            break;
         case KM_TAG_BLOCK_MODE:
             integer_set = &record->block_mode;
             break;
+        case KM_TAG_RSA_OAEP_MGF_DIGEST:
+            integer_set = &record->mgf_digest;
+            break;
 
         /* Non-repeating unsigned integers */
         case KM_TAG_KEY_SIZE:
@@ -194,6 +613,15 @@
         case KM_TAG_MIN_MAC_LENGTH:
             integer_ptr = &record->min_mac_length;
             break;
+        case KM_TAG_BOOT_PATCHLEVEL:
+            integer_ptr = &record->boot_patch_level;
+            break;
+        case KM_TAG_VENDOR_PATCHLEVEL:
+            integer_ptr = &record->vendor_patchlevel;
+            break;
+        case KM_TAG_USAGE_COUNT_LIMIT:
+            integer_ptr = &record->usage_count_limit;
+            break;
 
         /* Non-repeating long unsigned integers */
         case KM_TAG_RSA_PUBLIC_EXPONENT:
@@ -239,11 +667,20 @@
         case KM_TAG_TRUSTED_CONFIRMATION_REQUIRED:
             bool_ptr = &record->trusted_confirmation_required;
             break;
+        case KM_TAG_EARLY_BOOT_ONLY:
+            bool_ptr = &record->early_boot_only;
+            break;
+        case KM_TAG_DEVICE_UNIQUE_ATTESTATION:
+            bool_ptr = &record->device_unique_attestation;
+            break;
+        case KM_TAG_IDENTITY_CREDENTIAL_KEY:
+            bool_ptr = &record->identity_credential_key;
+            break;
+        case KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED:
+            bool_ptr = &record->trusted_user_presence_required;
+            break;
 
         /* Byte arrays*/
-        case KM_TAG_APPLICATION_ID:
-            string_ptr = &record->application_id;
-            break;
         case KM_TAG_ATTESTATION_APPLICATION_ID:
             string_ptr = &record->attestation_application_id;
             break;
@@ -279,14 +716,17 @@
         case KM_ENUM_REP:
         case KM_UINT:
         case KM_UINT_REP: {
-            assert((keymaster_tag_repeatable(entry.tag) && integer_set) ||
-                   (!keymaster_tag_repeatable(entry.tag) && integer_ptr));
+            ASSERT_OR_RETURN_ERROR((keymaster_tag_repeatable(entry.tag) && integer_set) ||
+                                       (!keymaster_tag_repeatable(entry.tag) && integer_ptr),
+                                   KM_ERROR_INVALID_TAG);
 
             UniquePtr<ASN1_INTEGER, ASN1_INTEGER_Delete> value(ASN1_INTEGER_new());
-            if (!value.get())
+            if (!value.get()) {
                 return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-            if (!ASN1_INTEGER_set(value.get(), get_uint32_value(entry)))
+            }
+            if (!ASN1_INTEGER_set(value.get(), get_uint32_value(entry))) {
                 return TranslateLastOpenSslError();
+            }
 
             insert_integer(value.release(), integer_ptr, integer_set);
             break;
@@ -295,12 +735,14 @@
         case KM_ULONG:
         case KM_ULONG_REP:
         case KM_DATE: {
-            assert((keymaster_tag_repeatable(entry.tag) && integer_set) ||
-                   (!keymaster_tag_repeatable(entry.tag) && integer_ptr));
+            ASSERT_OR_RETURN_ERROR((keymaster_tag_repeatable(entry.tag) && integer_set) ||
+                                       (!keymaster_tag_repeatable(entry.tag) && integer_ptr),
+                                   KM_ERROR_INVALID_TAG);
 
             UniquePtr<BIGNUM, BIGNUM_Delete> bn_value(BN_new());
-            if (!bn_value.get())
+            if (!bn_value.get()) {
                 return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+            }
 
             if (type == KM_DATE) {
                 if (!BN_set_u64(bn_value.get(), entry.date_time)) {
@@ -314,30 +756,32 @@
 
             UniquePtr<ASN1_INTEGER, ASN1_INTEGER_Delete> value(
                 BN_to_ASN1_INTEGER(bn_value.get(), nullptr));
-            if (!value.get())
+            if (!value.get()) {
                 return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+            }
 
             insert_integer(value.release(), integer_ptr, integer_set);
             break;
         }
 
         case KM_BOOL:
-            assert(bool_ptr);
-            if (!*bool_ptr)
-                *bool_ptr = ASN1_NULL_new();
-            if (!*bool_ptr)
-                return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+            ASSERT_OR_RETURN_ERROR(bool_ptr, KM_ERROR_INVALID_TAG);
+            if (!*bool_ptr) *bool_ptr = ASN1_NULL_new();
+            if (!*bool_ptr) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
             break;
 
         /* Byte arrays*/
         case KM_BYTES:
-            assert(string_ptr);
-            if (!*string_ptr)
+            ASSERT_OR_RETURN_ERROR(string_ptr, KM_ERROR_INVALID_TAG);
+            if (!*string_ptr) {
                 *string_ptr = ASN1_OCTET_STRING_new();
-            if (!*string_ptr)
+            }
+            if (!*string_ptr) {
                 return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-            if (!ASN1_OCTET_STRING_set(*string_ptr, entry.blob.data, entry.blob.data_length))
+            }
+            if (!ASN1_OCTET_STRING_set(*string_ptr, entry.blob.data, entry.blob.data_length)) {
                 return TranslateLastOpenSslError();
+            }
             break;
 
         default:
@@ -353,15 +797,16 @@
         // This must be a keymaster1 key. It's an EC key with no curve.  Insert the curve.
 
         keymaster_error_t error = EcKeySizeToCurve(key_size, &ec_curve);
-        if (error != KM_ERROR_OK)
-            return error;
+        if (error != KM_ERROR_OK) return error;
 
         UniquePtr<ASN1_INTEGER, ASN1_INTEGER_Delete> value(ASN1_INTEGER_new());
-        if (!value.get())
+        if (!value.get()) {
             return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        }
 
-        if (!ASN1_INTEGER_set(value.get(), ec_curve))
+        if (!ASN1_INTEGER_set(value.get(), ec_curve)) {
             return TranslateLastOpenSslError();
+        }
 
         insert_integer(value.release(), &record->ec_curve, nullptr);
     }
@@ -369,19 +814,164 @@
     return KM_ERROR_OK;
 }
 
+// Construct a CBOR-encoded attestation record containing the values from sw_enforced
+// and tee_enforced.
+keymaster_error_t build_eat_record(const AuthorizationSet& attestation_params,
+                                   AuthorizationSet sw_enforced, AuthorizationSet tee_enforced,
+                                   const AttestationContext& context,
+                                   std::vector<uint8_t>* eat_token) {
+    ASSERT_OR_RETURN_ERROR(eat_token, KM_ERROR_UNEXPECTED_NULL_POINTER);
+
+    cppbor::Map eat_record;
+    switch (context.GetSecurityLevel()) {
+    case KM_SECURITY_LEVEL_SOFTWARE:
+        eat_record.add(EatClaim::SECURITY_LEVEL, get_uint32_value(EatSecurityLevel::UNRESTRICTED));
+        break;
+    case KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT:
+        eat_record.add(EatClaim::SECURITY_LEVEL,
+                       get_uint32_value(EatSecurityLevel::SECURE_RESTRICTED));
+        break;
+    case KM_SECURITY_LEVEL_STRONGBOX:
+        eat_record.add(EatClaim::SECURITY_LEVEL, get_uint32_value(EatSecurityLevel::HARDWARE));
+        break;
+    default:
+        return KM_ERROR_UNKNOWN_ERROR;
+    }
+
+    keymaster_error_t error;
+    const AttestationContext::VerifiedBootParams* vb_params = context.GetVerifiedBootParams(&error);
+    if (error != KM_ERROR_OK) return error;
+
+    if (vb_params->verified_boot_key.data_length) {
+        eat_record.add(EatClaim::VERIFIED_BOOT_KEY, blob_to_bstr(vb_params->verified_boot_key));
+    }
+    if (vb_params->verified_boot_hash.data_length) {
+        eat_record.add(EatClaim::VERIFIED_BOOT_HASH, blob_to_bstr(vb_params->verified_boot_hash));
+    }
+    if (vb_params->device_locked) {
+        eat_record.add(EatClaim::DEVICE_LOCKED, vb_params->device_locked);
+    }
+
+    bool verified_or_self_signed = (vb_params->verified_boot_state == KM_VERIFIED_BOOT_VERIFIED ||
+                                    vb_params->verified_boot_state == KM_VERIFIED_BOOT_SELF_SIGNED);
+    auto eat_boot_state = cppbor::Array()
+                              .add(verified_or_self_signed)  // secure-boot-enabled
+                              .add(verified_or_self_signed)  // debug-disabled
+                              .add(verified_or_self_signed)  // debug-disabled-since-boot
+                              .add(verified_or_self_signed)  // debug-permanent-disable
+                              .add(false);  // debug-full-permanent-disable (no way to verify)
+    eat_record.add(EatClaim::BOOT_STATE, std::move(eat_boot_state));
+    eat_record.add(EatClaim::OFFICIAL_BUILD,
+                   vb_params->verified_boot_state == KM_VERIFIED_BOOT_VERIFIED);
+
+    eat_record.add(EatClaim::ATTESTATION_VERSION,
+                   version_to_attestation_version(context.GetKmVersion()));
+    eat_record.add(EatClaim::KEYMASTER_VERSION,
+                   version_to_attestation_km_version(context.GetKmVersion()));
+
+    keymaster_blob_t attestation_challenge = {nullptr, 0};
+    if (!attestation_params.GetTagValue(TAG_ATTESTATION_CHALLENGE, &attestation_challenge)) {
+        return KM_ERROR_ATTESTATION_CHALLENGE_MISSING;
+    }
+
+    if (!is_valid_attestation_challenge(attestation_challenge)) {
+        return KM_ERROR_INVALID_INPUT_LENGTH;
+    }
+
+    eat_record.add(EatClaim::NONCE, blob_to_bstr(attestation_challenge));
+
+    keymaster_blob_t attestation_app_id;
+    if (!attestation_params.GetTagValue(TAG_ATTESTATION_APPLICATION_ID, &attestation_app_id)) {
+        return KM_ERROR_ATTESTATION_APPLICATION_ID_MISSING;
+    }
+    // TODO: what should happen when sw_enforced already contains TAG_ATTESTATION_APPLICATION_ID?
+    // (as is the case in android_keymaster_test.cpp). For now, we will ignore the provided one in
+    // attestation_params if that's the case.
+    keymaster_blob_t existing_app_id;
+    if (!sw_enforced.GetTagValue(TAG_ATTESTATION_APPLICATION_ID, &existing_app_id)) {
+        sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID, attestation_app_id);
+    }
+
+    error = context.VerifyAndCopyDeviceIds(
+        attestation_params,
+        context.GetSecurityLevel() == KM_SECURITY_LEVEL_SOFTWARE ? &sw_enforced : &tee_enforced);
+    if (error == KM_ERROR_UNIMPLEMENTED) {
+        // The KeymasterContext implementation does not support device ID attestation. Bail out if
+        // device ID attestation is being attempted.
+        for (const auto& tag : kDeviceAttestationTags) {
+            if (attestation_params.find(tag) != -1) {
+                return KM_ERROR_CANNOT_ATTEST_IDS;
+            }
+        }
+    } else if (error != KM_ERROR_OK) {
+        return error;
+    }
+
+    if (attestation_params.Contains(TAG_DEVICE_UNIQUE_ATTESTATION) &&
+        context.GetSecurityLevel() == KM_SECURITY_LEVEL_STRONGBOX) {
+        eat_record.add(EatClaim::DEVICE_UNIQUE_ATTESTATION, true);
+    }
+
+    cppbor::Map software_submod;
+    error = build_eat_submod(sw_enforced, EatSecurityLevel::UNRESTRICTED, &software_submod);
+    if (error != KM_ERROR_OK) return error;
+
+    cppbor::Map tee_submod;
+    error = build_eat_submod(tee_enforced, EatSecurityLevel::SECURE_RESTRICTED, &tee_submod);
+    if (error != KM_ERROR_OK) return error;
+
+    if (software_submod.size() + tee_submod.size() > 0) {
+        cppbor::Map submods;
+        if (software_submod.size() > 0) {
+            submods.add(kEatSubmodNameSoftware, std::move(software_submod));
+        }
+        if (tee_submod.size() > 0) {
+            submods.add(kEatSubmodNameTee, std::move(tee_submod));
+        }
+
+        eat_record.add(EatClaim::SUBMODS, std::move(submods));
+    }
+
+    // Only check tee_enforced for TAG_INCLUDE_UNIQUE_ID.  If we don't have hardware we can't
+    // generate unique IDs.
+    if (tee_enforced.GetTagValue(TAG_INCLUDE_UNIQUE_ID)) {
+        uint64_t creation_datetime;
+        // Only check sw_enforced for TAG_CREATION_DATETIME, since it shouldn't be in tee_enforced,
+        // since this implementation has no secure wall clock.
+        if (!sw_enforced.GetTagValue(TAG_CREATION_DATETIME, &creation_datetime)) {
+            LOG_E("Unique ID cannot be created without creation datetime", 0);
+            return KM_ERROR_INVALID_KEY_BLOB;
+        }
+
+        keymaster_blob_t application_id = {nullptr, 0};
+        sw_enforced.GetTagValue(TAG_APPLICATION_ID, &application_id);
+
+        Buffer unique_id = context.GenerateUniqueId(
+            creation_datetime, application_id,
+            attestation_params.GetTagValue(TAG_RESET_SINCE_ID_ROTATION), &error);
+        if (error != KM_ERROR_OK) return error;
+
+        eat_record.add(EatClaim::CTI,
+                       cppbor::Bstr(std::pair(unique_id.begin(), unique_id.available_read())));
+    }
+
+    *eat_token = eat_record.encode();
+
+    return KM_ERROR_OK;
+}
+
 // Construct an ASN1.1 DER-encoded attestation record containing the values from sw_enforced and
 // tee_enforced.
-keymaster_error_t build_attestation_record(const AuthorizationSet& attestation_params,
+keymaster_error_t build_attestation_record(const AuthorizationSet& attestation_params,  //
                                            AuthorizationSet sw_enforced,
                                            AuthorizationSet tee_enforced,
-                                           const AttestationRecordContext& context,
+                                           const AttestationContext& context,
                                            UniquePtr<uint8_t[]>* asn1_key_desc,
                                            size_t* asn1_key_desc_len) {
-    assert(asn1_key_desc && asn1_key_desc_len);
+    ASSERT_OR_RETURN_ERROR(asn1_key_desc && asn1_key_desc_len, KM_ERROR_UNEXPECTED_NULL_POINTER);
 
     UniquePtr<KM_KEY_DESCRIPTION, KM_KEY_DESCRIPTION_Delete> key_desc(KM_KEY_DESCRIPTION_new());
-    if (!key_desc.get())
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!key_desc.get()) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
     KM_ROOT_OF_TRUST* root_of_trust = nullptr;
     if (context.GetSecurityLevel() == KM_SECURITY_LEVEL_SOFTWARE) {
@@ -392,51 +982,53 @@
         root_of_trust = key_desc->tee_enforced->root_of_trust;
     }
 
-    keymaster_blob_t verified_boot_key;
-    keymaster_blob_t verified_boot_hash;
-    keymaster_verified_boot_t verified_boot_state;
-    bool device_locked;
-    keymaster_error_t error = context.GetVerifiedBootParams(&verified_boot_key, &verified_boot_hash,
-                                                            &verified_boot_state, &device_locked);
+    keymaster_error_t error;
+    auto vb_params = context.GetVerifiedBootParams(&error);
     if (error != KM_ERROR_OK) return error;
-    if (verified_boot_key.data_length &&
-        !ASN1_OCTET_STRING_set(root_of_trust->verified_boot_key, verified_boot_key.data,
-                               verified_boot_key.data_length)) {
+    if (vb_params->verified_boot_key.data_length &&
+        !ASN1_OCTET_STRING_set(root_of_trust->verified_boot_key, vb_params->verified_boot_key.data,
+                               vb_params->verified_boot_key.data_length)) {
+        return TranslateLastOpenSslError();
+    }
+    if (vb_params->verified_boot_hash.data_length &&
+        !ASN1_OCTET_STRING_set(root_of_trust->verified_boot_hash,
+                               vb_params->verified_boot_hash.data,
+                               vb_params->verified_boot_hash.data_length)) {
         return TranslateLastOpenSslError();
     }
 
-    root_of_trust->device_locked = reinterpret_cast<int*>(malloc(sizeof(ASN1_BOOLEAN)));
-    *root_of_trust->device_locked = device_locked;
-    if (!ASN1_ENUMERATED_set(root_of_trust->verified_boot_state, verified_boot_state)) {
-        return TranslateLastOpenSslError();
-    }
-    if (verified_boot_hash.data_length &&
-        !ASN1_OCTET_STRING_set(root_of_trust->verified_boot_hash, verified_boot_hash.data,
-                               verified_boot_hash.data_length)) {
+    root_of_trust->device_locked = vb_params->device_locked ? 0xFF : 0x00;
+    if (!ASN1_ENUMERATED_set(root_of_trust->verified_boot_state, vb_params->verified_boot_state)) {
         return TranslateLastOpenSslError();
     }
 
-    if (!ASN1_INTEGER_set(key_desc->attestation_version, kCurrentAttestationVersion) ||
+    if (!ASN1_INTEGER_set(key_desc->attestation_version,
+                          version_to_attestation_version(context.GetKmVersion())) ||
         !ASN1_ENUMERATED_set(key_desc->attestation_security_level, context.GetSecurityLevel()) ||
-        !ASN1_INTEGER_set(key_desc->keymaster_version, kCurrentKeymasterVersion) ||
+        !ASN1_INTEGER_set(key_desc->keymaster_version,
+                          version_to_attestation_km_version(context.GetKmVersion())) ||
         !ASN1_ENUMERATED_set(key_desc->keymaster_security_level, context.GetSecurityLevel())) {
         return TranslateLastOpenSslError();
     }
 
     keymaster_blob_t attestation_challenge = {nullptr, 0};
-    if (!attestation_params.GetTagValue(TAG_ATTESTATION_CHALLENGE, &attestation_challenge))
+    if (!attestation_params.GetTagValue(TAG_ATTESTATION_CHALLENGE, &attestation_challenge)) {
         return KM_ERROR_ATTESTATION_CHALLENGE_MISSING;
+    }
 
-    if (attestation_challenge.data_length > kMaximumAttestationChallengeLength)
+    if (!is_valid_attestation_challenge(attestation_challenge)) {
         return KM_ERROR_INVALID_INPUT_LENGTH;
+    }
 
     if (!ASN1_OCTET_STRING_set(key_desc->attestation_challenge, attestation_challenge.data,
-                               attestation_challenge.data_length))
+                               attestation_challenge.data_length)) {
         return TranslateLastOpenSslError();
+    }
 
     keymaster_blob_t attestation_app_id;
-    if (!attestation_params.GetTagValue(TAG_ATTESTATION_APPLICATION_ID, &attestation_app_id))
+    if (!attestation_params.GetTagValue(TAG_ATTESTATION_APPLICATION_ID, &attestation_app_id)) {
         return KM_ERROR_ATTESTATION_APPLICATION_ID_MISSING;
+    }
     sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID, attestation_app_id);
 
     error = context.VerifyAndCopyDeviceIds(
@@ -454,13 +1046,16 @@
         return error;
     }
 
+    if (attestation_params.Contains(TAG_DEVICE_UNIQUE_ATTESTATION) &&
+        context.GetSecurityLevel() == KM_SECURITY_LEVEL_STRONGBOX) {
+        tee_enforced.push_back(TAG_DEVICE_UNIQUE_ATTESTATION);
+    };
+
     error = build_auth_list(sw_enforced, key_desc->software_enforced);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     error = build_auth_list(tee_enforced, key_desc->tee_enforced);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     // Only check tee_enforced for TAG_INCLUDE_UNIQUE_ID.  If we don't have hardware we can't
     // generate unique IDs.
@@ -476,12 +1071,10 @@
         keymaster_blob_t application_id = {nullptr, 0};
         sw_enforced.GetTagValue(TAG_APPLICATION_ID, &application_id);
 
-        Buffer unique_id;
-        error = context.GenerateUniqueId(
+        Buffer unique_id = context.GenerateUniqueId(
             creation_datetime, application_id,
-            attestation_params.GetTagValue(TAG_RESET_SINCE_ID_ROTATION), &unique_id);
-        if (error != KM_ERROR_OK)
-            return error;
+            attestation_params.GetTagValue(TAG_RESET_SINCE_ID_ROTATION), &error);
+        if (error != KM_ERROR_OK) return error;
 
         key_desc->unique_id = ASN1_OCTET_STRING_new();
         if (!key_desc->unique_id ||
@@ -491,16 +1084,13 @@
     }
 
     int len = i2d_KM_KEY_DESCRIPTION(key_desc.get(), nullptr);
-    if (len < 0)
-        return TranslateLastOpenSslError();
+    if (len < 0) return TranslateLastOpenSslError();
     *asn1_key_desc_len = len;
-    asn1_key_desc->reset(new(std::nothrow) uint8_t[*asn1_key_desc_len]);
-    if (!asn1_key_desc->get())
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    asn1_key_desc->reset(new (std::nothrow) uint8_t[*asn1_key_desc_len]);
+    if (!asn1_key_desc->get()) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
     uint8_t* p = asn1_key_desc->get();
     len = i2d_KM_KEY_DESCRIPTION(key_desc.get(), &p);
-    if (len < 0)
-        return TranslateLastOpenSslError();
+    if (len < 0) return TranslateLastOpenSslError();
 
     return KM_ERROR_OK;
 }
@@ -508,7 +1098,7 @@
 // Copy all enumerated values with the specified tag from stack to auth_list.
 static bool get_repeated_enums(const ASN1_INTEGER_SET* stack, keymaster_tag_t tag,
                                AuthorizationSet* auth_list) {
-    assert(keymaster_tag_get_type(tag) == KM_ENUM_REP);
+    ASSERT_OR_RETURN_ERROR(keymaster_tag_get_type(tag) == KM_ENUM_REP, KM_ERROR_INVALID_TAG);
     for (size_t i = 0; i < sk_ASN1_INTEGER_num(stack); ++i) {
         if (!auth_list->push_back(
                 keymaster_param_enum(tag, ASN1_INTEGER_get(sk_ASN1_INTEGER_value(stack, i)))))
@@ -521,196 +1111,283 @@
 template <keymaster_tag_type_t Type, keymaster_tag_t Tag, typename KeymasterEnum>
 static bool get_enum(const ASN1_INTEGER* asn1_int, TypedEnumTag<Type, Tag, KeymasterEnum> tag,
                      AuthorizationSet* auth_list) {
-    if (!asn1_int)
-        return true;
+    if (!asn1_int) return true;
     return auth_list->push_back(tag, static_cast<KeymasterEnum>(ASN1_INTEGER_get(asn1_int)));
 }
 
 // Add the specified ulong tag/value pair to auth_list.
 static bool get_ulong(const ASN1_INTEGER* asn1_int, keymaster_tag_t tag,
                       AuthorizationSet* auth_list) {
-    if (!asn1_int)
-        return true;
+    if (!asn1_int) return true;
     UniquePtr<BIGNUM, BIGNUM_Delete> bn(ASN1_INTEGER_to_BN(asn1_int, nullptr));
-    if (!bn.get())
-        return false;
-    uint64_t ulong = BN_get_word(bn.get());
+    if (!bn.get()) return false;
+    uint64_t ulong = 0;
+    BN_get_u64(bn.get(), &ulong);
     return auth_list->push_back(keymaster_param_long(tag, ulong));
 }
 
 // Extract the values from the specified ASN.1 record and place them in auth_list.
 keymaster_error_t extract_auth_list(const KM_AUTH_LIST* record, AuthorizationSet* auth_list) {
-    if (!record)
-        return KM_ERROR_OK;
+    if (!record) return KM_ERROR_OK;
 
     // Purpose
-    if (!get_repeated_enums(record->purpose, TAG_PURPOSE, auth_list))
+    if (!get_repeated_enums(record->purpose, TAG_PURPOSE, auth_list)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // Algorithm
-    if (!get_enum(record->algorithm, TAG_ALGORITHM, auth_list))
+    if (!get_enum(record->algorithm, TAG_ALGORITHM, auth_list)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // Key size
-    if (record->key_size && !auth_list->push_back(TAG_KEY_SIZE, ASN1_INTEGER_get(record->key_size)))
+    if (record->key_size &&
+        !auth_list->push_back(TAG_KEY_SIZE, ASN1_INTEGER_get(record->key_size))) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // Block mode
-    if (!get_repeated_enums(record->block_mode, TAG_BLOCK_MODE, auth_list))
+    if (!get_repeated_enums(record->block_mode, TAG_BLOCK_MODE, auth_list)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // Digest
-    if (!get_repeated_enums(record->digest, TAG_DIGEST, auth_list))
+    if (!get_repeated_enums(record->digest, TAG_DIGEST, auth_list)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // Padding
-    if (!get_repeated_enums(record->padding, TAG_PADDING, auth_list))
+    if (!get_repeated_enums(record->padding, TAG_PADDING, auth_list)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // Caller nonce
-    if (record->caller_nonce && !auth_list->push_back(TAG_CALLER_NONCE))
+    if (record->caller_nonce && !auth_list->push_back(TAG_CALLER_NONCE)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // Min mac length
-    if (!get_ulong(record->min_mac_length, TAG_MIN_MAC_LENGTH, auth_list))
+    if (!get_ulong(record->min_mac_length, TAG_MIN_MAC_LENGTH, auth_list)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // EC curve
-    if (!get_enum(record->ec_curve, TAG_EC_CURVE, auth_list))
+    if (!get_enum(record->ec_curve, TAG_EC_CURVE, auth_list)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // RSA public exponent
-    if (!get_ulong(record->rsa_public_exponent, TAG_RSA_PUBLIC_EXPONENT, auth_list))
+    if (!get_ulong(record->rsa_public_exponent, TAG_RSA_PUBLIC_EXPONENT, auth_list)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    // Rsa Oaep Mgf Digest
+    if (!get_repeated_enums(record->mgf_digest, TAG_RSA_OAEP_MGF_DIGEST, auth_list)) {
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    // Rollback resistance
+    if (record->rollback_resistance && !auth_list->push_back(TAG_ROLLBACK_RESISTANCE)) {
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    // Early boot only
+    if (record->early_boot_only && !auth_list->push_back(TAG_EARLY_BOOT_ONLY)) {
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // Active date time
-    if (!get_ulong(record->active_date_time, TAG_ACTIVE_DATETIME, auth_list))
+    if (!get_ulong(record->active_date_time, TAG_ACTIVE_DATETIME, auth_list)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // Origination expire date time
     if (!get_ulong(record->origination_expire_date_time, TAG_ORIGINATION_EXPIRE_DATETIME,
-                   auth_list))
+                   auth_list)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // Usage Expire date time
-    if (!get_ulong(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list))
+    if (!get_ulong(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    // Usage count limit
+    if (record->usage_count_limit &&
+        !auth_list->push_back(TAG_USAGE_COUNT_LIMIT, ASN1_INTEGER_get(record->usage_count_limit))) {
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // No auth required
-    if (record->no_auth_required && !auth_list->push_back(TAG_NO_AUTH_REQUIRED))
+    if (record->no_auth_required && !auth_list->push_back(TAG_NO_AUTH_REQUIRED)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // User auth type
-    if (!get_enum(record->user_auth_type, TAG_USER_AUTH_TYPE, auth_list))
+    if (!get_enum(record->user_auth_type, TAG_USER_AUTH_TYPE, auth_list)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // Auth timeout
     if (record->auth_timeout &&
-        !auth_list->push_back(TAG_AUTH_TIMEOUT, ASN1_INTEGER_get(record->auth_timeout)))
+        !auth_list->push_back(TAG_AUTH_TIMEOUT, ASN1_INTEGER_get(record->auth_timeout))) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    // Allow while on body
+    if (record->allow_while_on_body && !auth_list->push_back(TAG_ALLOW_WHILE_ON_BODY)) {
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    // trusted user presence required
+    if (record->trusted_user_presence_required &&
+        !auth_list->push_back(TAG_TRUSTED_USER_PRESENCE_REQUIRED)) {
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    // trusted confirmation required
+    if (record->trusted_confirmation_required &&
+        !auth_list->push_back(TAG_TRUSTED_CONFIRMATION_REQUIRED)) {
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    // Unlocked device required
+    if (record->unlocked_device_required && !auth_list->push_back(TAG_UNLOCKED_DEVICE_REQUIRED)) {
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // All applications
-    if (record->all_applications && !auth_list->push_back(TAG_ALL_APPLICATIONS))
+    if (record->all_applications && !auth_list->push_back(TAG_ALL_APPLICATIONS)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // Application ID
     if (record->application_id &&
         !auth_list->push_back(TAG_APPLICATION_ID, record->application_id->data,
-                              record->application_id->length))
+                              record->application_id->length)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
-    // Attestation application ID
-    if (record->attestation_application_id &&
-        !auth_list->push_back(TAG_ATTESTATION_APPLICATION_ID,
-                              record->attestation_application_id->data,
-                              record->attestation_application_id->length))
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // Creation date time
-    if (!get_ulong(record->creation_date_time, TAG_CREATION_DATETIME, auth_list))
+    if (!get_ulong(record->creation_date_time, TAG_CREATION_DATETIME, auth_list)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // Origin
-    if (!get_enum(record->origin, TAG_ORIGIN, auth_list))
+    if (!get_enum(record->origin, TAG_ORIGIN, auth_list)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // Rollback resistant
-    if (record->rollback_resistant && !auth_list->push_back(TAG_ROLLBACK_RESISTANT))
+    if (record->rollback_resistant && !auth_list->push_back(TAG_ROLLBACK_RESISTANT)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // Root of trust
     if (record->root_of_trust) {
         KM_ROOT_OF_TRUST* rot = record->root_of_trust;
-        if (!rot->verified_boot_key)
-            return KM_ERROR_INVALID_KEY_BLOB;
+        if (!rot->verified_boot_key) return KM_ERROR_INVALID_KEY_BLOB;
 
         // Other root of trust fields are not mapped to auth set entries.
     }
 
     // OS Version
     if (record->os_version &&
-        !auth_list->push_back(TAG_OS_VERSION, ASN1_INTEGER_get(record->os_version)))
+        !auth_list->push_back(TAG_OS_VERSION, ASN1_INTEGER_get(record->os_version))) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // OS Patch level
     if (record->os_patchlevel &&
-        !auth_list->push_back(TAG_OS_PATCHLEVEL, ASN1_INTEGER_get(record->os_patchlevel)))
+        !auth_list->push_back(TAG_OS_PATCHLEVEL, ASN1_INTEGER_get(record->os_patchlevel))) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    // attestation application Id
+    if (record->attestation_application_id &&
+        !auth_list->push_back(TAG_ATTESTATION_APPLICATION_ID,
+                              record->attestation_application_id->data,
+                              record->attestation_application_id->length)) {
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // Brand name
     if (record->attestation_id_brand &&
         !auth_list->push_back(TAG_ATTESTATION_ID_BRAND, record->attestation_id_brand->data,
-                              record->attestation_id_brand->length))
+                              record->attestation_id_brand->length)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // Device name
     if (record->attestation_id_device &&
         !auth_list->push_back(TAG_ATTESTATION_ID_DEVICE, record->attestation_id_device->data,
-                              record->attestation_id_device->length))
+                              record->attestation_id_device->length)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // Product name
     if (record->attestation_id_product &&
         !auth_list->push_back(TAG_ATTESTATION_ID_PRODUCT, record->attestation_id_product->data,
-                              record->attestation_id_product->length))
+                              record->attestation_id_product->length)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // Serial number
     if (record->attestation_id_serial &&
         !auth_list->push_back(TAG_ATTESTATION_ID_SERIAL, record->attestation_id_serial->data,
-                              record->attestation_id_serial->length))
+                              record->attestation_id_serial->length)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // IMEI
     if (record->attestation_id_imei &&
         !auth_list->push_back(TAG_ATTESTATION_ID_IMEI, record->attestation_id_imei->data,
-                              record->attestation_id_imei->length))
+                              record->attestation_id_imei->length)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // MEID
     if (record->attestation_id_meid &&
         !auth_list->push_back(TAG_ATTESTATION_ID_MEID, record->attestation_id_meid->data,
-                              record->attestation_id_meid->length))
+                              record->attestation_id_meid->length)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // Manufacturer name
     if (record->attestation_id_manufacturer &&
         !auth_list->push_back(TAG_ATTESTATION_ID_MANUFACTURER,
                               record->attestation_id_manufacturer->data,
-                              record->attestation_id_manufacturer->length))
+                              record->attestation_id_manufacturer->length)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     // Model name
     if (record->attestation_id_model &&
         !auth_list->push_back(TAG_ATTESTATION_ID_MODEL, record->attestation_id_model->data,
-                              record->attestation_id_model->length))
+                              record->attestation_id_model->length)) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
-    // Trusted confirmation required
-    if (record->trusted_confirmation_required) {
-        if (!auth_list->push_back(TAG_NO_AUTH_REQUIRED)) {
-            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-        }
+    // vendor patch level
+    if (record->vendor_patchlevel &&
+        !auth_list->push_back(TAG_VENDOR_PATCHLEVEL, ASN1_INTEGER_get(record->vendor_patchlevel))) {
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    // boot patch level
+    if (record->boot_patch_level &&
+        !auth_list->push_back(TAG_BOOT_PATCHLEVEL, ASN1_INTEGER_get(record->boot_patch_level))) {
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    // device unique attestation
+    if (record->device_unique_attestation && !auth_list->push_back(TAG_DEVICE_UNIQUE_ATTESTATION)) {
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    // identity credential key
+    if (record->identity_credential_key && !auth_list->push_back(TAG_IDENTITY_CREDENTIAL_KEY)) {
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
     }
 
     return KM_ERROR_OK;
@@ -730,8 +1407,7 @@
     const uint8_t* p = asn1_key_desc;
     UniquePtr<KM_KEY_DESCRIPTION, KM_KEY_DESCRIPTION_Delete> record(
         d2i_KM_KEY_DESCRIPTION(nullptr, &p, asn1_key_desc_len));
-    if (!record.get())
-        return TranslateLastOpenSslError();
+    if (!record.get()) return TranslateLastOpenSslError();
 
     *attestation_version = ASN1_INTEGER_get(record->attestation_version);
     *attestation_security_level = static_cast<keymaster_security_level_t>(
@@ -748,8 +1424,7 @@
     unique_id->data_length = record->unique_id->length;
 
     keymaster_error_t error = extract_auth_list(record->software_enforced, software_enforced);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     return extract_auth_list(record->tee_enforced, tee_enforced);
 }
@@ -783,4 +1458,408 @@
     return KM_ERROR_OK;
 }
 
+// Parse the EAT-encoded attestation record, placing the results in keymaster_version,
+// attestation_challenge, software_enforced, tee_enforced and unique_id.
+keymaster_error_t parse_eat_record(
+    const uint8_t* eat_key_desc, size_t eat_key_desc_len, uint32_t* attestation_version,
+    keymaster_security_level_t* attestation_security_level, uint32_t* keymaster_version,
+    keymaster_security_level_t* keymaster_security_level, keymaster_blob_t* attestation_challenge,
+    AuthorizationSet* software_enforced, AuthorizationSet* tee_enforced,
+    keymaster_blob_t* unique_id, keymaster_blob_t* verified_boot_key,
+    keymaster_verified_boot_t* verified_boot_state, bool* device_locked,
+    std::vector<int64_t>* unexpected_claims) {
+    auto [top_level_item, next_pos, error] = cppbor::parse(eat_key_desc, eat_key_desc_len);
+    ASSERT_OR_RETURN_ERROR(top_level_item, KM_ERROR_INVALID_TAG);
+    const cppbor::Map* eat_map = top_level_item->asMap();
+    ASSERT_OR_RETURN_ERROR(eat_map, KM_ERROR_INVALID_TAG);
+    bool verified_or_self_signed = false;
+
+    for (size_t i = 0; i < eat_map->size(); i++) {
+        auto& [key_item, value_item] = (*eat_map)[i];
+        const cppbor::Int* key = key_item->asInt();
+        ASSERT_OR_RETURN_ERROR(key, (KM_ERROR_INVALID_TAG));
+
+        // The following values will either hold the typed value, or be null (if not the right
+        // type).
+        const cppbor::Int* int_value = value_item->asInt();
+        const cppbor::Bstr* bstr_value = value_item->asBstr();
+        const cppbor::Simple* simple_value = value_item->asSimple();
+        const cppbor::Array* array_value = value_item->asArray();
+        const cppbor::Map* map_value = value_item->asMap();
+
+        keymaster_error_t error;
+        switch ((EatClaim)key->value()) {
+        default:
+            unexpected_claims->push_back(key->value());
+            break;
+        case EatClaim::ATTESTATION_VERSION:
+            ASSERT_OR_RETURN_ERROR(int_value, KM_ERROR_INVALID_TAG);
+            *attestation_version = int_value->value();
+            break;
+        case EatClaim::SECURITY_LEVEL:
+            ASSERT_OR_RETURN_ERROR(int_value, KM_ERROR_INVALID_TAG);
+            switch ((EatSecurityLevel)int_value->value()) {
+            // TODO: Is my assumption correct that the security level of the attestation data should
+            // always be equal to the security level of keymint, as the attestation data always
+            // lives in the top-level module?
+            case EatSecurityLevel::UNRESTRICTED:
+                *keymaster_security_level = *attestation_security_level =
+                    KM_SECURITY_LEVEL_SOFTWARE;
+                break;
+            case EatSecurityLevel::SECURE_RESTRICTED:
+                *keymaster_security_level = *attestation_security_level =
+                    KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
+                break;
+            case EatSecurityLevel::HARDWARE:
+                *keymaster_security_level = *attestation_security_level =
+                    KM_SECURITY_LEVEL_STRONGBOX;
+                break;
+            default:
+                return KM_ERROR_INVALID_TAG;
+            }
+            break;
+        case EatClaim::KEYMASTER_VERSION:
+            ASSERT_OR_RETURN_ERROR(int_value, KM_ERROR_INVALID_TAG);
+            *keymaster_version = int_value->value();
+            break;
+        case EatClaim::SUBMODS:
+            ASSERT_OR_RETURN_ERROR(map_value, KM_ERROR_INVALID_TAG);
+            for (size_t j = 0; j < map_value->size(); j++) {
+                auto& [submod_key, submod_value] = (*map_value)[j];
+                const cppbor::Map* submod_map = submod_value->asMap();
+                ASSERT_OR_RETURN_ERROR(submod_map, KM_ERROR_INVALID_TAG);
+                error = parse_eat_submod(submod_map, software_enforced, tee_enforced);
+                if (error != KM_ERROR_OK) return error;
+            }
+            break;
+        case EatClaim::CTI:
+            error = bstr_to_blob(bstr_value, unique_id);
+            if (error != KM_ERROR_OK) return error;
+            break;
+        case EatClaim::NONCE:
+            error = bstr_to_blob(bstr_value, attestation_challenge);
+            if (error != KM_ERROR_OK) return error;
+            break;
+        case EatClaim::VERIFIED_BOOT_KEY:
+            error = bstr_to_blob(bstr_value, verified_boot_key);
+            if (error != KM_ERROR_OK) return error;
+            break;
+        case EatClaim::VERIFIED_BOOT_HASH:
+            // Not parsing this for now.
+            break;
+        case EatClaim::DEVICE_UNIQUE_ATTESTATION:
+            if (value_item->asSimple() == nullptr || !value_item->asSimple()->asBool()->value()) {
+                return KM_ERROR_INVALID_TAG;
+            }
+            // Not parsing this for now.
+            break;
+        case EatClaim::DEVICE_LOCKED:
+            ASSERT_OR_RETURN_ERROR(simple_value->asBool(), KM_ERROR_INVALID_TAG);
+            *device_locked = simple_value->asBool()->value();
+            break;
+        case EatClaim::BOOT_STATE:
+            ASSERT_OR_RETURN_ERROR(array_value, KM_ERROR_INVALID_TAG);
+            ASSERT_OR_RETURN_ERROR(array_value->size() == 5, KM_ERROR_INVALID_TAG);
+            ASSERT_OR_RETURN_ERROR((*array_value)[4]->asSimple()->asBool()->value() == false,
+                                   KM_ERROR_INVALID_TAG);
+            verified_or_self_signed = (*array_value)[0]->asSimple()->asBool()->value();
+            ASSERT_OR_RETURN_ERROR(verified_or_self_signed ==
+                                       (*array_value)[1]->asSimple()->asBool()->value(),
+                                   KM_ERROR_INVALID_TAG);
+            ASSERT_OR_RETURN_ERROR(verified_or_self_signed ==
+                                       (*array_value)[2]->asSimple()->asBool()->value(),
+                                   KM_ERROR_INVALID_TAG);
+            ASSERT_OR_RETURN_ERROR(verified_or_self_signed ==
+                                       (*array_value)[3]->asSimple()->asBool()->value(),
+                                   KM_ERROR_INVALID_TAG);
+            break;
+        case EatClaim::OFFICIAL_BUILD:
+            *verified_boot_state = KM_VERIFIED_BOOT_VERIFIED;
+            break;
+        }
+    }
+
+    if (*verified_boot_state == KM_VERIFIED_BOOT_VERIFIED) {
+        (void)(verified_boot_state);
+        // TODO: re-enable this
+        // ASSERT_OR_RETURN_ERROR(verified_or_self_signed, KM_ERROR_INVALID_TAG);
+    } else {
+        *verified_boot_state =
+            verified_or_self_signed ? KM_VERIFIED_BOOT_SELF_SIGNED : KM_VERIFIED_BOOT_UNVERIFIED;
+    }
+
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t parse_submod_values(AuthorizationSetBuilder* set_builder,
+                                      int* auth_set_security_level, const cppbor::Map* submod_map) {
+    ASSERT_OR_RETURN_ERROR(set_builder, KM_ERROR_UNEXPECTED_NULL_POINTER);
+    for (size_t i = 0; i < submod_map->size(); i++) {
+        auto& [key_item, value_item] = (*submod_map)[i];
+        const cppbor::Int* key_int = key_item->asInt();
+        ASSERT_OR_RETURN_ERROR(key_int, KM_ERROR_INVALID_TAG);
+        int key = key_int->value();
+        keymaster_error_t error;
+        keymaster_blob_t blob;
+
+        switch ((EatClaim)key) {
+        default:
+            return KM_ERROR_INVALID_TAG;
+        case EatClaim::ALGORITHM:
+            ASSERT_OR_RETURN_ERROR(value_item->asInt(), KM_ERROR_INVALID_TAG);
+            set_builder->Authorization(
+                TAG_ALGORITHM, static_cast<keymaster_algorithm_t>(value_item->asInt()->value()));
+            break;
+        case EatClaim::EC_CURVE:
+            ASSERT_OR_RETURN_ERROR(value_item->asInt(), KM_ERROR_INVALID_TAG);
+            set_builder->Authorization(
+                TAG_EC_CURVE, static_cast<keymaster_ec_curve_t>(value_item->asInt()->value()));
+            break;
+        case EatClaim::USER_AUTH_TYPE:
+            ASSERT_OR_RETURN_ERROR(value_item->asInt(), KM_ERROR_INVALID_TAG);
+            set_builder->Authorization(TAG_USER_AUTH_TYPE, static_cast<hw_authenticator_type_t>(
+                                                               value_item->asInt()->value()));
+            break;
+        case EatClaim::ORIGIN:
+            ASSERT_OR_RETURN_ERROR(value_item->asInt(), KM_ERROR_INVALID_TAG);
+            set_builder->Authorization(
+                TAG_ORIGIN, static_cast<keymaster_key_origin_t>(value_item->asInt()->value()));
+            break;
+        case EatClaim::PURPOSE:
+            for (size_t j = 0; j < value_item->asArray()->size(); j++) {
+                set_builder->Authorization(TAG_PURPOSE,
+                                           static_cast<keymaster_purpose_t>(
+                                               (*value_item->asArray())[j]->asInt()->value()));
+            }
+            break;
+        case EatClaim::PADDING:
+            for (size_t j = 0; j < value_item->asArray()->size(); j++) {
+                set_builder->Authorization(TAG_PADDING,
+                                           static_cast<keymaster_padding_t>(
+                                               (*value_item->asArray())[j]->asInt()->value()));
+            }
+            break;
+        case EatClaim::DIGEST:
+            for (size_t j = 0; j < value_item->asArray()->size(); j++) {
+                set_builder->Authorization(
+                    TAG_DIGEST,
+                    static_cast<keymaster_digest_t>((*value_item->asArray())[j]->asInt()->value()));
+            }
+            break;
+        case EatClaim::BLOCK_MODE:
+            for (size_t j = 0; j < value_item->asArray()->size(); j++) {
+                set_builder->Authorization(TAG_BLOCK_MODE,
+                                           static_cast<keymaster_block_mode_t>(
+                                               (*value_item->asArray())[j]->asInt()->value()));
+            }
+            break;
+        case EatClaim::KEY_SIZE:
+            ASSERT_OR_RETURN_ERROR(value_item->asInt(), KM_ERROR_INVALID_TAG);
+            set_builder->Authorization(TAG_KEY_SIZE, value_item->asInt()->value());
+            break;
+        case EatClaim::AUTH_TIMEOUT:
+            ASSERT_OR_RETURN_ERROR(value_item->asInt(), KM_ERROR_INVALID_TAG);
+            set_builder->Authorization(TAG_AUTH_TIMEOUT, value_item->asInt()->value());
+            break;
+        case EatClaim::OS_VERSION:
+            ASSERT_OR_RETURN_ERROR(value_item->asInt(), KM_ERROR_INVALID_TAG);
+            set_builder->Authorization(TAG_OS_VERSION, value_item->asInt()->value());
+            break;
+        case EatClaim::OS_PATCHLEVEL:
+            ASSERT_OR_RETURN_ERROR(value_item->asInt(), KM_ERROR_INVALID_TAG);
+            set_builder->Authorization(TAG_OS_PATCHLEVEL, value_item->asInt()->value());
+            break;
+        case EatClaim::MIN_MAC_LENGTH:
+            ASSERT_OR_RETURN_ERROR(value_item->asInt(), KM_ERROR_INVALID_TAG);
+            set_builder->Authorization(TAG_MIN_MAC_LENGTH, value_item->asInt()->value());
+            break;
+        case EatClaim::BOOT_PATCHLEVEL:
+            ASSERT_OR_RETURN_ERROR(value_item->asInt(), KM_ERROR_INVALID_TAG);
+            set_builder->Authorization(TAG_BOOT_PATCHLEVEL, value_item->asInt()->value());
+            break;
+        case EatClaim::VENDOR_PATCHLEVEL:
+            ASSERT_OR_RETURN_ERROR(value_item->asInt(), KM_ERROR_INVALID_TAG);
+            set_builder->Authorization(TAG_VENDOR_PATCHLEVEL, value_item->asInt()->value());
+            break;
+        case EatClaim::RSA_PUBLIC_EXPONENT:
+            ASSERT_OR_RETURN_ERROR(value_item->asInt(), KM_ERROR_INVALID_TAG);
+            set_builder->Authorization(TAG_RSA_PUBLIC_EXPONENT, value_item->asInt()->value());
+            break;
+        case EatClaim::ACTIVE_DATETIME:
+            ASSERT_OR_RETURN_ERROR(value_item->asInt(), KM_ERROR_INVALID_TAG);
+            set_builder->Authorization(TAG_ACTIVE_DATETIME, value_item->asInt()->value());
+            break;
+        case EatClaim::ORIGINATION_EXPIRE_DATETIME:
+            ASSERT_OR_RETURN_ERROR(value_item->asInt(), KM_ERROR_INVALID_TAG);
+            set_builder->Authorization(TAG_ORIGINATION_EXPIRE_DATETIME,
+                                       value_item->asInt()->value());
+            break;
+        case EatClaim::USAGE_EXPIRE_DATETIME:
+            ASSERT_OR_RETURN_ERROR(value_item->asInt(), KM_ERROR_INVALID_TAG);
+            set_builder->Authorization(TAG_USAGE_EXPIRE_DATETIME, value_item->asInt()->value());
+            break;
+        case EatClaim::IAT:
+            ASSERT_OR_RETURN_ERROR(value_item->asInt(), KM_ERROR_INVALID_TAG);
+            set_builder->Authorization(TAG_CREATION_DATETIME, value_item->asInt()->value());
+            break;
+        case EatClaim::NO_AUTH_REQUIRED:
+            if (value_item->asSimple() == nullptr || !value_item->asSimple()->asBool()->value()) {
+                return KM_ERROR_INVALID_TAG;
+            }
+            set_builder->Authorization(TAG_NO_AUTH_REQUIRED);
+            break;
+        case EatClaim::ALL_APPLICATIONS:
+            if (value_item->asSimple() == nullptr || !value_item->asSimple()->asBool()->value()) {
+                return KM_ERROR_INVALID_TAG;
+            }
+            set_builder->Authorization(TAG_ALL_APPLICATIONS);
+            break;
+        case EatClaim::ROLLBACK_RESISTANT:
+            if (value_item->asSimple() == nullptr || !value_item->asSimple()->asBool()->value()) {
+                return KM_ERROR_INVALID_TAG;
+            }
+            set_builder->Authorization(TAG_ROLLBACK_RESISTANT);
+            break;
+        case EatClaim::ALLOW_WHILE_ON_BODY:
+            if (value_item->asSimple() == nullptr || !value_item->asSimple()->asBool()->value()) {
+                return KM_ERROR_INVALID_TAG;
+            }
+            set_builder->Authorization(TAG_ALLOW_WHILE_ON_BODY);
+            break;
+        case EatClaim::UNLOCKED_DEVICE_REQUIRED:
+            if (value_item->asSimple() == nullptr || !value_item->asSimple()->asBool()->value()) {
+                return KM_ERROR_INVALID_TAG;
+            }
+            set_builder->Authorization(TAG_UNLOCKED_DEVICE_REQUIRED);
+            break;
+        case EatClaim::CALLER_NONCE:
+            if (value_item->asSimple() == nullptr || !value_item->asSimple()->asBool()->value()) {
+                return KM_ERROR_INVALID_TAG;
+            }
+            set_builder->Authorization(TAG_CALLER_NONCE);
+            break;
+        case EatClaim::TRUSTED_CONFIRMATION_REQUIRED:
+            if (value_item->asSimple() == nullptr || !value_item->asSimple()->asBool()->value()) {
+                return KM_ERROR_INVALID_TAG;
+            }
+            set_builder->Authorization(TAG_TRUSTED_CONFIRMATION_REQUIRED);
+            break;
+        case EatClaim::EARLY_BOOT_ONLY:
+            if (value_item->asSimple() == nullptr || !value_item->asSimple()->asBool()->value()) {
+                return KM_ERROR_INVALID_TAG;
+            }
+            set_builder->Authorization(TAG_EARLY_BOOT_ONLY);
+            break;
+        case EatClaim::IDENTITY_CREDENTIAL_KEY:
+            if (value_item->asSimple() == nullptr || !value_item->asSimple()->asBool()->value()) {
+                return KM_ERROR_INVALID_TAG;
+            }
+            set_builder->Authorization(TAG_IDENTITY_CREDENTIAL_KEY);
+            break;
+        case EatClaim::STORAGE_KEY:
+            if (value_item->asSimple() == nullptr || !value_item->asSimple()->asBool()->value()) {
+                return KM_ERROR_INVALID_TAG;
+            }
+            set_builder->Authorization(TAG_STORAGE_KEY);
+            break;
+        case EatClaim::TRUSTED_USER_PRESENCE_REQUIRED:
+            if (value_item->asSimple() == nullptr || !value_item->asSimple()->asBool()->value()) {
+                return KM_ERROR_INVALID_TAG;
+            }
+            set_builder->Authorization(TAG_TRUSTED_USER_PRESENCE_REQUIRED);
+            break;
+        case EatClaim::DEVICE_UNIQUE_ATTESTATION:
+            if (value_item->asSimple() == nullptr || !value_item->asSimple()->asBool()->value()) {
+                return KM_ERROR_INVALID_TAG;
+            }
+            set_builder->Authorization(TAG_DEVICE_UNIQUE_ATTESTATION);
+            break;
+        case EatClaim::APPLICATION_ID:
+            error = bstr_to_blob(value_item->asBstr(), &blob);
+            if (error != KM_ERROR_OK) return error;
+            set_builder->Authorization(TAG_APPLICATION_ID, blob);
+            break;
+        case EatClaim::ATTESTATION_APPLICATION_ID:
+            error = bstr_to_blob(value_item->asBstr(), &blob);
+            if (error != KM_ERROR_OK) return error;
+            set_builder->Authorization(TAG_ATTESTATION_APPLICATION_ID, blob);
+            break;
+        case EatClaim::ATTESTATION_ID_BRAND:
+            error = bstr_to_blob(value_item->asBstr(), &blob);
+            if (error != KM_ERROR_OK) return error;
+            set_builder->Authorization(TAG_ATTESTATION_ID_BRAND, blob);
+            break;
+        case EatClaim::ATTESTATION_ID_DEVICE:
+            error = bstr_to_blob(value_item->asBstr(), &blob);
+            if (error != KM_ERROR_OK) return error;
+            set_builder->Authorization(TAG_ATTESTATION_ID_DEVICE, blob);
+            break;
+        case EatClaim::ATTESTATION_ID_PRODUCT:
+            error = bstr_to_blob(value_item->asBstr(), &blob);
+            if (error != KM_ERROR_OK) return error;
+            set_builder->Authorization(TAG_ATTESTATION_ID_PRODUCT, blob);
+            break;
+        case EatClaim::ATTESTATION_ID_SERIAL:
+            error = bstr_to_blob(value_item->asBstr(), &blob);
+            if (error != KM_ERROR_OK) return error;
+            set_builder->Authorization(TAG_ATTESTATION_ID_SERIAL, blob);
+            break;
+        case EatClaim::UEID:
+            error = ueid_to_imei_blob(value_item->asBstr(), &blob);
+            if (error != KM_ERROR_OK) return error;
+            set_builder->Authorization(TAG_ATTESTATION_ID_IMEI, blob);
+            break;
+        case EatClaim::ATTESTATION_ID_MEID:
+            error = bstr_to_blob(value_item->asBstr(), &blob);
+            if (error != KM_ERROR_OK) return error;
+            set_builder->Authorization(TAG_ATTESTATION_ID_MEID, blob);
+            break;
+        case EatClaim::ATTESTATION_ID_MANUFACTURER:
+            error = bstr_to_blob(value_item->asBstr(), &blob);
+            if (error != KM_ERROR_OK) return error;
+            set_builder->Authorization(TAG_ATTESTATION_ID_MANUFACTURER, blob);
+            break;
+        case EatClaim::ATTESTATION_ID_MODEL:
+            error = bstr_to_blob(value_item->asBstr(), &blob);
+            if (error != KM_ERROR_OK) return error;
+            set_builder->Authorization(TAG_ATTESTATION_ID_MODEL, blob);
+            break;
+        case EatClaim::CONFIRMATION_TOKEN:
+            error = bstr_to_blob(value_item->asBstr(), &blob);
+            if (error != KM_ERROR_OK) return error;
+            set_builder->Authorization(TAG_CONFIRMATION_TOKEN, blob);
+            break;
+        case EatClaim::SECURITY_LEVEL:
+            ASSERT_OR_RETURN_ERROR(value_item->asInt(), KM_ERROR_INVALID_TAG);
+            *auth_set_security_level = value_item->asInt()->value();
+        }
+    }
+
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t parse_eat_submod(const cppbor::Map* submod_values,
+                                   AuthorizationSet* software_enforced,
+                                   AuthorizationSet* tee_enforced) {
+    AuthorizationSetBuilder auth_set_builder;
+    int auth_set_security_level = 0;
+    keymaster_error_t error =
+        parse_submod_values(&auth_set_builder, &auth_set_security_level, submod_values);
+    if (error) return error;
+    switch ((EatSecurityLevel)auth_set_security_level) {
+    case EatSecurityLevel::HARDWARE:
+        // Hardware attestation should never occur in a submod of another EAT.
+        [[fallthrough]];
+    default:
+        return KM_ERROR_INVALID_TAG;
+    case EatSecurityLevel::UNRESTRICTED:
+        *software_enforced = AuthorizationSet(auth_set_builder);
+        break;
+    case EatSecurityLevel::SECURE_RESTRICTED:
+        *tee_enforced = AuthorizationSet(auth_set_builder);
+        break;
+    }
+
+    return KM_ERROR_OK;
+}
 }  // namespace keymaster
diff --git a/km_openssl/attestation_utils.cpp b/km_openssl/attestation_utils.cpp
index e6754a2..9a6c7f3 100644
--- a/km_openssl/attestation_utils.cpp
+++ b/km_openssl/attestation_utils.cpp
@@ -15,408 +15,318 @@
 ** limitations under the License.
 */
 
-#include <keymaster/km_openssl/attestation_utils.h>
+#include <openssl/evp.h>
+#include <openssl/x509v3.h>
 
 #include <hardware/keymaster_defs.h>
 
 #include <keymaster/authorization_set.h>
-#include <keymaster/attestation_record.h>
 #include <keymaster/km_openssl/asymmetric_key.h>
-#include <keymaster/km_openssl/openssl_utils.h>
+#include <keymaster/km_openssl/attestation_record.h>
+#include <keymaster/km_openssl/attestation_utils.h>
+#include <keymaster/km_openssl/certificate_utils.h>
 #include <keymaster/km_openssl/openssl_err.h>
-
-#include <openssl/x509v3.h>
-#include <openssl/evp.h>
-
+#include <keymaster/km_openssl/openssl_utils.h>
 
 namespace keymaster {
 
 namespace {
 
-constexpr int kDigitalSignatureKeyUsageBit = 0;
-constexpr int kKeyEnciphermentKeyUsageBit = 2;
-constexpr int kDataEnciphermentKeyUsageBit = 3;
-constexpr int kMaxKeyUsageBit = 8;
+CertificateChain make_cert_chain(X509* certificate, CertificateChain chain,
+                                 keymaster_error_t* error) {
+    keymaster_blob_t blob{};
+    *error = encode_certificate(certificate, &blob);
+    if (*error != KM_ERROR_OK) return {};
 
-template <typename T> T && min(T && a, T && b) {
-    return (a < b) ? forward<T>(a) : forward<T>(b);
-}
-
-struct emptyCert {};
-
-__attribute__((__unused__))
-inline keymaster_blob_t certBlobifier(const emptyCert&, bool*){ return {}; }
-template <size_t N>
-inline keymaster_blob_t certBlobifier(const uint8_t (&cert)[N], bool* fail){
-    keymaster_blob_t result = { dup_array(cert), N };
-    if (!result.data) {
-        *fail = true;
+    if (!chain.push_front(blob)) {
+        *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
         return {};
     }
-    return result;
+    return chain;
 }
-inline keymaster_blob_t certBlobifier(const keymaster_blob_t& blob, bool* fail){
-    if (blob.data == nullptr || blob.data_length == 0) return {};
-    keymaster_blob_t result = { dup_array(blob.data, blob.data_length), blob.data_length };
-    if (!result.data) {
-        *fail = true;
-        return {};
-    }
-    return result;
-}
-inline keymaster_blob_t certBlobifier(keymaster_blob_t&& blob, bool*){
-    if (blob.data == nullptr || blob.data_length == 0) return {};
-    keymaster_blob_t result = blob;
-    blob = {};
-    return result;
-}
-inline keymaster_blob_t certBlobifier(X509* certificate, bool* fail){
-    int len = i2d_X509(certificate, nullptr);
-    if (len < 0) {
-        *fail = true;
-        return {};
-    }
-
-    uint8_t* data = new(std::nothrow) uint8_t[len];
-    if (!data) {
-        *fail = true;
-        return {};
-    }
-    uint8_t* p = data;
-
-    i2d_X509(certificate, &p);
-
-    return { data, (size_t)len };
-}
-
-inline bool certCopier(keymaster_blob_t** out, const keymaster_cert_chain_t& chain,
-                              bool* fail) {
-    for (size_t i = 0; i < chain.entry_count; ++i) {
-        *(*out)++ = certBlobifier(chain.entries[i], fail);
-    }
-    return *fail;
-}
-
-__attribute__((__unused__))
-inline bool certCopier(keymaster_blob_t** out, keymaster_cert_chain_t&& chain, bool* fail) {
-    for (size_t i = 0; i < chain.entry_count; ++i) {
-        *(*out)++ = certBlobifier(move(chain.entries[i]), fail);
-    }
-    delete[] chain.entries;
-    chain.entries = nullptr;
-    chain.entry_count = 0;
-    return *fail;
-}
-template <typename CERT>
-inline bool certCopier(keymaster_blob_t** out, CERT&& cert, bool* fail) {
-    *(*out)++ = certBlobifier(forward<CERT>(cert), fail);
-    return *fail;
-}
-
-inline bool certCopyHelper(keymaster_blob_t**, bool* fail) {
-    return *fail;
-}
-
-template <typename CERT, typename... CERTS>
-inline bool certCopyHelper(keymaster_blob_t** out, bool* fail, CERT&& cert, CERTS&&... certs) {
-    certCopier(out, forward<CERT>(cert), fail);
-    return certCopyHelper(out, fail, forward<CERTS>(certs)...);
-}
-
-
-
-template <typename T>
-inline size_t noOfCert(T &&) { return 1; }
-inline size_t noOfCert(const keymaster_cert_chain_t& cert_chain) { return cert_chain.entry_count; }
-
-inline size_t certCount() { return 0; }
-template <typename CERT, typename... CERTS>
-inline size_t certCount(CERT&& cert, CERTS&&... certs) {
-    return noOfCert(forward<CERT>(cert)) + certCount(forward<CERTS>(certs)...);
-}
-
-/*
- * makeCertChain creates a new keymaster_cert_chain_t from all the certs that get thrown at it
- * in the given order. A cert may be a X509*, uint8_t[], a keymaster_blob_t, an instance of
- * emptyCert, or another keymater_cert_chain_t in which case the certs of the chain are included
- * in the new chain. emptyCert is a placeholder which results in an empty slot at the given
- * position in the newly created certificate chain. E.g., makeCertChain(emptyCert(), someCertChain)
- * allocates enough slots to accommodate all certificates of someCertChain plus one empty slot and
- * copies in someCertChain starting at index 1 so that the slot with index 0 can be used for a new
- * leaf entry.
- *
- * makeCertChain respects move semantics. E.g., makeCertChain(emptyCert(), std::move(someCertChain))
- * will take possession of secondary resources for the certificate blobs so that someCertChain is
- * empty after the call. Also, because no allocation happens this cannot fail. Note, however, that
- * if another cert is passed to makeCertChain, that needs to be copied and thus requires
- * allocation, and this allocation fails, all resources - allocated or moved - will be reaped.
- */
-template <typename... CERTS>
-CertChainPtr makeCertChain(CERTS&&... certs) {
-    CertChainPtr result(new (std::nothrow) keymaster_cert_chain_t);
-    if (!result.get()) return {};
-    result->entries = new (std::nothrow) keymaster_blob_t[certCount(forward<CERTS>(certs)...)];
-    if (!result->entries) return {};
-    result->entry_count = certCount(forward<CERTS>(certs)...);
-    bool allocation_failed = false;
-    keymaster_blob_t* entries = result->entries;
-    certCopyHelper(&entries, &allocation_failed, forward<CERTS>(certs)...);
-    if (allocation_failed) return {};
-    return result;
-}
-
 
 keymaster_error_t build_attestation_extension(const AuthorizationSet& attest_params,
-                                                     const AuthorizationSet& tee_enforced,
-                                                     const AuthorizationSet& sw_enforced,
-                                                     const AttestationRecordContext& context,
-                                                     X509_EXTENSION_Ptr* extension) {
+                                              const AuthorizationSet& tee_enforced,
+                                              const AuthorizationSet& sw_enforced,
+                                              const AttestationContext& context,
+                                              X509_EXTENSION_Ptr* extension) {
     ASN1_OBJECT_Ptr oid(
-        OBJ_txt2obj(kAttestionRecordOid, 1 /* accept numerical dotted string form only */));
-    if (!oid.get())
-        return TranslateLastOpenSslError();
+        OBJ_txt2obj(kAsn1TokenOid, 1 /* accept numerical dotted string form only */));
+    if (!oid.get()) return TranslateLastOpenSslError();
 
     UniquePtr<uint8_t[]> attest_bytes;
     size_t attest_bytes_len;
     keymaster_error_t error = build_attestation_record(attest_params, sw_enforced, tee_enforced,
                                                        context, &attest_bytes, &attest_bytes_len);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     ASN1_OCTET_STRING_Ptr attest_str(ASN1_OCTET_STRING_new());
     if (!attest_str.get() ||
-        !ASN1_OCTET_STRING_set(attest_str.get(), attest_bytes.get(), attest_bytes_len))
+        !ASN1_OCTET_STRING_set(attest_str.get(), attest_bytes.get(), attest_bytes_len)) {
         return TranslateLastOpenSslError();
+    }
 
     extension->reset(
         X509_EXTENSION_create_by_OBJ(nullptr, oid.get(), 0 /* not critical */, attest_str.get()));
-    if (!extension->get())
-        return TranslateLastOpenSslError();
-
-    return KM_ERROR_OK;
-}
-
-keymaster_error_t add_key_usage_extension(const AuthorizationSet& tee_enforced,
-                                                 const AuthorizationSet& sw_enforced,
-                                                 X509* certificate) {
-    // Build BIT_STRING with correct contents.
-    ASN1_BIT_STRING_Ptr key_usage(ASN1_BIT_STRING_new());
-    if (!key_usage) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
-    for (size_t i = 0; i <= kMaxKeyUsageBit; ++i) {
-        if (!ASN1_BIT_STRING_set_bit(key_usage.get(), i, 0)) {
-            return TranslateLastOpenSslError();
-        }
-    }
-
-    if (tee_enforced.Contains(TAG_PURPOSE, KM_PURPOSE_SIGN) ||
-        tee_enforced.Contains(TAG_PURPOSE, KM_PURPOSE_VERIFY) ||
-        sw_enforced.Contains(TAG_PURPOSE, KM_PURPOSE_SIGN) ||
-        sw_enforced.Contains(TAG_PURPOSE, KM_PURPOSE_VERIFY)) {
-        if (!ASN1_BIT_STRING_set_bit(key_usage.get(), kDigitalSignatureKeyUsageBit, 1)) {
-            return TranslateLastOpenSslError();
-        }
-    }
-
-    if (tee_enforced.Contains(TAG_PURPOSE, KM_PURPOSE_ENCRYPT) ||
-        tee_enforced.Contains(TAG_PURPOSE, KM_PURPOSE_DECRYPT) ||
-        sw_enforced.Contains(TAG_PURPOSE, KM_PURPOSE_ENCRYPT) ||
-        sw_enforced.Contains(TAG_PURPOSE, KM_PURPOSE_DECRYPT)) {
-        if (!ASN1_BIT_STRING_set_bit(key_usage.get(), kKeyEnciphermentKeyUsageBit, 1) ||
-            !ASN1_BIT_STRING_set_bit(key_usage.get(), kDataEnciphermentKeyUsageBit, 1)) {
-            return TranslateLastOpenSslError();
-        }
-    }
-
-    // Convert to octets
-    int len = i2d_ASN1_BIT_STRING(key_usage.get(), nullptr);
-    if (len < 0) {
-        return TranslateLastOpenSslError();
-    }
-    UniquePtr<uint8_t[]> asn1_key_usage(new(std::nothrow) uint8_t[len]);
-    if (!asn1_key_usage.get()) {
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-    }
-    uint8_t* p = asn1_key_usage.get();
-    len = i2d_ASN1_BIT_STRING(key_usage.get(), &p);
-    if (len < 0) {
-        return TranslateLastOpenSslError();
-    }
-
-    // Build OCTET_STRING
-    ASN1_OCTET_STRING_Ptr key_usage_str(ASN1_OCTET_STRING_new());
-    if (!key_usage_str.get() ||
-        !ASN1_OCTET_STRING_set(key_usage_str.get(), asn1_key_usage.get(), len)) {
-        return TranslateLastOpenSslError();
-    }
-
-    X509_EXTENSION_Ptr key_usage_extension(X509_EXTENSION_create_by_NID(nullptr,        //
-                                                                        NID_key_usage,  //
-                                                                        false /* critical */,
-                                                                        key_usage_str.get()));
-    if (!key_usage_extension.get()) {
-        return TranslateLastOpenSslError();
-    }
-
-    if (!X509_add_ext(certificate, key_usage_extension.get() /* Don't release; copied */,
-                      -1 /* insert at end */)) {
+    if (!extension->get()) {
         return TranslateLastOpenSslError();
     }
 
     return KM_ERROR_OK;
 }
 
-bool add_public_key(EVP_PKEY* key, X509* certificate, keymaster_error_t* error) {
-    if (!X509_set_pubkey(certificate, key)) {
-        *error = TranslateLastOpenSslError();
-        return false;
-    }
-    return true;
-}
-
-bool add_attestation_extension(const AuthorizationSet& attest_params,
+keymaster_error_t build_eat_extension(const AuthorizationSet& attest_params,
                                       const AuthorizationSet& tee_enforced,
                                       const AuthorizationSet& sw_enforced,
-                                      const AttestationRecordContext& context,
-                                      X509* certificate,
-                                      keymaster_error_t* error) {
+                                      const AttestationContext& context,  //
+                                      X509_EXTENSION_Ptr* extension) {
+    ASN1_OBJECT_Ptr oid(
+        OBJ_txt2obj(kEatTokenOid, 1 /* accept numerical dotted string form only */));
+    if (!oid.get()) {
+        return TranslateLastOpenSslError();
+    }
+
+    std::vector<uint8_t> eat_bytes;
+    keymaster_error_t error =
+        build_eat_record(attest_params, sw_enforced, tee_enforced, context, &eat_bytes);
+    if (error != KM_ERROR_OK) return error;
+
+    ASN1_OCTET_STRING_Ptr eat_str(ASN1_OCTET_STRING_new());
+    if (!eat_str.get() ||
+        !ASN1_OCTET_STRING_set(eat_str.get(), eat_bytes.data(), eat_bytes.size())) {
+        return TranslateLastOpenSslError();
+    }
+
+    extension->reset(
+        X509_EXTENSION_create_by_OBJ(nullptr, oid.get(), 0 /* not critical */, eat_str.get()));
+    if (!extension->get()) {
+        return TranslateLastOpenSslError();
+    }
+
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t add_attestation_extension(const AuthorizationSet& attest_params,
+                                            const AuthorizationSet& tee_enforced,
+                                            const AuthorizationSet& sw_enforced,
+                                            const AttestationContext& context,  //
+                                            X509* certificate) {
     X509_EXTENSION_Ptr attest_extension;
-    *error = build_attestation_extension(attest_params, tee_enforced, sw_enforced, context,
-                                         &attest_extension);
-    if (*error != KM_ERROR_OK)
-        return false;
+    if (context.GetKmVersion() <= KmVersion::KEYMINT_1) {
+        if (auto error = build_attestation_extension(attest_params, tee_enforced, sw_enforced,
+                                                     context, &attest_extension)) {
+            return error;
+        }
+    } else {
+        if (auto error = build_eat_extension(attest_params, tee_enforced, sw_enforced, context,
+                                             &attest_extension)) {
+            return error;
+        }
+    }
 
     if (!X509_add_ext(certificate, attest_extension.get() /* Don't release; copied */,
                       -1 /* insert at end */)) {
-        *error = TranslateLastOpenSslError();
-        return false;
-    }
-
-    return true;
-}
-
-} // anonymous namespace
-
-keymaster_error_t generate_attestation(const AsymmetricKey& key,
-        const AuthorizationSet& attest_params, const keymaster_cert_chain_t& attestation_chain,
-        const keymaster_key_blob_t& attestation_signing_key,
-        const AttestationRecordContext& context, CertChainPtr* cert_chain_out) {
-
-    if (!cert_chain_out)
-        return KM_ERROR_UNEXPECTED_NULL_POINTER;
-
-    keymaster_algorithm_t sign_algorithm;
-    if ((!key.sw_enforced().GetTagValue(TAG_ALGORITHM, &sign_algorithm) &&
-         !key.hw_enforced().GetTagValue(TAG_ALGORITHM, &sign_algorithm)))
-        return KM_ERROR_UNKNOWN_ERROR;
-
-    EVP_PKEY_Ptr pkey(EVP_PKEY_new());
-    if (!key.InternalToEvp(pkey.get()))
-        return TranslateLastOpenSslError();
-
-    X509_Ptr certificate(X509_new());
-    if (!certificate.get())
-        return TranslateLastOpenSslError();
-
-    if (!X509_set_version(certificate.get(), 2 /* version 3, but zero-based */))
-        return TranslateLastOpenSslError();
-
-    ASN1_INTEGER_Ptr serialNumber(ASN1_INTEGER_new());
-    if (!serialNumber.get() || !ASN1_INTEGER_set(serialNumber.get(), 1) ||
-        !X509_set_serialNumber(certificate.get(), serialNumber.get() /* Don't release; copied */))
-        return TranslateLastOpenSslError();
-
-    X509_NAME_Ptr subjectName(X509_NAME_new());
-    if (!subjectName.get() ||
-        !X509_NAME_add_entry_by_txt(subjectName.get(), "CN", MBSTRING_ASC,
-                                    reinterpret_cast<const uint8_t*>("Android Keystore Key"),
-                                    -1 /* len */, -1 /* loc */, 0 /* set */) ||
-        !X509_set_subject_name(certificate.get(), subjectName.get() /* Don't release; copied */))
-        return TranslateLastOpenSslError();
-
-    ASN1_TIME_Ptr notBefore(ASN1_TIME_new());
-    uint64_t activeDateTime = 0;
-    key.authorizations().GetTagValue(TAG_ACTIVE_DATETIME, &activeDateTime);
-    if (!notBefore.get() || !ASN1_TIME_set(notBefore.get(), activeDateTime / 1000) ||
-        !X509_set_notBefore(certificate.get(), notBefore.get() /* Don't release; copied */))
-        return TranslateLastOpenSslError();
-
-    ASN1_TIME_Ptr notAfter(ASN1_TIME_new());
-    uint64_t usageExpireDateTime = UINT64_MAX;
-    key.authorizations().GetTagValue(TAG_USAGE_EXPIRE_DATETIME, &usageExpireDateTime);
-    // TODO(swillden): When trusty can use the C++ standard library change the calculation of
-    // notAfterTime to use std::numeric_limits<time_t>::max(), rather than assuming that time_t is
-    // 32 bits.
-    time_t notAfterTime =
-        (time_t)min(static_cast<uint64_t>(UINT32_MAX), usageExpireDateTime / 1000);
-    if (!notAfter.get() || !ASN1_TIME_set(notAfter.get(), notAfterTime) ||
-        !X509_set_notAfter(certificate.get(), notAfter.get() /* Don't release; copied */))
-        return TranslateLastOpenSslError();
-
-    keymaster_error_t error = add_key_usage_extension(key.hw_enforced(), key.sw_enforced(), certificate.get());
-    if (error != KM_ERROR_OK) {
-        return error;
-    }
-
-    // We have established above that it is one of the two. So if it is not RSA its EC.
-    int evp_key_type = (sign_algorithm == KM_ALGORITHM_RSA) ? EVP_PKEY_RSA : EVP_PKEY_EC;
-
-    const uint8_t* key_material = attestation_signing_key.key_material;
-    EVP_PKEY_Ptr sign_key(
-            d2i_PrivateKey(evp_key_type, nullptr,
-                    const_cast<const uint8_t**>(&key_material),
-                    attestation_signing_key.key_material_size));
-    if (!sign_key.get()) return TranslateLastOpenSslError();
-
-    if (!add_public_key(pkey.get(), certificate.get(), &error) ||
-        !add_attestation_extension(attest_params, key.hw_enforced(), key.sw_enforced(),
-                                   context, certificate.get(), &error))
-        return error;
-
-    if (attestation_chain.entry_count < 1) {
-        // the attestation chain must have at least the cert for the key that signs the new cert.
-        return KM_ERROR_UNKNOWN_ERROR;
-    }
-
-    const uint8_t* p = attestation_chain.entries[0].data;
-    X509_Ptr signing_cert(d2i_X509(nullptr, &p, attestation_chain.entries[0].data_length));
-    if (!signing_cert.get()) {
         return TranslateLastOpenSslError();
     }
 
-    // Set issuer to subject of batch certificate.
-    X509_NAME* issuerSubject = X509_get_subject_name(signing_cert.get());
-    if (!issuerSubject) {
-        return KM_ERROR_UNKNOWN_ERROR;
-    }
-    if (!X509_set_issuer_name(certificate.get(), issuerSubject)) {
-        return TranslateLastOpenSslError();
-    }
-
-    UniquePtr<X509V3_CTX> x509v3_ctx(new(std::nothrow) X509V3_CTX);
-    if (!x509v3_ctx.get())
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-    *x509v3_ctx = {};
-    X509V3_set_ctx(x509v3_ctx.get(), signing_cert.get(), certificate.get(), nullptr /* req */,
-                   nullptr /* crl */, 0 /* flags */);
-
-    X509_EXTENSION_Ptr auth_key_id(X509V3_EXT_nconf_nid(nullptr /* conf */, x509v3_ctx.get(),
-                                                        NID_authority_key_identifier,
-                                                        const_cast<char*>("keyid:always")));
-    if (!auth_key_id.get() ||
-        !X509_add_ext(certificate.get(), auth_key_id.get() /* Don't release; copied */,
-                      -1 /* insert at end */)) {
-        return TranslateLastOpenSslError();
-    }
-
-    if (!X509_sign(certificate.get(), sign_key.get(), EVP_sha256()))
-        return TranslateLastOpenSslError();
-
-    *cert_chain_out = makeCertChain(certificate.get(), attestation_chain);
-    if (!cert_chain_out->get())
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
     return KM_ERROR_OK;
 }
 
+keymaster_error_t make_attestation_cert(const EVP_PKEY* evp_pkey, const X509_NAME* issuer,
+                                        const CertificateCallerParams& cert_params,
+                                        const AuthorizationSet& attest_params,
+                                        const AuthorizationSet& tee_enforced,
+                                        const AuthorizationSet& sw_enforced,
+                                        const AttestationContext& context, X509_Ptr* cert_out) {
 
-} // namespace keymaster
+    // First make the basic certificate with usage extension.
+    X509_Ptr certificate;
+    if (auto error = make_cert(evp_pkey, issuer, cert_params, &certificate)) {
+        return error;
+    }
+
+    // Add attestation extension.
+    if (auto error = add_attestation_extension(attest_params, tee_enforced, sw_enforced, context,
+                                               certificate.get())) {
+        return error;
+    }
+
+    *cert_out = move(certificate);
+    return KM_ERROR_OK;
+}
+
+X509_NAME_Ptr get_issuer_subject(const AttestKeyInfo& attest_key, keymaster_error_t* error) {
+    // Use subject from attest_key.
+    const uint8_t* p = attest_key.issuer_subject->data;
+    if (!p || !attest_key.issuer_subject->data_length) {
+        *error = KM_ERROR_MISSING_ISSUER_SUBJECT;
+        return {};
+    }
+    X509_NAME_Ptr retval(d2i_X509_NAME(nullptr /* Allocate X509_NAME */, &p,
+                                       attest_key.issuer_subject->data_length));
+    if (!retval) *error = KM_ERROR_INVALID_ISSUER_SUBJECT;
+    return retval;
+}
+
+X509_NAME_Ptr get_issuer_subject(const keymaster_blob_t& signing_cert_der,
+                                 keymaster_error_t* error) {
+    const uint8_t* p = signing_cert_der.data;
+    if (!p) {
+        *error = KM_ERROR_UNEXPECTED_NULL_POINTER;
+        return {};
+    }
+    X509_Ptr signing_cert(d2i_X509(nullptr /* Allocate X509 */, &p, signing_cert_der.data_length));
+    if (!signing_cert) {
+        *error = TranslateLastOpenSslError();
+        return {};
+    }
+
+    X509_NAME* issuer_subject = X509_get_subject_name(signing_cert.get());
+    if (!issuer_subject) {
+        *error = TranslateLastOpenSslError();
+        return {};
+    }
+
+    X509_NAME_Ptr retval(X509_NAME_dup(issuer_subject));
+    if (!retval) *error = TranslateLastOpenSslError();
+
+    return retval;
+}
+
+// Return subject from attest_key, if non-null, otherwise extract from cert_chain.
+X509_NAME_Ptr get_issuer_subject(const AttestKeyInfo& attest_key,
+                                 const CertificateChain& cert_chain, keymaster_error_t* error) {
+    if (attest_key) {
+        return get_issuer_subject(attest_key, error);
+    }
+
+    // Need to extract issuer from cert chain.  First cert in the chain is the signing key cert.
+    if (cert_chain.entry_count >= 1) return get_issuer_subject(cert_chain.entries[0], error);
+
+    *error = KM_ERROR_UNKNOWN_ERROR;
+    return {};
+}
+
+keymaster_error_t check_attest_key_auths(const Key& key) {
+    auto auths = key.authorizations();
+
+    if (!auths.Contains(TAG_ALGORITHM, KM_ALGORITHM_RSA) &&
+        !auths.Contains(TAG_ALGORITHM, KM_ALGORITHM_EC)) {
+        return KM_ERROR_INCOMPATIBLE_ALGORITHM;
+    }
+    if (!auths.Contains(TAG_PURPOSE, KM_PURPOSE_ATTEST_KEY)) {
+        return KM_ERROR_INCOMPATIBLE_PURPOSE;
+    }
+    return KM_ERROR_OK;
+}
+
+EVP_PKEY_Ptr get_attestation_key(keymaster_algorithm_t algorithm, const AttestationContext& context,
+                                 keymaster_error_t* error) {
+    KeymasterKeyBlob signing_key_blob = context.GetAttestationKey(algorithm, error);
+    if (*error != KM_ERROR_OK) return {};
+
+    const uint8_t* p = signing_key_blob.key_material;
+    EVP_PKEY_Ptr retval(
+        d2i_AutoPrivateKey(nullptr /* Allocate key */, &p, signing_key_blob.key_material_size));
+    if (!retval) *error = TranslateLastOpenSslError();
+    return retval;
+}
+
+}  // namespace
+
+AttestKeyInfo::AttestKeyInfo(const UniquePtr<Key>& key, const KeymasterBlob* issuer_subject_,
+                             keymaster_error_t* error)
+    : issuer_subject(issuer_subject_) {
+    if (!error) return;
+
+    if (!key) {
+        // No key... so this is just an empty AttestKeyInfo.
+        issuer_subject = nullptr;
+        return;
+    }
+
+    if (!issuer_subject) {
+        *error = KM_ERROR_UNEXPECTED_NULL_POINTER;
+        return;
+    }
+
+    *error = check_attest_key_auths(*key);
+    if (*error != KM_ERROR_OK) return;
+
+    signing_key.reset(EVP_PKEY_new());
+    if (!signing_key) {
+        *error = TranslateLastOpenSslError();
+        return;
+    }
+
+    if (!static_cast<const AsymmetricKey&>(*key).InternalToEvp(signing_key.get())) {
+        *error = KM_ERROR_UNKNOWN_ERROR;
+    }
+}
+
+CertificateChain generate_attestation(const AsymmetricKey& key,
+                                      const AuthorizationSet& attest_params,
+                                      AttestKeyInfo attest_key,
+                                      const AttestationContext& context,  //
+                                      keymaster_error_t* error) {
+    EVP_PKEY_Ptr pkey(EVP_PKEY_new());
+    if (!key.InternalToEvp(pkey.get())) {
+        *error = TranslateLastOpenSslError();
+        return {};
+    }
+
+    return generate_attestation(pkey.get(), key.sw_enforced(), key.hw_enforced(), attest_params,
+                                move(attest_key), context, error);
+}
+
+CertificateChain generate_attestation(const EVP_PKEY* evp_key,              //
+                                      const AuthorizationSet& sw_enforced,  //
+                                      const AuthorizationSet& tee_enforced,
+                                      const AuthorizationSet& attest_params,
+                                      AttestKeyInfo attest_key,
+                                      const AttestationContext& context,  //
+                                      keymaster_error_t* error) {
+    if (!error) return {};
+
+    CertificateCallerParams cert_params{};
+    *error = get_certificate_params(attest_params, &cert_params, context.GetKmVersion());
+    if (*error != KM_ERROR_OK) return {};
+
+    AuthProxy proxy(tee_enforced, sw_enforced);
+    cert_params.is_signing_key = proxy.Contains(TAG_PURPOSE, KM_PURPOSE_SIGN);
+    cert_params.is_encryption_key = proxy.Contains(TAG_PURPOSE, KM_PURPOSE_DECRYPT);
+    cert_params.is_agreement_key = proxy.Contains(TAG_PURPOSE, KM_PURPOSE_AGREE_KEY);
+
+    keymaster_algorithm_t algorithm;
+    if (!proxy.GetTagValue(TAG_ALGORITHM, &algorithm)) {
+        *error = KM_ERROR_UNSUPPORTED_PURPOSE;
+        return {};
+    }
+
+    CertificateChain cert_chain =
+        attest_key ? CertificateChain() : context.GetAttestationChain(algorithm, error);
+    if (*error != KM_ERROR_OK) return {};
+
+    X509_NAME_Ptr issuer_subject = get_issuer_subject(attest_key, cert_chain, error);
+    if (*error != KM_ERROR_OK) return {};
+
+    X509_Ptr certificate;
+    *error = make_attestation_cert(evp_key, issuer_subject.get(), cert_params, attest_params,
+                                   tee_enforced, sw_enforced, context, &certificate);
+    if (*error != KM_ERROR_OK) return {};
+
+    EVP_PKEY_Ptr signing_key;
+    const EVP_PKEY* signing_key_ptr = attest_key.signing_key.get();
+    if (!signing_key_ptr) {
+        signing_key = get_attestation_key(algorithm, context, error);
+        if (*error != KM_ERROR_OK) return {};
+        signing_key_ptr = signing_key.get();
+    }
+
+    *error = sign_cert(certificate.get(), signing_key_ptr);
+    if (*error != KM_ERROR_OK) return {};
+
+    return make_cert_chain(certificate.get(), move(cert_chain), error);
+}
+
+}  // namespace keymaster
diff --git a/km_openssl/block_cipher_operation.cpp b/km_openssl/block_cipher_operation.cpp
index 4a34b35..a381e75 100644
--- a/km_openssl/block_cipher_operation.cpp
+++ b/km_openssl/block_cipher_operation.cpp
@@ -18,8 +18,6 @@
 
 #include <stdio.h>
 
-#include <keymaster/new.h>
-
 #include <keymaster/UniquePtr.h>
 
 #include <openssl/aes.h>
@@ -162,7 +160,9 @@
                              (size_t)sizeof(operation_handle_));
     if (rc != KM_ERROR_OK) return rc;
 
-    return InitializeCipher(move(key_));
+    auto retval = InitializeCipher(key_);
+    key_ = {};
+    return retval;
 }
 
 keymaster_error_t BlockCipherEvpOperation::Update(const AuthorizationSet& additional_params,
@@ -177,6 +177,7 @@
     return KM_ERROR_OK;
 }
 
+// NOLINTNEXTLINE(google-runtime-int)
 inline bool is_bad_decrypt(unsigned long error) {
     return (ERR_GET_LIB(error) == ERR_LIB_CIPHER &&  //
             ERR_GET_REASON(error) == CIPHER_R_BAD_DECRYPT);
@@ -197,7 +198,9 @@
     int output_written = -1;
     if (!EVP_CipherFinal_ex(&ctx_, output->peek_write(), &output_written)) {
         if (tag_length_ > 0) return KM_ERROR_VERIFICATION_FAILED;
-        LOG_E("Error encrypting final block: %s", ERR_error_string(ERR_peek_last_error(), nullptr));
+        char buf[128];
+        ERR_error_string_n(ERR_peek_last_error(), buf, sizeof(buf));
+        LOG_E("Error encrypting final block: %s", buf);
         return TranslateLastOpenSslError();
     }
 
@@ -222,7 +225,7 @@
     }
 }
 
-keymaster_error_t BlockCipherEvpOperation::InitializeCipher(KeymasterKeyBlob key) {
+keymaster_error_t BlockCipherEvpOperation::InitializeCipher(const KeymasterKeyBlob& key) {
     keymaster_error_t error;
     const EVP_CIPHER* cipher =
         cipher_description_.GetCipherInstance(key.key_material_size, block_mode_, &error);
diff --git a/km_openssl/block_cipher_operation.h b/km_openssl/block_cipher_operation.h
index 1da94eb..9c25bda 100644
--- a/km_openssl/block_cipher_operation.h
+++ b/km_openssl/block_cipher_operation.h
@@ -87,7 +87,7 @@
     virtual int evp_encrypt_mode() = 0;
 
     bool need_iv() const;
-    keymaster_error_t InitializeCipher(KeymasterKeyBlob key);
+    keymaster_error_t InitializeCipher(const KeymasterKeyBlob& key);
     keymaster_error_t GetIv(const AuthorizationSet& input_params);
     bool HandleAad(const AuthorizationSet& input_params, const Buffer& input,
                    keymaster_error_t* error);
diff --git a/km_openssl/certificate_utils.cpp b/km_openssl/certificate_utils.cpp
new file mode 100644
index 0000000..d9419c8
--- /dev/null
+++ b/km_openssl/certificate_utils.cpp
@@ -0,0 +1,401 @@
+/*
+ * Copyright 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <openssl/asn1.h>
+#include <openssl/evp.h>
+#include <openssl/x509v3.h>
+
+#include <hardware/keymaster_defs.h>
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/authorization_set.h>
+#include <keymaster/km_openssl/asymmetric_key.h>
+#include <keymaster/km_openssl/certificate_utils.h>
+#include <keymaster/km_openssl/openssl_err.h>
+#include <keymaster/logger.h>
+
+namespace keymaster {
+
+namespace {
+
+constexpr const char kDefaultSubject[] = "Android Keystore Key";
+constexpr int kDataEnciphermentKeyUsageBit = 3;
+constexpr int kDigitalSignatureKeyUsageBit = 0;
+constexpr int kKeyEnciphermentKeyUsageBit = 2;
+constexpr int kKeyAgreementKeyUsageBit = 4;
+constexpr int kMaxKeyUsageBit = 8;
+
+template <typename T> T&& min(T&& a, T&& b) {
+    return (a < b) ? forward<T>(a) : forward<T>(b);
+}
+
+keymaster_error_t fake_sign_cert(X509* cert) {
+    // Set algorithm in TBSCertificate
+    X509_ALGOR_set0(cert->cert_info->signature, OBJ_nid2obj(NID_sha256WithRSAEncryption),
+                    V_ASN1_NULL, nullptr);
+
+    // Set algorithm in Certificate
+    X509_ALGOR_set0(cert->sig_alg, OBJ_nid2obj(NID_sha256WithRSAEncryption), V_ASN1_NULL, nullptr);
+
+    // Set signature to a bit string containing a single byte, value 0.
+    uint8_t fake_sig = 0;
+    if (!cert->signature) cert->signature = ASN1_BIT_STRING_new();
+    if (!cert->signature) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!ASN1_STRING_set(cert->signature, &fake_sig, sizeof(fake_sig))) {
+        return TranslateLastOpenSslError();
+    }
+
+    return KM_ERROR_OK;
+}
+
+}  // namespace
+
+keymaster_error_t make_name_from_str(const char name[], X509_NAME_Ptr* name_out) {
+    if (name_out == nullptr) return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    X509_NAME_Ptr x509_name(X509_NAME_new());
+    if (!x509_name.get()) {
+        return TranslateLastOpenSslError();
+    }
+    if (!X509_NAME_add_entry_by_txt(x509_name.get(),  //
+                                    "CN",             //
+                                    MBSTRING_ASC, reinterpret_cast<const uint8_t*>(&name[0]),
+                                    -1,  // len
+                                    -1,  // loc
+                                    0 /* set */)) {
+        return TranslateLastOpenSslError();
+    }
+    *name_out = move(x509_name);
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t make_name_from_der(const keymaster_blob_t& name, X509_NAME_Ptr* name_out) {
+    if (!name_out || !name.data) return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    const uint8_t* p = name.data;
+    X509_NAME_Ptr x509_name(d2i_X509_NAME(nullptr, &p, name.data_length));
+    if (!x509_name.get()) {
+        return TranslateLastOpenSslError();
+    }
+
+    *name_out = move(x509_name);
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t get_common_name(X509_NAME* name, UniquePtr<const char[]>* name_out) {
+    if (name == nullptr || name_out == nullptr) return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    int len = X509_NAME_get_text_by_NID(name, NID_commonName, nullptr, 0);
+    UniquePtr<char[]> name_ptr(new (std::nothrow) char[len]);
+    if (!name_ptr) {
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+    X509_NAME_get_text_by_NID(name, NID_commonName, name_ptr.get(), len);
+    *name_out = UniquePtr<const char[]>{name_ptr.release()};
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t get_certificate_params(const AuthorizationSet& caller_params,
+                                         CertificateCallerParams* cert_params,
+                                         KmVersion kmVersion) {
+    if (!cert_params) return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    BIGNUM_Ptr serial(BN_new());
+    if (!serial) {
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+
+    keymaster_blob_t serial_blob{.data = nullptr, .data_length = 0};
+    if (caller_params.GetTagValue(TAG_CERTIFICATE_SERIAL, &serial_blob)) {
+        if (BN_bin2bn(serial_blob.data, serial_blob.data_length, serial.get()) == nullptr) {
+            return TranslateLastOpenSslError();
+        }
+    } else {
+        // Default serial is one.
+        BN_one(serial.get());
+    }
+    cert_params->serial = move(serial);
+
+    cert_params->active_date_time = 0;
+    cert_params->expire_date_time = kUndefinedExpirationDateTime;
+
+    uint64_t tmp;
+    switch (kmVersion) {
+    case KmVersion::KEYMASTER_1:
+    case KmVersion::KEYMASTER_1_1:
+    case KmVersion::KEYMASTER_2:
+    case KmVersion::KEYMASTER_3:
+    case KmVersion::KEYMASTER_4:
+    case KmVersion::KEYMASTER_4_1:
+        if (caller_params.GetTagValue(TAG_ACTIVE_DATETIME, &tmp)) {
+            LOG_D("Using TAG_ACTIVE_DATETIME: %lu", tmp);
+            cert_params->active_date_time = static_cast<int64_t>(tmp);
+        }
+        if (caller_params.GetTagValue(TAG_ORIGINATION_EXPIRE_DATETIME, &tmp)) {
+            LOG_D("Using TAG_ORIGINATION_EXPIRE_DATETIME: %lu", tmp);
+            cert_params->expire_date_time = static_cast<int64_t>(tmp);
+        }
+        break;
+
+    case KmVersion::KEYMINT_1:
+        if (!caller_params.GetTagValue(TAG_CERTIFICATE_NOT_BEFORE, &tmp)) {
+            return KM_ERROR_MISSING_NOT_BEFORE;
+        }
+        LOG_D("Using TAG_CERTIFICATE_NOT_BEFORE: %lu", tmp);
+        cert_params->active_date_time = static_cast<int64_t>(tmp);
+
+        if (!caller_params.GetTagValue(TAG_CERTIFICATE_NOT_AFTER, &tmp)) {
+            return KM_ERROR_MISSING_NOT_AFTER;
+        }
+        LOG_D("Using TAG_CERTIFICATE_NOT_AFTER: %lu", tmp);
+        cert_params->expire_date_time = static_cast<int64_t>(tmp);
+    }
+
+    LOG_D("Got certificate date params:  NotBefore = %ld, NotAfter = %ld",
+          cert_params->active_date_time, cert_params->expire_date_time);
+
+    keymaster_blob_t subject{};
+    if (caller_params.GetTagValue(TAG_CERTIFICATE_SUBJECT, &subject) && subject.data_length) {
+        return make_name_from_der(subject, &cert_params->subject_name);
+    }
+
+    return make_name_from_str(kDefaultSubject, &cert_params->subject_name);
+}
+
+keymaster_error_t make_key_usage_extension(bool is_signing_key, bool is_encryption_key,
+                                           bool is_key_agreement_key,
+                                           X509_EXTENSION_Ptr* usage_extension_out) {
+    if (usage_extension_out == nullptr) return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    // Build BIT_STRING with correct contents.
+    ASN1_BIT_STRING_Ptr key_usage(ASN1_BIT_STRING_new());
+    if (!key_usage) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    for (size_t i = 0; i <= kMaxKeyUsageBit; ++i) {
+        if (!ASN1_BIT_STRING_set_bit(key_usage.get(), i, 0)) {
+            return TranslateLastOpenSslError();
+        }
+    }
+
+    if (is_signing_key) {
+        if (!ASN1_BIT_STRING_set_bit(key_usage.get(), kDigitalSignatureKeyUsageBit, 1)) {
+            return TranslateLastOpenSslError();
+        }
+    }
+
+    if (is_encryption_key) {
+        if (!ASN1_BIT_STRING_set_bit(key_usage.get(), kKeyEnciphermentKeyUsageBit, 1) ||
+            !ASN1_BIT_STRING_set_bit(key_usage.get(), kDataEnciphermentKeyUsageBit, 1)) {
+            return TranslateLastOpenSslError();
+        }
+    }
+
+    if (is_key_agreement_key) {
+        if (!ASN1_BIT_STRING_set_bit(key_usage.get(), kKeyAgreementKeyUsageBit, 1)) {
+            return TranslateLastOpenSslError();
+        }
+    }
+
+    // Convert to octets
+    int len = i2d_ASN1_BIT_STRING(key_usage.get(), nullptr);
+    if (len < 0) {
+        return TranslateLastOpenSslError();
+    }
+    UniquePtr<uint8_t[]> asn1_key_usage(new (std::nothrow) uint8_t[len]);
+    if (!asn1_key_usage.get()) {
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+    uint8_t* p = asn1_key_usage.get();
+    len = i2d_ASN1_BIT_STRING(key_usage.get(), &p);
+    if (len < 0) {
+        return TranslateLastOpenSslError();
+    }
+
+    // Build OCTET_STRING
+    ASN1_OCTET_STRING_Ptr key_usage_str(ASN1_OCTET_STRING_new());
+    if (!key_usage_str.get() ||
+        !ASN1_OCTET_STRING_set(key_usage_str.get(), asn1_key_usage.get(), len)) {
+        return TranslateLastOpenSslError();
+    }
+
+    X509_EXTENSION_Ptr key_usage_extension(X509_EXTENSION_create_by_NID(nullptr,        //
+                                                                        NID_key_usage,  //
+                                                                        true /* critical */,
+                                                                        key_usage_str.get()));
+    if (!key_usage_extension.get()) {
+        return TranslateLastOpenSslError();
+    }
+
+    *usage_extension_out = move(key_usage_extension);
+
+    return KM_ERROR_OK;
+}
+
+// Creates a rump certificate structure with serial, subject and issuer names, as well as
+// activation and expiry date.
+// Callers should pass an empty X509_Ptr and check the return value for KM_ERROR_OK (0) before
+// accessing the result.
+keymaster_error_t make_cert_rump(const X509_NAME* issuer,
+                                 const CertificateCallerParams& cert_params, X509_Ptr* cert_out) {
+    if (!cert_out || !issuer) return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    // Create certificate structure.
+    X509_Ptr certificate(X509_new());
+    if (!certificate.get()) return TranslateLastOpenSslError();
+
+    // Set the X509 version.
+    if (!X509_set_version(certificate.get(), 2 /* version 3 */)) return TranslateLastOpenSslError();
+
+    // Set the certificate serialNumber
+    ASN1_INTEGER_Ptr serial_number(ASN1_INTEGER_new());
+    if (!serial_number.get() ||  //
+        !BN_to_ASN1_INTEGER(cert_params.serial.get(), serial_number.get()) ||
+        !X509_set_serialNumber(certificate.get(),
+                               serial_number.get() /* Don't release; copied */)) {
+        return TranslateLastOpenSslError();
+    }
+
+    if (!X509_set_subject_name(certificate.get(),
+                               const_cast<X509_NAME*>(cert_params.subject_name.get()))) {
+        return TranslateLastOpenSslError();
+    }
+
+    if (!X509_set_issuer_name(certificate.get(), const_cast<X509_NAME*>(issuer))) {
+        return TranslateLastOpenSslError();
+    }
+
+    // Set activation date.
+    ASN1_TIME_Ptr notBefore(ASN1_TIME_new());
+    LOG_D("Setting notBefore to %ld: ", cert_params.active_date_time / 1000);
+    time_t notBeforeTime = static_cast<time_t>(cert_params.active_date_time / 1000);
+    if (!notBefore.get() || !ASN1_TIME_set(notBefore.get(), notBeforeTime) ||
+        !X509_set_notBefore(certificate.get(), notBefore.get() /* Don't release; copied */)) {
+        return TranslateLastOpenSslError();
+    }
+
+    // Set expiration date.
+    ASN1_TIME_Ptr notAfter(ASN1_TIME_new());
+    LOG_D("Setting notAfter to %ld: ", cert_params.expire_date_time / 1000);
+    time_t notAfterTime = static_cast<time_t>(cert_params.expire_date_time / 1000);
+
+    if (!notAfter.get() || !ASN1_TIME_set(notAfter.get(), notAfterTime) ||
+        !X509_set_notAfter(certificate.get(), notAfter.get() /* Don't release; copied */)) {
+        return TranslateLastOpenSslError();
+    }
+
+    *cert_out = move(certificate);
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t make_cert(const EVP_PKEY* evp_pkey, const X509_NAME* issuer,
+                            const CertificateCallerParams& cert_params, X509_Ptr* cert_out) {
+
+    // Make the rump certificate with serial, subject, not before and not after dates.
+    X509_Ptr certificate;
+    if (keymaster_error_t error = make_cert_rump(issuer, cert_params, &certificate)) {
+        return error;
+    }
+
+    // Set the public key.
+    if (!X509_set_pubkey(certificate.get(), (EVP_PKEY*)evp_pkey)) {
+        return TranslateLastOpenSslError();
+    }
+
+    // Make and add the key usage extension.
+    X509_EXTENSION_Ptr key_usage_extension;
+    if (auto error =
+            make_key_usage_extension(cert_params.is_signing_key, cert_params.is_encryption_key,
+                                     cert_params.is_agreement_key, &key_usage_extension)) {
+        return error;
+    }
+    if (!X509_add_ext(certificate.get(), key_usage_extension.get() /* Don't release; copied */,
+                      -1 /* insert at end */)) {
+        return TranslateLastOpenSslError();
+    }
+
+    *cert_out = move(certificate);
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t sign_cert(X509* certificate, const EVP_PKEY* signing_key) {
+    if (!certificate || !signing_key) return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    // X509_sign takes the key as non-const, but per the BoringSSL dev team, that's a legacy
+    // mistake that hasn't yet been corrected.
+    auto sk = const_cast<EVP_PKEY*>(signing_key);
+
+    if (!X509_sign(certificate, sk, EVP_sha256())) {
+        return TranslateLastOpenSslError();
+    }
+    return KM_ERROR_OK;
+}
+
+CertificateChain generate_self_signed_cert(const AsymmetricKey& key, const AuthorizationSet& params,
+                                           bool fake_signature, keymaster_error_t* error) {
+    keymaster_error_t err;
+    if (!error) error = &err;
+
+    EVP_PKEY_Ptr pkey(EVP_PKEY_new());
+    if (!key.InternalToEvp(pkey.get())) {
+        *error = TranslateLastOpenSslError();
+        return {};
+    }
+
+    CertificateCallerParams cert_params{};
+    // Self signed certificates are only generated since Keymint 1.0. To keep the API stable for
+    // now, we pass KEYMINT_1 to get_certificate_params, which has the intended effect. If
+    // get_certificate_params ever has to distinguish between versions of KeyMint this needs to be
+    // changed.
+    *error = get_certificate_params(params, &cert_params, KmVersion::KEYMINT_1);
+    if (*error != KM_ERROR_OK) return {};
+
+    cert_params.is_signing_key = key.authorizations().Contains(TAG_PURPOSE, KM_PURPOSE_SIGN);
+    cert_params.is_encryption_key = key.authorizations().Contains(TAG_PURPOSE, KM_PURPOSE_DECRYPT);
+    cert_params.is_agreement_key = key.authorizations().Contains(TAG_PURPOSE, KM_PURPOSE_AGREE_KEY);
+
+    X509_Ptr cert;
+    *error = make_cert(pkey.get(), cert_params.subject_name.get() /* issuer */, cert_params, &cert);
+    if (*error != KM_ERROR_OK) return {};
+
+    if (fake_signature) {
+        *error = fake_sign_cert(cert.get());
+    } else {
+        *error = sign_cert(cert.get(), pkey.get());
+    }
+    if (*error != KM_ERROR_OK) return {};
+
+    CertificateChain result(1);
+    if (!result) {
+        *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        return {};
+    }
+
+    *error = encode_certificate(cert.get(), &result.entries[0]);
+    if (*error != KM_ERROR_OK) return {};
+
+    return result;
+}
+
+keymaster_error_t encode_certificate(X509* certificate, keymaster_blob_t* blob) {
+    int len = i2d_X509(certificate, nullptr /* ppout */);
+    if (len < 0) return TranslateLastOpenSslError();
+
+    blob->data = new (std::nothrow) uint8_t[len];
+    if (!blob->data) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    uint8_t* p = const_cast<uint8_t*>(blob->data);
+    blob->data_length = i2d_X509(certificate, &p);
+    return KM_ERROR_OK;
+}
+
+}  // namespace keymaster
diff --git a/km_openssl/ec_key_factory.cpp b/km_openssl/ec_key_factory.cpp
index 8dead88..80d761f 100644
--- a/km_openssl/ec_key_factory.cpp
+++ b/km_openssl/ec_key_factory.cpp
@@ -18,7 +18,9 @@
 
 #include <openssl/evp.h>
 
+#include <keymaster/keymaster_context.h>
 #include <keymaster/km_openssl/ec_key.h>
+#include <keymaster/km_openssl/ecdh_operation.h>
 #include <keymaster/km_openssl/ecdsa_operation.h>
 #include <keymaster/km_openssl/openssl_err.h>
 
@@ -28,6 +30,7 @@
 
 static EcdsaSignOperationFactory sign_factory;
 static EcdsaVerifyOperationFactory verify_factory;
+static EcdhOperationFactory agree_key_factory;
 
 OperationFactory* EcKeyFactory::GetOperationFactory(keymaster_purpose_t purpose) const {
     switch (purpose) {
@@ -35,6 +38,8 @@
         return &sign_factory;
     case KM_PURPOSE_VERIFY:
         return &verify_factory;
+    case KM_PURPOSE_AGREE_KEY:
+        return &agree_key_factory;
     default:
         return nullptr;
     }
@@ -72,11 +77,13 @@
 }
 
 keymaster_error_t EcKeyFactory::GenerateKey(const AuthorizationSet& key_description,
+                                            UniquePtr<Key> attest_key,  //
+                                            const KeymasterBlob& issuer_subject,
                                             KeymasterKeyBlob* key_blob,
                                             AuthorizationSet* hw_enforced,
-                                            AuthorizationSet* sw_enforced) const {
-    if (!key_blob || !hw_enforced || !sw_enforced)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+                                            AuthorizationSet* sw_enforced,
+                                            CertificateChain* cert_chain) const {
+    if (!key_blob || !hw_enforced || !sw_enforced) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     AuthorizationSet authorizations(key_description);
 
@@ -93,8 +100,7 @@
 
     UniquePtr<EC_KEY, EC_KEY_Delete> ec_key(EC_KEY_new());
     UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new());
-    if (ec_key.get() == nullptr || pkey.get() == nullptr)
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (ec_key.get() == nullptr || pkey.get() == nullptr) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
     UniquePtr<EC_GROUP, EC_GROUP_Delete> group(ChooseGroup(ec_curve));
     if (group.get() == nullptr) {
@@ -112,36 +118,78 @@
         return TranslateLastOpenSslError();
     }
 
-    if (EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get()) != 1)
-        return TranslateLastOpenSslError();
+    if (EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get()) != 1) return TranslateLastOpenSslError();
 
     KeymasterKeyBlob key_material;
     error = EvpKeyToKeyMaterial(pkey.get(), &key_material);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
-    return blob_maker_.CreateKeyBlob(authorizations, KM_ORIGIN_GENERATED, key_material, key_blob,
-                                     hw_enforced, sw_enforced);
+    error = blob_maker_.CreateKeyBlob(authorizations, KM_ORIGIN_GENERATED, key_material, key_blob,
+                                      hw_enforced, sw_enforced);
+    if (error != KM_ERROR_OK) return error;
+
+    if (context_.GetKmVersion() < KmVersion::KEYMINT_1) return KM_ERROR_OK;
+    if (!cert_chain) return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    EcKey key(*hw_enforced, *sw_enforced, this, move(ec_key));
+    if (key_description.Contains(TAG_ATTESTATION_CHALLENGE)) {
+        *cert_chain = context_.GenerateAttestation(key, key_description, move(attest_key),
+                                                   issuer_subject, &error);
+    } else if (attest_key.get() != nullptr) {
+        return KM_ERROR_ATTESTATION_CHALLENGE_MISSING;
+    } else {
+        *cert_chain = context_.GenerateSelfSignedCertificate(
+            key, key_description,
+            !key_description.Contains(TAG_PURPOSE, KM_PURPOSE_SIGN) /* fake_signature */, &error);
+    }
+
+    return error;
 }
 
-keymaster_error_t EcKeyFactory::ImportKey(const AuthorizationSet& key_description,
+keymaster_error_t EcKeyFactory::ImportKey(const AuthorizationSet& key_description,  //
                                           keymaster_key_format_t input_key_material_format,
                                           const KeymasterKeyBlob& input_key_material,
+                                          UniquePtr<Key> attest_key,  //
+                                          const KeymasterBlob& issuer_subject,
                                           KeymasterKeyBlob* output_key_blob,
                                           AuthorizationSet* hw_enforced,
-                                          AuthorizationSet* sw_enforced) const {
-    if (!output_key_blob || !hw_enforced || !sw_enforced)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+                                          AuthorizationSet* sw_enforced,
+                                          CertificateChain* cert_chain) const {
+    if (!output_key_blob || !hw_enforced || !sw_enforced) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     AuthorizationSet authorizations;
     uint32_t key_size;
     keymaster_error_t error = UpdateImportKeyDescription(
         key_description, input_key_material_format, input_key_material, &authorizations, &key_size);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
-    return blob_maker_.CreateKeyBlob(authorizations, KM_ORIGIN_IMPORTED, input_key_material,
-                                     output_key_blob, hw_enforced, sw_enforced);
+    error = blob_maker_.CreateKeyBlob(authorizations, KM_ORIGIN_IMPORTED, input_key_material,
+                                      output_key_blob, hw_enforced, sw_enforced);
+    if (error != KM_ERROR_OK) return error;
+
+    if (context_.GetKmVersion() < KmVersion::KEYMINT_1) return KM_ERROR_OK;
+    if (!cert_chain) return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    EVP_PKEY_Ptr pkey;
+    error = KeyMaterialToEvpKey(KM_KEY_FORMAT_PKCS8, input_key_material, KM_ALGORITHM_EC, &pkey);
+    if (error != KM_ERROR_OK) return error;
+
+    EC_KEY_Ptr ec_key(EVP_PKEY_get1_EC_KEY(pkey.get()));
+    if (!ec_key.get()) return KM_ERROR_INVALID_ARGUMENT;
+
+    EcKey key(*hw_enforced, *sw_enforced, this, move(ec_key));
+    if (key_description.Contains(KM_TAG_ATTESTATION_CHALLENGE)) {
+        *cert_chain = context_.GenerateAttestation(key, key_description, move(attest_key),
+                                                   issuer_subject, &error);
+    } else if (attest_key.get() != nullptr) {
+        return KM_ERROR_ATTESTATION_CHALLENGE_MISSING;
+    } else {
+        *cert_chain = context_.GenerateSelfSignedCertificate(
+            key, key_description,
+            !key_description.Contains(TAG_PURPOSE, KM_PURPOSE_SIGN) /* fake_signature */, &error);
+    }
+
+    return error;
 }
 
 keymaster_error_t EcKeyFactory::UpdateImportKeyDescription(const AuthorizationSet& key_description,
@@ -149,25 +197,21 @@
                                                            const KeymasterKeyBlob& key_material,
                                                            AuthorizationSet* updated_description,
                                                            uint32_t* key_size_bits) const {
-    if (!updated_description || !key_size_bits)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    if (!updated_description || !key_size_bits) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey;
     keymaster_error_t error =
         KeyMaterialToEvpKey(key_format, key_material, keymaster_key_type(), &pkey);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     UniquePtr<EC_KEY, EC_KEY_Delete> ec_key(EVP_PKEY_get1_EC_KEY(pkey.get()));
-    if (!ec_key.get())
-        return TranslateLastOpenSslError();
+    if (!ec_key.get()) return TranslateLastOpenSslError();
 
     updated_description->Reinitialize(key_description);
 
     size_t extracted_key_size_bits;
     error = ec_get_group_size(EC_KEY_get0_group(ec_key.get()), &extracted_key_size_bits);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     *key_size_bits = extracted_key_size_bits;
     if (!updated_description->GetTagValue(TAG_KEY_SIZE, key_size_bits)) {
@@ -178,8 +222,7 @@
 
     keymaster_ec_curve_t curve_from_size;
     error = EcKeySizeToCurve(*key_size_bits, &curve_from_size);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
     keymaster_ec_curve_t curve;
     if (!updated_description->GetTagValue(TAG_EC_CURVE, &curve)) {
         updated_description->push_back(TAG_EC_CURVE, curve_from_size);
diff --git a/km_openssl/ecdh_operation.cpp b/km_openssl/ecdh_operation.cpp
new file mode 100644
index 0000000..fbc6f3e
--- /dev/null
+++ b/km_openssl/ecdh_operation.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <keymaster/km_openssl/ecdh_operation.h>
+
+#include <keymaster/km_openssl/ec_key.h>
+#include <keymaster/km_openssl/openssl_err.h>
+#include <keymaster/km_openssl/openssl_utils.h>
+#include <keymaster/logger.h>
+#include <openssl/err.h>
+#include <vector>
+
+namespace keymaster {
+
+keymaster_error_t EcdhOperation::Begin(const AuthorizationSet& /*input_params*/,
+                                       AuthorizationSet* /*output_params*/) {
+    auto rc = GenerateRandom(reinterpret_cast<uint8_t*>(&operation_handle_),
+                             (size_t)sizeof(operation_handle_));
+    if (rc != KM_ERROR_OK) {
+        return rc;
+    }
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t EcdhOperation::Update(const AuthorizationSet& /*additional_params*/,
+                                        const Buffer& /*input*/,
+                                        AuthorizationSet* /*output_params*/, Buffer* /*output*/,
+                                        size_t* /*input_consumed*/) {
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t EcdhOperation::Finish(const AuthorizationSet& /*additional_params*/,
+                                        const Buffer& input, const Buffer& /*signature*/,
+                                        AuthorizationSet* /*output_params*/, Buffer* output) {
+    const unsigned char* encodedPublicKey = input.begin();
+    EVP_PKEY* pkeyRaw = d2i_PUBKEY(nullptr, &encodedPublicKey, input.available_read());
+    if (pkeyRaw == nullptr) {
+        LOG_E("Error decoding key", 0);
+        return TranslateLastOpenSslError();
+    }
+    auto pkey = EVP_PKEY_Ptr(pkeyRaw);
+
+    auto ctx = EVP_PKEY_CTX_Ptr(EVP_PKEY_CTX_new(ecdh_key_.get(), nullptr));
+    if (ctx.get() == nullptr) {
+        LOG_E("Memory allocation failed", 0);
+        return TranslateLastOpenSslError();
+    }
+    if (EVP_PKEY_derive_init(ctx.get()) != 1) {
+        LOG_E("Context initialization failed", 0);
+        return TranslateLastOpenSslError();
+    }
+    if (EVP_PKEY_derive_set_peer(ctx.get(), pkey.get()) != 1) {
+        LOG_E("Error setting peer key", 0);
+        return TranslateLastOpenSslError();
+    }
+    size_t sharedSecretLen = 0;
+    if (EVP_PKEY_derive(ctx.get(), nullptr, &sharedSecretLen) != 1) {
+        LOG_E("Error deriving key", 0);
+        return TranslateLastOpenSslError();
+    }
+    if (!output->reserve(sharedSecretLen)) {
+        LOG_E("Error reserving data in output buffer", 0);
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+    if (EVP_PKEY_derive(ctx.get(), output->peek_write(), &sharedSecretLen) != 1) {
+        LOG_E("Error deriving key", 0);
+        return TranslateLastOpenSslError();
+    }
+    output->advance_write(sharedSecretLen);
+
+    return KM_ERROR_OK;
+}
+
+OperationPtr EcdhOperationFactory::CreateOperation(Key&& key,
+                                                   const AuthorizationSet& /*begin_params*/,
+                                                   keymaster_error_t* error) {
+    const EcKey& ecdh_key = static_cast<EcKey&>(key);
+
+    EVP_PKEY_Ptr pkey(EVP_PKEY_new());
+    if (pkey.get() == nullptr) {
+        *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        return nullptr;
+    }
+    if (!ecdh_key.InternalToEvp(pkey.get())) {
+        *error = KM_ERROR_UNKNOWN_ERROR;
+        return nullptr;
+    }
+
+    *error = KM_ERROR_OK;
+    auto op = new (std::nothrow)
+        EcdhOperation(move(key.hw_enforced_move()), move(key.sw_enforced_move()), pkey.release());
+    if (!op) {
+        *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        return nullptr;
+    }
+    return OperationPtr(op);
+}
+
+}  // namespace keymaster
diff --git a/km_openssl/ecdsa_operation.cpp b/km_openssl/ecdsa_operation.cpp
index e4cac5a..b840bb0 100644
--- a/km_openssl/ecdsa_operation.cpp
+++ b/km_openssl/ecdsa_operation.cpp
@@ -56,8 +56,7 @@
 }
 
 EcdsaOperation::~EcdsaOperation() {
-    if (ecdsa_key_ != nullptr)
-        EVP_PKEY_free(ecdsa_key_);
+    if (ecdsa_key_ != nullptr) EVP_PKEY_free(ecdsa_key_);
     EVP_MD_CTX_cleanup(&digest_ctx_);
 }
 
@@ -109,11 +108,9 @@
     if (rc != KM_ERROR_OK) return rc;
 
     keymaster_error_t error = InitDigest();
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
-    if (digest_ == KM_DIGEST_NONE)
-        return KM_ERROR_OK;
+    if (digest_ == KM_DIGEST_NONE) return KM_ERROR_OK;
 
     EVP_PKEY_CTX* pkey_ctx;
     if (EVP_DigestSignInit(&digest_ctx_, &pkey_ctx, digest_algorithm_, nullptr /* engine */,
@@ -126,8 +123,7 @@
                                              const Buffer& input,
                                              AuthorizationSet* /* output_params */,
                                              Buffer* /* output */, size_t* input_consumed) {
-    if (digest_ == KM_DIGEST_NONE)
-        return StoreData(input, input_consumed);
+    if (digest_ == KM_DIGEST_NONE) return StoreData(input, input_consumed);
 
     if (EVP_DigestSignUpdate(&digest_ctx_, input.peek_read(), input.available_read()) != 1)
         return TranslateLastOpenSslError();
@@ -139,18 +135,15 @@
                                              const Buffer& input, const Buffer& /* signature */,
                                              AuthorizationSet* /* output_params */,
                                              Buffer* output) {
-    if (!output)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    if (!output) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     keymaster_error_t error = UpdateForFinish(additional_params, input);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     size_t siglen;
     if (digest_ == KM_DIGEST_NONE) {
         UniquePtr<EC_KEY, EC_KEY_Delete> ecdsa(EVP_PKEY_get1_EC_KEY(ecdsa_key_));
-        if (!ecdsa.get())
-            return TranslateLastOpenSslError();
+        if (!ecdsa.get()) return TranslateLastOpenSslError();
 
         output->Reinitialize(ECDSA_size(ecdsa.get()));
         unsigned int siglen_tmp;
@@ -161,13 +154,11 @@
     } else {
         if (EVP_DigestSignFinal(&digest_ctx_, nullptr /* signature */, &siglen) != 1)
             return TranslateLastOpenSslError();
-        if (!output->Reinitialize(siglen))
-            return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+        if (!output->Reinitialize(siglen)) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
         if (EVP_DigestSignFinal(&digest_ctx_, output->peek_write(), &siglen) <= 0)
             return TranslateLastOpenSslError();
     }
-    if (!output->advance_write(siglen))
-        return KM_ERROR_UNKNOWN_ERROR;
+    if (!output->advance_write(siglen)) return KM_ERROR_UNKNOWN_ERROR;
     return KM_ERROR_OK;
 }
 
@@ -178,11 +169,9 @@
     if (rc != KM_ERROR_OK) return rc;
 
     keymaster_error_t error = InitDigest();
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
-    if (digest_ == KM_DIGEST_NONE)
-        return KM_ERROR_OK;
+    if (digest_ == KM_DIGEST_NONE) return KM_ERROR_OK;
 
     EVP_PKEY_CTX* pkey_ctx;
     if (EVP_DigestVerifyInit(&digest_ctx_, &pkey_ctx, digest_algorithm_, nullptr /* engine */,
@@ -195,8 +184,7 @@
                                                const Buffer& input,
                                                AuthorizationSet* /* output_params */,
                                                Buffer* /* output */, size_t* input_consumed) {
-    if (digest_ == KM_DIGEST_NONE)
-        return StoreData(input, input_consumed);
+    if (digest_ == KM_DIGEST_NONE) return StoreData(input, input_consumed);
 
     if (EVP_DigestVerifyUpdate(&digest_ctx_, input.peek_read(), input.available_read()) != 1)
         return TranslateLastOpenSslError();
@@ -209,13 +197,11 @@
                                                AuthorizationSet* /* output_params */,
                                                Buffer* /* output */) {
     keymaster_error_t error = UpdateForFinish(additional_params, input);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     if (digest_ == KM_DIGEST_NONE) {
         UniquePtr<EC_KEY, EC_KEY_Delete> ecdsa(EVP_PKEY_get1_EC_KEY(ecdsa_key_));
-        if (!ecdsa.get())
-            return TranslateLastOpenSslError();
+        if (!ecdsa.get()) return TranslateLastOpenSslError();
 
         int result =
             ECDSA_verify(0 /* type -- ignored */, data_.peek_read(), data_.available_read(),
diff --git a/km_openssl/ecies_kem.cpp b/km_openssl/ecies_kem.cpp
index 91f6912..6c5b15d 100644
--- a/km_openssl/ecies_kem.cpp
+++ b/km_openssl/ecies_kem.cpp
@@ -50,7 +50,7 @@
     }
     switch (kdf) {
     case KM_KDF_RFC5869_SHA256:
-        kdf_.reset(new(std::nothrow) Rfc5869Sha256Kdf());
+        kdf_.reset(new (std::nothrow) Rfc5869Sha256Kdf());
         break;
     default:
         LOG_E("Kdf %d is unsupported", kdf);
@@ -136,7 +136,7 @@
                        Buffer* output_key) {
 
     keymaster_error_t error;
-    key_exchange_.reset(new(std::nothrow) NistCurveKeyExchange(private_key, &error));
+    key_exchange_.reset(new (std::nothrow) NistCurveKeyExchange(private_key, &error));
     if (!key_exchange_.get() || error != KM_ERROR_OK) {
         return false;
     }
diff --git a/km_openssl/hkdf.cpp b/km_openssl/hkdf.cpp
index 7ac49b9..8bd466a 100644
--- a/km_openssl/hkdf.cpp
+++ b/km_openssl/hkdf.cpp
@@ -18,14 +18,12 @@
 
 #include <keymaster/android_keymaster_utils.h>
 #include <keymaster/km_openssl/hmac.h>
-#include <keymaster/new.h>
 
 namespace keymaster {
 
 bool Rfc5869Sha256Kdf::GenerateKey(const uint8_t* info, size_t info_len, uint8_t* output,
                                    size_t output_len) {
-    if (!is_initialized_ || output == nullptr)
-        return false;
+    if (!is_initialized_ || output == nullptr) return false;
     /**
      * Step 1. Extract: PRK = HMAC-SHA256(actual_salt, secret)
      * https://tools.ietf.org/html/rfc5869#section-2.2
@@ -35,40 +33,33 @@
     if (salt_.get() != nullptr && salt_len_ > 0) {
         result = prk_hmac.Init(salt_.get(), salt_len_);
     } else {
-        UniquePtr<uint8_t[]> zeros(new(std::nothrow) uint8_t[digest_size_]);
-        if (zeros.get() == nullptr)
-            return false;
+        UniquePtr<uint8_t[]> zeros(new (std::nothrow) uint8_t[digest_size_]);
+        if (zeros.get() == nullptr) return false;
         /* If salt is not given, digest size of zeros are used. */
         memset(zeros.get(), 0, digest_size_);
         result = prk_hmac.Init(zeros.get(), digest_size_);
     }
-    if (!result)
-        return false;
+    if (!result) return false;
 
-    UniquePtr<uint8_t[]> pseudo_random_key(new(std::nothrow) uint8_t[digest_size_]);
-    if (pseudo_random_key.get() == nullptr || digest_size_ != prk_hmac.DigestLength())
-        return false;
+    UniquePtr<uint8_t[]> pseudo_random_key(new (std::nothrow) uint8_t[digest_size_]);
+    if (pseudo_random_key.get() == nullptr || digest_size_ != prk_hmac.DigestLength()) return false;
     result =
         prk_hmac.Sign(secret_key_.get(), secret_key_len_, pseudo_random_key.get(), digest_size_);
-    if (!result)
-        return false;
+    if (!result) return false;
 
     /**
      * Step 2. Expand: OUTPUT = HKDF-Expand(PRK, info)
      * https://tools.ietf.org/html/rfc5869#section-2.3
      */
     const size_t num_blocks = (output_len + digest_size_ - 1) / digest_size_;
-    if (num_blocks >= 256u)
-        return false;
+    if (num_blocks >= 256u) return false;
 
-    UniquePtr<uint8_t[]> buf(new(std::nothrow) uint8_t[digest_size_ + info_len + 1]);
-    UniquePtr<uint8_t[]> digest(new(std::nothrow) uint8_t[digest_size_]);
-    if (buf.get() == nullptr || digest.get() == nullptr)
-        return false;
+    UniquePtr<uint8_t[]> buf(new (std::nothrow) uint8_t[digest_size_ + info_len + 1]);
+    UniquePtr<uint8_t[]> digest(new (std::nothrow) uint8_t[digest_size_]);
+    if (buf.get() == nullptr || digest.get() == nullptr) return false;
     HmacSha256 hmac;
     result = hmac.Init(pseudo_random_key.get(), digest_size_);
-    if (!result)
-        return false;
+    if (!result) return false;
 
     for (size_t i = 0; i < num_blocks; i++) {
         size_t block_input_len = 0;
@@ -76,13 +67,11 @@
             memcpy(buf.get(), digest.get(), digest_size_);
             block_input_len = digest_size_;
         }
-        if (info != nullptr && info_len > 0)
-            memcpy(buf.get() + block_input_len, info, info_len);
+        if (info != nullptr && info_len > 0) memcpy(buf.get() + block_input_len, info, info_len);
         block_input_len += info_len;
         *(buf.get() + block_input_len++) = static_cast<uint8_t>(i + 1);
         result = hmac.Sign(buf.get(), block_input_len, digest.get(), digest_size_);
-        if (!result)
-            return false;
+        if (!result) return false;
         size_t block_output_len = digest_size_ < output_len - i * digest_size_
                                       ? digest_size_
                                       : output_len - i * digest_size_;
diff --git a/km_openssl/hmac.cpp b/km_openssl/hmac.cpp
index e39f671..cb788d0 100644
--- a/km_openssl/hmac.cpp
+++ b/km_openssl/hmac.cpp
@@ -36,8 +36,7 @@
 }
 
 bool HmacSha256::Init(const uint8_t* key, size_t key_len) {
-    if (!key)
-        return false;
+    if (!key) return false;
 
     key_len_ = key_len;
     key_.reset(dup_buffer(key, key_len));
@@ -57,14 +56,12 @@
 
     uint8_t tmp[SHA256_DIGEST_LENGTH];
     uint8_t* digest = tmp;
-    if (digest_len >= SHA256_DIGEST_LENGTH)
-        digest = out_digest;
+    if (digest_len >= SHA256_DIGEST_LENGTH) digest = out_digest;
 
     if (nullptr == ::HMAC(EVP_sha256(), key_.get(), key_len_, data, data_len, digest, nullptr)) {
         return false;
     }
-    if (digest_len < SHA256_DIGEST_LENGTH)
-        memcpy(out_digest, tmp, digest_len);
+    if (digest_len < SHA256_DIGEST_LENGTH) memcpy(out_digest, tmp, digest_len);
 
     return true;
 }
@@ -76,12 +73,10 @@
 
 bool HmacSha256::Verify(const uint8_t* data, size_t data_len, const uint8_t* digest,
                         size_t digest_len) const {
-    if (digest_len != SHA256_DIGEST_LENGTH)
-        return false;
+    if (digest_len != SHA256_DIGEST_LENGTH) return false;
 
     uint8_t computed_digest[SHA256_DIGEST_LENGTH];
-    if (!Sign(data, data_len, computed_digest, sizeof(computed_digest)))
-        return false;
+    if (!Sign(data, data_len, computed_digest, sizeof(computed_digest))) return false;
 
     return 0 == CRYPTO_memcmp(digest, computed_digest, SHA256_DIGEST_LENGTH);
 }
diff --git a/km_openssl/hmac_key.cpp b/km_openssl/hmac_key.cpp
index b2757b6..d74ff37 100644
--- a/km_openssl/hmac_key.cpp
+++ b/km_openssl/hmac_key.cpp
@@ -16,8 +16,6 @@
 
 #include <keymaster/km_openssl/hmac_key.h>
 
-#include <keymaster/new.h>
-
 #include <openssl/err.h>
 #include <openssl/rand.h>
 
@@ -44,8 +42,7 @@
                                           AuthorizationSet&& hw_enforced,
                                           AuthorizationSet&& sw_enforced,
                                           UniquePtr<Key>* key) const {
-    if (!key)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    if (!key) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     uint32_t min_mac_length;
     if (!hw_enforced.GetTagValue(TAG_MIN_MAC_LENGTH, &min_mac_length) &&
@@ -54,10 +51,9 @@
         return KM_ERROR_INVALID_KEY_BLOB;
     }
 
-    key->reset(new (std::nothrow) HmacKey(move(key_material), move(hw_enforced), move(sw_enforced),
-                                          this));
-    if (!key->get())
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    key->reset(new (std::nothrow)
+                   HmacKey(move(key_material), move(hw_enforced), move(sw_enforced), this));
+    if (!key->get()) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
     return KM_ERROR_OK;
 }
 
@@ -105,8 +101,7 @@
     if (min_mac_length_bits % 8 != 0 || min_mac_length_bits > hash_size_bits)
         return KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH;
 
-    if (min_mac_length_bits < kMinHmacLengthBits)
-        return KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH;
+    if (min_mac_length_bits < kMinHmacLengthBits) return KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH;
 
     return KM_ERROR_OK;
 }
diff --git a/km_openssl/hmac_operation.cpp b/km_openssl/hmac_operation.cpp
index ce80cfc..759ca12 100644
--- a/km_openssl/hmac_operation.cpp
+++ b/km_openssl/hmac_operation.cpp
@@ -16,8 +16,6 @@
 
 #include "hmac_operation.h"
 
-#include <keymaster/new.h>
-
 #include <openssl/evp.h>
 #include <openssl/hmac.h>
 
@@ -50,6 +48,11 @@
             *error = KM_ERROR_INVALID_ARGUMENT;
             return nullptr;
         }
+        if ((mac_length_bits % 8) != 0) {
+            LOG_E("MAC length must be a multiple of 8", mac_length_bits);
+            *error = KM_ERROR_UNSUPPORTED_MAC_LENGTH;
+            return nullptr;
+        }
     } else {
         if (purpose() == KM_PURPOSE_SIGN) {
             *error = KM_ERROR_MISSING_MAC_LENGTH;
diff --git a/km_openssl/kdf.cpp b/km_openssl/kdf.cpp
index e4ed135..ad0b68a 100644
--- a/km_openssl/kdf.cpp
+++ b/km_openssl/kdf.cpp
@@ -37,19 +37,16 @@
         return false;
     }
 
-    if (!secret || secret_len == 0)
-        return false;
+    if (!secret || secret_len == 0) return false;
 
     secret_key_len_ = secret_len;
     secret_key_.reset(dup_buffer(secret, secret_len));
-    if (!secret_key_.get())
-        return false;
+    if (!secret_key_.get()) return false;
 
     salt_len_ = salt_len;
     if (salt && salt_len > 0) {
         salt_.reset(dup_buffer(salt, salt_len));
-        if (!salt_.get())
-            return false;
+        if (!salt_.get()) return false;
     } else {
         salt_.reset();
     }
@@ -59,8 +56,7 @@
 }
 
 bool Kdf::Uint32ToBigEndianByteArray(uint32_t number, uint8_t* output) {
-    if (!output)
-        return false;
+    if (!output) return false;
 
     output[0] = (number >> 24) & 0xff;
     output[1] = (number >> 16) & 0xff;
diff --git a/km_openssl/openssl_err.cpp b/km_openssl/openssl_err.cpp
index 1391f40..73d1ad0 100644
--- a/km_openssl/openssl_err.cpp
+++ b/km_openssl/openssl_err.cpp
@@ -41,10 +41,12 @@
 #endif
 
 keymaster_error_t TranslateLastOpenSslError(bool log_message) {
-    unsigned long error = ERR_peek_last_error();
+    uint32_t error = ERR_peek_last_error();
 
     if (log_message) {
-        LOG_D("%s", ERR_error_string(error, nullptr));
+        char buf[128];
+        ERR_error_string_n(error, buf, sizeof(buf));
+        LOG_D("%s", buf);
     }
 
     int reason = ERR_GET_REASON(error);
diff --git a/km_openssl/openssl_utils.cpp b/km_openssl/openssl_utils.cpp
index 06cfafa..a0c0300 100644
--- a/km_openssl/openssl_utils.cpp
+++ b/km_openssl/openssl_utils.cpp
@@ -16,13 +16,15 @@
 
 #include <keymaster/km_openssl/openssl_utils.h>
 
-#include <openssl/rand.h>
 #include <keymaster/android_keymaster_utils.h>
+#include <openssl/rand.h>
 
 #include <keymaster/km_openssl/openssl_err.h>
 
 namespace keymaster {
 
+constexpr uint32_t kAffinePointLength = 32;
+
 keymaster_error_t ec_get_group_size(const EC_GROUP* group, size_t* key_size_bits) {
     switch (EC_GROUP_get_curve_name(group)) {
     case NID_secp224r1:
@@ -77,17 +79,14 @@
 keymaster_error_t convert_pkcs8_blob_to_evp(const uint8_t* key_data, size_t key_length,
                                             keymaster_algorithm_t expected_algorithm,
                                             UniquePtr<EVP_PKEY, EVP_PKEY_Delete>* pkey) {
-    if (key_data == nullptr || key_length <= 0)
-        return KM_ERROR_INVALID_KEY_BLOB;
+    if (key_data == nullptr || key_length <= 0) return KM_ERROR_INVALID_KEY_BLOB;
 
     UniquePtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete> pkcs8(
         d2i_PKCS8_PRIV_KEY_INFO(nullptr, &key_data, key_length));
-    if (pkcs8.get() == nullptr)
-        return TranslateLastOpenSslError(true /* log_message */);
+    if (pkcs8.get() == nullptr) return TranslateLastOpenSslError(true /* log_message */);
 
     pkey->reset(EVP_PKCS82PKEY(pkcs8.get()));
-    if (!pkey->get())
-        return TranslateLastOpenSslError(true /* log_message */);
+    if (!pkey->get()) return TranslateLastOpenSslError(true /* log_message */);
 
     if (EVP_PKEY_type((*pkey)->type) != convert_to_evp(expected_algorithm)) {
         LOG_E("EVP key algorithm was %d, not the expected %d", EVP_PKEY_type((*pkey)->type),
@@ -101,9 +100,8 @@
 keymaster_error_t KeyMaterialToEvpKey(keymaster_key_format_t key_format,
                                       const KeymasterKeyBlob& key_material,
                                       keymaster_algorithm_t expected_algorithm,
-                                      UniquePtr<EVP_PKEY, EVP_PKEY_Delete>* pkey) {
-    if (key_format != KM_KEY_FORMAT_PKCS8)
-        return KM_ERROR_UNSUPPORTED_KEY_FORMAT;
+                                      EVP_PKEY_Ptr* pkey) {
+    if (key_format != KM_KEY_FORMAT_PKCS8) return KM_ERROR_UNSUPPORTED_KEY_FORMAT;
 
     return convert_pkcs8_blob_to_evp(key_material.key_material, key_material.key_material_size,
                                      expected_algorithm, pkey);
@@ -111,11 +109,9 @@
 
 keymaster_error_t EvpKeyToKeyMaterial(const EVP_PKEY* pkey, KeymasterKeyBlob* key_blob) {
     int key_data_size = i2d_PrivateKey(pkey, nullptr /* key_data*/);
-    if (key_data_size <= 0)
-        return TranslateLastOpenSslError();
+    if (key_data_size <= 0) return TranslateLastOpenSslError();
 
-    if (!key_blob->Reset(key_data_size))
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!key_blob->Reset(key_data_size)) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
     uint8_t* tmp = key_blob->writable_data();
     i2d_PrivateKey(pkey, &tmp);
@@ -123,6 +119,43 @@
     return KM_ERROR_OK;
 }
 
+// Remote provisioning helper function
+keymaster_error_t GetEcdsa256KeyFromCert(const keymaster_blob_t* km_cert, uint8_t* x_coord,
+                                         size_t x_length, uint8_t* y_coord, size_t y_length) {
+    if (km_cert == nullptr || x_coord == nullptr || y_coord == nullptr) {
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+    }
+    if (x_length != kAffinePointLength || y_length != kAffinePointLength) {
+        return KM_ERROR_INVALID_ARGUMENT;
+    }
+    const uint8_t* temp = km_cert->data;
+    X509_Ptr cert(d2i_X509(NULL, &temp, km_cert->data_length));
+    if (!cert.get()) return TranslateLastOpenSslError();
+    EVP_PKEY_Ptr pubKey(X509_get_pubkey(cert.get()));
+    if (!pubKey.get()) return TranslateLastOpenSslError();
+    EC_KEY* ecKey = EVP_PKEY_get0_EC_KEY(pubKey.get());
+    if (!ecKey) return TranslateLastOpenSslError();
+    const EC_POINT* jacobian_coords = EC_KEY_get0_public_key(ecKey);
+    if (!jacobian_coords) return TranslateLastOpenSslError();
+    bssl::UniquePtr<BIGNUM> x(BN_new());
+    bssl::UniquePtr<BIGNUM> y(BN_new());
+    BN_CTX_Ptr ctx(BN_CTX_new());
+    if (!ctx.get()) return TranslateLastOpenSslError();
+    if (!EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ecKey), jacobian_coords, x.get(),
+                                             y.get(), ctx.get())) {
+        return TranslateLastOpenSslError();
+    }
+    uint8_t* tmp_x = x_coord;
+    if (BN_bn2binpad(x.get(), tmp_x, kAffinePointLength) != kAffinePointLength) {
+        return TranslateLastOpenSslError();
+    }
+    uint8_t* tmp_y = y_coord;
+    if (BN_bn2binpad(y.get(), tmp_y, kAffinePointLength) != kAffinePointLength) {
+        return TranslateLastOpenSslError();
+    }
+    return KM_ERROR_OK;
+}
+
 size_t ec_group_size_bits(EC_KEY* ec_key) {
     const EC_GROUP* group = EC_KEY_get0_group(ec_key);
     UniquePtr<BN_CTX, BN_CTX_Delete> bn_ctx(BN_CTX_new());
@@ -135,8 +168,7 @@
 }
 
 keymaster_error_t GenerateRandom(uint8_t* buf, size_t length) {
-    if (RAND_bytes(buf, length) != 1)
-        return KM_ERROR_UNKNOWN_ERROR;
+    if (RAND_bytes(buf, length) != 1) return KM_ERROR_UNKNOWN_ERROR;
     return KM_ERROR_OK;
 }
 
diff --git a/km_openssl/rsa_key.cpp b/km_openssl/rsa_key.cpp
index 8b5b6ae..154fe1b 100644
--- a/km_openssl/rsa_key.cpp
+++ b/km_openssl/rsa_key.cpp
@@ -34,6 +34,9 @@
 
 bool RsaKey::SupportedMode(keymaster_purpose_t purpose, keymaster_padding_t padding) {
     switch (purpose) {
+    case KM_PURPOSE_ATTEST_KEY:
+        return true;
+
     case KM_PURPOSE_SIGN:
     case KM_PURPOSE_VERIFY:
         return padding == KM_PAD_NONE || padding == KM_PAD_RSA_PSS ||
@@ -45,6 +48,7 @@
         return padding == KM_PAD_RSA_OAEP || padding == KM_PAD_RSA_PKCS1_1_5_ENCRYPT;
 
     case KM_PURPOSE_DERIVE_KEY:
+    case KM_PURPOSE_AGREE_KEY:
         return false;
     };
     return false;
@@ -52,6 +56,9 @@
 
 bool RsaKey::SupportedMode(keymaster_purpose_t purpose, keymaster_digest_t digest) {
     switch (purpose) {
+    case KM_PURPOSE_ATTEST_KEY:
+        return true;
+
     case KM_PURPOSE_SIGN:
     case KM_PURPOSE_VERIFY:
         return digest == KM_DIGEST_NONE || digest == KM_DIGEST_SHA_2_256;
@@ -63,6 +70,7 @@
         break;
 
     case KM_PURPOSE_DERIVE_KEY:
+    case KM_PURPOSE_AGREE_KEY:
         return false;
     };
     return true;
diff --git a/km_openssl/rsa_key_factory.cpp b/km_openssl/rsa_key_factory.cpp
index 05029bb..114fdab 100644
--- a/km_openssl/rsa_key_factory.cpp
+++ b/km_openssl/rsa_key_factory.cpp
@@ -21,7 +21,6 @@
 #include <keymaster/km_openssl/openssl_utils.h>
 #include <keymaster/km_openssl/rsa_key.h>
 #include <keymaster/km_openssl/rsa_operation.h>
-#include <keymaster/new.h>
 
 namespace keymaster {
 
@@ -50,16 +49,16 @@
 }
 
 keymaster_error_t RsaKeyFactory::GenerateKey(const AuthorizationSet& key_description,
+                                             UniquePtr<Key> attest_key,  //
+                                             const KeymasterBlob& issuer_subject,
                                              KeymasterKeyBlob* key_blob,
                                              AuthorizationSet* hw_enforced,
-                                             AuthorizationSet* sw_enforced) const {
-    if (!key_blob || !hw_enforced || !sw_enforced)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
-
-    const AuthorizationSet& authorizations(key_description);
+                                             AuthorizationSet* sw_enforced,
+                                             CertificateChain* cert_chain) const {
+    if (!key_blob || !hw_enforced || !sw_enforced) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     uint64_t public_exponent;
-    if (!authorizations.GetTagValue(TAG_RSA_PUBLIC_EXPONENT, &public_exponent)) {
+    if (!key_description.GetTagValue(TAG_RSA_PUBLIC_EXPONENT, &public_exponent)) {
         LOG_E("No public exponent specified for RSA key generation", 0);
         return KM_ERROR_INVALID_ARGUMENT;
     }
@@ -69,7 +68,7 @@
     }
 
     uint32_t key_size;
-    if (!authorizations.GetTagValue(TAG_KEY_SIZE, &key_size)) {
+    if (!key_description.GetTagValue(TAG_KEY_SIZE, &key_size)) {
         LOG_E("No key size specified for RSA key generation", 0);
         return KM_ERROR_UNSUPPORTED_KEY_SIZE;
     }
@@ -78,36 +77,56 @@
         return KM_ERROR_UNSUPPORTED_KEY_SIZE;
     }
 
-    UniquePtr<BIGNUM, BIGNUM_Delete> exponent(BN_new());
-    UniquePtr<RSA, RsaKey::RSA_Delete> rsa_key(RSA_new());
-    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new());
-    if (exponent.get() == nullptr || rsa_key.get() == nullptr || pkey.get() == nullptr)
+    BIGNUM_Ptr exponent(BN_new());
+    RSA_Ptr rsa_key(RSA_new());
+    EVP_PKEY_Ptr pkey(EVP_PKEY_new());
+    if (exponent.get() == nullptr || rsa_key.get() == nullptr || pkey.get() == nullptr) {
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
 
     if (!BN_set_word(exponent.get(), public_exponent) ||
         !RSA_generate_key_ex(rsa_key.get(), key_size, exponent.get(), nullptr /* callback */))
         return TranslateLastOpenSslError();
 
-    if (EVP_PKEY_set1_RSA(pkey.get(), rsa_key.get()) != 1)
-        return TranslateLastOpenSslError();
+    if (EVP_PKEY_set1_RSA(pkey.get(), rsa_key.get()) != 1) return TranslateLastOpenSslError();
 
     KeymasterKeyBlob key_material;
     keymaster_error_t error = EvpKeyToKeyMaterial(pkey.get(), &key_material);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
-    return blob_maker_.CreateKeyBlob(authorizations, KM_ORIGIN_GENERATED, key_material, key_blob,
-                                     hw_enforced, sw_enforced);
+    error = blob_maker_.CreateKeyBlob(key_description, KM_ORIGIN_GENERATED, key_material, key_blob,
+                                      hw_enforced, sw_enforced);
+    if (error != KM_ERROR_OK) return error;
+
+    if (context_.GetKmVersion() < KmVersion::KEYMINT_1) return KM_ERROR_OK;
+    if (!cert_chain) return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    RsaKey key(*hw_enforced, *sw_enforced, this, move(rsa_key));
+    if (key_description.Contains(TAG_ATTESTATION_CHALLENGE)) {
+        *cert_chain = context_.GenerateAttestation(key, key_description, move(attest_key),
+                                                   issuer_subject, &error);
+    } else if (attest_key.get() != nullptr) {
+        return KM_ERROR_ATTESTATION_CHALLENGE_MISSING;
+    } else {
+        bool fake_signature =
+            key_size < 1024 || !key_description.Contains(TAG_PURPOSE, KM_PURPOSE_SIGN);
+        *cert_chain =
+            context_.GenerateSelfSignedCertificate(key, key_description, fake_signature, &error);
+    }
+
+    return error;
 }
 
-keymaster_error_t RsaKeyFactory::ImportKey(const AuthorizationSet& key_description,
+keymaster_error_t RsaKeyFactory::ImportKey(const AuthorizationSet& key_description,  //
                                            keymaster_key_format_t input_key_material_format,
                                            const KeymasterKeyBlob& input_key_material,
+                                           UniquePtr<Key> attest_key,  //
+                                           const KeymasterBlob& issuer_subject,
                                            KeymasterKeyBlob* output_key_blob,
                                            AuthorizationSet* hw_enforced,
-                                           AuthorizationSet* sw_enforced) const {
-    if (!output_key_blob || !hw_enforced || !sw_enforced)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+                                           AuthorizationSet* sw_enforced,
+                                           CertificateChain* cert_chain) const {
+    if (!output_key_blob || !hw_enforced || !sw_enforced) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     AuthorizationSet authorizations;
     uint64_t public_exponent;
@@ -115,10 +134,35 @@
     keymaster_error_t error =
         UpdateImportKeyDescription(key_description, input_key_material_format, input_key_material,
                                    &authorizations, &public_exponent, &key_size);
-    if (error != KM_ERROR_OK)
-        return error;
-    return blob_maker_.CreateKeyBlob(authorizations, KM_ORIGIN_IMPORTED, input_key_material,
-                                     output_key_blob, hw_enforced, sw_enforced);
+    if (error != KM_ERROR_OK) return error;
+    error = blob_maker_.CreateKeyBlob(authorizations, KM_ORIGIN_IMPORTED, input_key_material,
+                                      output_key_blob, hw_enforced, sw_enforced);
+    if (error != KM_ERROR_OK) return error;
+
+    if (context_.GetKmVersion() < KmVersion::KEYMINT_1) return KM_ERROR_OK;
+    if (!cert_chain) return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    EVP_PKEY_Ptr pkey;
+    error = KeyMaterialToEvpKey(KM_KEY_FORMAT_PKCS8, input_key_material, KM_ALGORITHM_RSA, &pkey);
+    if (error != KM_ERROR_OK) return error;
+
+    RSA_Ptr rsa_key(EVP_PKEY_get1_RSA(pkey.get()));
+    if (!rsa_key.get()) return KM_ERROR_INVALID_ARGUMENT;
+
+    RsaKey key(*hw_enforced, *sw_enforced, this, move(rsa_key));
+    if (key_description.Contains(KM_TAG_ATTESTATION_CHALLENGE)) {
+        *cert_chain = context_.GenerateAttestation(key, key_description, move(attest_key),
+                                                   issuer_subject, &error);
+    } else if (attest_key.get() != nullptr) {
+        return KM_ERROR_ATTESTATION_CHALLENGE_MISSING;
+    } else {
+        bool fake_signature =
+            key_size < 1024 || !key_description.Contains(TAG_PURPOSE, KM_PURPOSE_SIGN);
+        *cert_chain =
+            context_.GenerateSelfSignedCertificate(key, key_description, fake_signature, &error);
+    }
+
+    return error;
 }
 
 keymaster_error_t RsaKeyFactory::UpdateImportKeyDescription(const AuthorizationSet& key_description,
@@ -130,21 +174,18 @@
     if (!updated_description || !public_exponent || !key_size)
         return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
-    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey;
+    EVP_PKEY_Ptr pkey;
     keymaster_error_t error =
         KeyMaterialToEvpKey(key_format, key_material, keymaster_key_type(), &pkey);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
-    UniquePtr<RSA, RsaKey::RSA_Delete> rsa_key(EVP_PKEY_get1_RSA(pkey.get()));
-    if (!rsa_key.get())
-        return TranslateLastOpenSslError();
+    RSA_Ptr rsa_key(EVP_PKEY_get1_RSA(pkey.get()));
+    if (!rsa_key.get()) return TranslateLastOpenSslError();
 
     updated_description->Reinitialize(key_description);
 
     *public_exponent = BN_get_word(rsa_key->e);
-    if (*public_exponent == 0xffffffffL)
-        return KM_ERROR_INVALID_KEY_BLOB;
+    if (*public_exponent == 0xffffffffL) return KM_ERROR_INVALID_KEY_BLOB;
     if (!updated_description->GetTagValue(TAG_RSA_PUBLIC_EXPONENT, public_exponent))
         updated_description->push_back(TAG_RSA_PUBLIC_EXPONENT, *public_exponent);
     if (*public_exponent != BN_get_word(rsa_key->e)) {
@@ -165,8 +206,7 @@
     keymaster_algorithm_t algorithm = KM_ALGORITHM_RSA;
     if (!updated_description->GetTagValue(TAG_ALGORITHM, &algorithm))
         updated_description->push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
-    if (algorithm != KM_ALGORITHM_RSA)
-        return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
+    if (algorithm != KM_ALGORITHM_RSA) return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
 
     return KM_ERROR_OK;
 }
diff --git a/km_openssl/rsa_operation.cpp b/km_openssl/rsa_operation.cpp
index 3e3e082..313afe9 100644
--- a/km_openssl/rsa_operation.cpp
+++ b/km_openssl/rsa_operation.cpp
@@ -24,7 +24,6 @@
 #include <keymaster/km_openssl/openssl_utils.h>
 #include <keymaster/km_openssl/rsa_key.h>
 #include <keymaster/logger.h>
-#include <keymaster/new.h>
 
 namespace keymaster {
 
@@ -35,8 +34,8 @@
 const size_t kPkcs1UndigestedSignaturePaddingOverhead = 11;
 
 /* static */
-EVP_PKEY* RsaOperationFactory::GetRsaKey(Key&& key, keymaster_error_t* error) {
-    const RsaKey& rsa_key = static_cast<RsaKey&>(key);
+EVP_PKEY* RsaOperationFactory::GetRsaKey(const Key& key, keymaster_error_t* error) {
+    const RsaKey& rsa_key = static_cast<const RsaKey&>(key);
     if (!rsa_key.key()) {
         *error = KM_ERROR_UNKNOWN_ERROR;
         return nullptr;
@@ -74,7 +73,7 @@
         return nullptr;
     }
 
-    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> rsa(GetRsaKey(move(key), error));
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> rsa(GetRsaKey(key, error));
     if (!rsa.get()) return nullptr;
 
     RsaOperation* op = InstantiateOperation(key.hw_enforced_move(), key.sw_enforced_move(), digest,
@@ -94,6 +93,10 @@
 RsaOperation* RsaCryptingOperationFactory::CreateRsaOperation(Key&& key,
                                                               const AuthorizationSet& begin_params,
                                                               keymaster_error_t* error) {
+    keymaster_digest_t mgf_digest = KM_DIGEST_NONE;
+    key.authorizations().GetTagValue(TAG_RSA_OAEP_MGF_DIGEST, &mgf_digest);
+    *error = GetAndValidateMgfDigest(begin_params, key, &mgf_digest);
+    if (*error != KM_ERROR_OK) return nullptr;
     UniquePtr<RsaOperation> op(
         RsaOperationFactory::CreateRsaOperation(move(key), begin_params, error));
     if (op.get()) {
@@ -111,6 +114,7 @@
                 *error = KM_ERROR_INCOMPATIBLE_DIGEST;
                 return nullptr;
             }
+            static_cast<RsaCryptOperation*>(op.get())->setOaepMgfDigest(mgf_digest);
             break;
 
         default:
@@ -121,6 +125,35 @@
     return op.release();
 }
 
+keymaster_error_t RsaCryptingOperationFactory::GetAndValidateMgfDigest(
+    const AuthorizationSet& begin_params, const Key& key, keymaster_digest_t* digest) const {
+    *digest = KM_DIGEST_SHA1;
+    if (!begin_params.Contains(TAG_PADDING, KM_PAD_RSA_OAEP)) {
+        *digest = KM_DIGEST_NONE;
+        return KM_ERROR_OK;
+    }
+    // If begin params does not specify any mgf digest
+    if (!begin_params.GetTagValue(TAG_RSA_OAEP_MGF_DIGEST, digest)) {
+        // And the authorizations has MGF Digest tag specified.
+        if (key.authorizations().GetTagCount(TAG_RSA_OAEP_MGF_DIGEST) > 0) {
+            // And key authorizations does not contain SHA1 for Mgf digest.
+            if (!key.authorizations().Contains(TAG_RSA_OAEP_MGF_DIGEST, KM_DIGEST_SHA1)) {
+                // Then it is an error.
+                LOG_E("%d MGF digests specified in begin params and SHA1 not authorized",
+                      begin_params.GetTagCount(TAG_RSA_OAEP_MGF_DIGEST));
+                return KM_ERROR_UNSUPPORTED_MGF_DIGEST;
+            }
+        }
+    } else if (!supported(*digest) || (*digest == KM_DIGEST_NONE)) {
+        LOG_E("MGF Digest %d not supported", *digest);
+        return KM_ERROR_UNSUPPORTED_MGF_DIGEST;
+    } else if (!key.authorizations().Contains(TAG_RSA_OAEP_MGF_DIGEST, *digest)) {
+        LOG_E("MGF Digest %d was specified, but not authorized by key", *digest);
+        return KM_ERROR_INCOMPATIBLE_MGF_DIGEST;
+    }
+    return KM_ERROR_OK;
+}
+
 static const keymaster_padding_t supported_crypt_padding[] = {KM_PAD_NONE, KM_PAD_RSA_OAEP,
                                                               KM_PAD_RSA_PKCS1_1_5_ENCRYPT};
 const keymaster_padding_t*
@@ -130,8 +163,7 @@
 }
 
 RsaOperation::~RsaOperation() {
-    if (rsa_key_ != nullptr)
-        EVP_PKEY_free(rsa_key_);
+    if (rsa_key_ != nullptr) EVP_PKEY_free(rsa_key_);
 }
 
 keymaster_error_t RsaOperation::Begin(const AuthorizationSet& /* input_params */,
@@ -161,8 +193,7 @@
 keymaster_error_t RsaOperation::StoreData(const Buffer& input, size_t* input_consumed) {
     assert(input_consumed);
 
-    if (!data_.reserve(EVP_PKEY_size(rsa_key_)))
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!data_.reserve(EVP_PKEY_size(rsa_key_))) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
     // If the write fails, it's because input length exceeds key size.
     if (!data_.write(input.peek_read(), input.available_read())) {
         LOG_E("Input too long: cannot operate on %u bytes of data with %u-byte RSA key",
@@ -177,8 +208,7 @@
 keymaster_error_t RsaOperation::SetRsaPaddingInEvpContext(EVP_PKEY_CTX* pkey_ctx, bool signing) {
     keymaster_error_t error;
     int openssl_padding = GetOpensslPadding(&error);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, openssl_padding) <= 0)
         return TranslateLastOpenSslError();
@@ -196,35 +226,14 @@
 
 keymaster_error_t RsaOperation::InitDigest() {
     if (digest_ == KM_DIGEST_NONE) {
-        if (require_digest())
-            return KM_ERROR_INCOMPATIBLE_DIGEST;
+        if (require_digest()) return KM_ERROR_INCOMPATIBLE_DIGEST;
         return KM_ERROR_OK;
     }
-
-    switch (digest_) {
-    case KM_DIGEST_NONE:
-        return KM_ERROR_OK;
-    case KM_DIGEST_MD5:
-        digest_algorithm_ = EVP_md5();
-        return KM_ERROR_OK;
-    case KM_DIGEST_SHA1:
-        digest_algorithm_ = EVP_sha1();
-        return KM_ERROR_OK;
-    case KM_DIGEST_SHA_2_224:
-        digest_algorithm_ = EVP_sha224();
-        return KM_ERROR_OK;
-    case KM_DIGEST_SHA_2_256:
-        digest_algorithm_ = EVP_sha256();
-        return KM_ERROR_OK;
-    case KM_DIGEST_SHA_2_384:
-        digest_algorithm_ = EVP_sha384();
-        return KM_ERROR_OK;
-    case KM_DIGEST_SHA_2_512:
-        digest_algorithm_ = EVP_sha512();
-        return KM_ERROR_OK;
-    default:
+    digest_algorithm_ = KmDigestToEvpDigest(digest_);
+    if (digest_algorithm_ == nullptr) {
         return KM_ERROR_UNSUPPORTED_DIGEST;
     }
+    return KM_ERROR_OK;
 }
 
 RsaDigestingOperation::RsaDigestingOperation(AuthorizationSet&& hw_enforced,
@@ -266,11 +275,9 @@
 keymaster_error_t RsaSignOperation::Begin(const AuthorizationSet& input_params,
                                           AuthorizationSet* output_params) {
     keymaster_error_t error = RsaDigestingOperation::Begin(input_params, output_params);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
-    if (digest_ == KM_DIGEST_NONE)
-        return KM_ERROR_OK;
+    if (digest_ == KM_DIGEST_NONE) return KM_ERROR_OK;
 
     EVP_PKEY_CTX* pkey_ctx;
     if (EVP_DigestSignInit(&digest_ctx_, &pkey_ctx, digest_algorithm_, nullptr /* engine */,
@@ -299,8 +306,7 @@
     assert(output);
 
     keymaster_error_t error = UpdateForFinish(additional_params, input);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     if (digest_ == KM_DIGEST_NONE)
         return SignUndigested(output);
@@ -311,25 +317,21 @@
 static keymaster_error_t zero_pad_left(UniquePtr<uint8_t[]>* dest, size_t padded_len, Buffer& src) {
     assert(padded_len > src.available_read());
 
-    dest->reset(new(std::nothrow) uint8_t[padded_len]);
-    if (!dest->get())
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    dest->reset(new (std::nothrow) uint8_t[padded_len]);
+    if (!dest->get()) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
     size_t padding_len = padded_len - src.available_read();
     memset(dest->get(), 0, padding_len);
-    if (!src.read(dest->get() + padding_len, src.available_read()))
-        return KM_ERROR_UNKNOWN_ERROR;
+    if (!src.read(dest->get() + padding_len, src.available_read())) return KM_ERROR_UNKNOWN_ERROR;
 
     return KM_ERROR_OK;
 }
 
 keymaster_error_t RsaSignOperation::SignUndigested(Buffer* output) {
     UniquePtr<RSA, RSA_Delete> rsa(EVP_PKEY_get1_RSA(const_cast<EVP_PKEY*>(rsa_key_)));
-    if (!rsa.get())
-        return TranslateLastOpenSslError();
+    if (!rsa.get()) return TranslateLastOpenSslError();
 
-    if (!output->Reinitialize(RSA_size(rsa.get())))
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!output->Reinitialize(RSA_size(rsa.get()))) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
     size_t key_len = EVP_PKEY_size(rsa_key_);
     int bytes_encrypted;
@@ -341,8 +343,7 @@
             return KM_ERROR_INVALID_INPUT_LENGTH;
         } else if (data_.available_read() < key_len) {
             keymaster_error_t error = zero_pad_left(&zero_padded, key_len, data_);
-            if (error != KM_ERROR_OK)
-                return error;
+            if (error != KM_ERROR_OK) return error;
             to_encrypt = zero_padded.get();
         }
         bytes_encrypted = RSA_private_encrypt(key_len, to_encrypt, output->peek_write(), rsa.get(),
@@ -364,10 +365,8 @@
         return KM_ERROR_UNSUPPORTED_PADDING_MODE;
     }
 
-    if (bytes_encrypted <= 0)
-        return TranslateLastOpenSslError();
-    if (!output->advance_write(bytes_encrypted))
-        return KM_ERROR_UNKNOWN_ERROR;
+    if (bytes_encrypted <= 0) return TranslateLastOpenSslError();
+    if (!output->advance_write(bytes_encrypted)) return KM_ERROR_UNKNOWN_ERROR;
     return KM_ERROR_OK;
 }
 
@@ -376,13 +375,11 @@
     if (EVP_DigestSignFinal(&digest_ctx_, nullptr /* signature */, &siglen) != 1)
         return TranslateLastOpenSslError();
 
-    if (!output->Reinitialize(siglen))
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!output->Reinitialize(siglen)) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
     if (EVP_DigestSignFinal(&digest_ctx_, output->peek_write(), &siglen) <= 0)
         return TranslateLastOpenSslError();
-    if (!output->advance_write(siglen))
-        return KM_ERROR_UNKNOWN_ERROR;
+    if (!output->advance_write(siglen)) return KM_ERROR_UNKNOWN_ERROR;
 
     return KM_ERROR_OK;
 }
@@ -390,11 +387,9 @@
 keymaster_error_t RsaVerifyOperation::Begin(const AuthorizationSet& input_params,
                                             AuthorizationSet* output_params) {
     keymaster_error_t error = RsaDigestingOperation::Begin(input_params, output_params);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
-    if (digest_ == KM_DIGEST_NONE)
-        return KM_ERROR_OK;
+    if (digest_ == KM_DIGEST_NONE) return KM_ERROR_OK;
 
     EVP_PKEY_CTX* pkey_ctx;
     if (EVP_DigestVerifyInit(&digest_ctx_, &pkey_ctx, digest_algorithm_, nullptr, rsa_key_) != 1)
@@ -421,8 +416,7 @@
                                              AuthorizationSet* /* output_params */,
                                              Buffer* /* output */) {
     keymaster_error_t error = UpdateForFinish(additional_params, input);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     if (digest_ == KM_DIGEST_NONE)
         return VerifyUndigested(signature);
@@ -432,17 +426,14 @@
 
 keymaster_error_t RsaVerifyOperation::VerifyUndigested(const Buffer& signature) {
     UniquePtr<RSA, RSA_Delete> rsa(EVP_PKEY_get1_RSA(const_cast<EVP_PKEY*>(rsa_key_)));
-    if (!rsa.get())
-        return KM_ERROR_UNKNOWN_ERROR;
+    if (!rsa.get()) return KM_ERROR_UNKNOWN_ERROR;
 
     size_t key_len = RSA_size(rsa.get());
     int openssl_padding;
     switch (padding_) {
     case KM_PAD_NONE:
-        if (data_.available_read() > key_len)
-            return KM_ERROR_INVALID_INPUT_LENGTH;
-        if (key_len != signature.available_read())
-            return KM_ERROR_VERIFICATION_FAILED;
+        if (data_.available_read() > key_len) return KM_ERROR_INVALID_INPUT_LENGTH;
+        if (key_len != signature.available_read()) return KM_ERROR_VERIFICATION_FAILED;
         openssl_padding = RSA_NO_PADDING;
         break;
     case KM_PAD_RSA_PKCS1_1_5_SIGN:
@@ -458,12 +449,10 @@
     }
 
     UniquePtr<uint8_t[]> decrypted_data(new (std::nothrow) uint8_t[key_len]);
-    if (!decrypted_data.get())
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!decrypted_data.get()) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
     int bytes_decrypted = RSA_public_decrypt(signature.available_read(), signature.peek_read(),
                                              decrypted_data.get(), rsa.get(), openssl_padding);
-    if (bytes_decrypted < 0)
-        return KM_ERROR_VERIFICATION_FAILED;
+    if (bytes_decrypted < 0) return KM_ERROR_VERIFICATION_FAILED;
 
     const uint8_t* compare_pos = decrypted_data.get();
     size_t bytes_to_compare = bytes_decrypted;
@@ -489,20 +478,27 @@
 }
 
 keymaster_error_t RsaCryptOperation::SetOaepDigestIfRequired(EVP_PKEY_CTX* pkey_ctx) {
-    if (padding() != KM_PAD_RSA_OAEP)
-        return KM_ERROR_OK;
+    if (padding() != KM_PAD_RSA_OAEP) return KM_ERROR_OK;
 
     assert(digest_algorithm_ != nullptr);
-    if (!EVP_PKEY_CTX_set_rsa_oaep_md(pkey_ctx, digest_algorithm_))
+    if (!EVP_PKEY_CTX_set_rsa_oaep_md(pkey_ctx, digest_algorithm_)) {
         return TranslateLastOpenSslError();
-
+    }
+    assert(mgf_digest_algorithm_ != nullptr);
     // MGF1 MD is always SHA1.
-    if (!EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, EVP_sha1()))
+    if (!EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf_digest_algorithm_)) {
         return TranslateLastOpenSslError();
-
+    }
     return KM_ERROR_OK;
 }
 
+keymaster_error_t RsaCryptOperation::Begin(const AuthorizationSet& input_params,
+                                           AuthorizationSet* output_params) {
+    keymaster_error_t error = RsaOperation::Begin(input_params, output_params);
+    if (error != KM_ERROR_OK) return error;
+    return InitMgfDigest();
+}
+
 int RsaCryptOperation::GetOpensslPadding(keymaster_error_t* error) {
     *error = KM_ERROR_OK;
     switch (padding_) {
@@ -517,59 +513,56 @@
     }
 }
 
-struct EVP_PKEY_CTX_Delete {
-    void operator()(EVP_PKEY_CTX* p) { EVP_PKEY_CTX_free(p); }
-};
+keymaster_error_t RsaCryptOperation::InitMgfDigest() {
+    if (mgf_digest_ == KM_DIGEST_NONE) {
+        return KM_ERROR_OK;
+    }
+    mgf_digest_algorithm_ = KmDigestToEvpDigest(mgf_digest_);
+    if (mgf_digest_algorithm_ == nullptr) {
+        return KM_ERROR_UNSUPPORTED_DIGEST;
+    }
+    return KM_ERROR_OK;
+}
 
 keymaster_error_t RsaEncryptOperation::Finish(const AuthorizationSet& additional_params,
                                               const Buffer& input, const Buffer& /* signature */,
                                               AuthorizationSet* /* output_params */,
                                               Buffer* output) {
-    if (!output)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    if (!output) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     keymaster_error_t error = UpdateForFinish(additional_params, input);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
-    UniquePtr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(
-        EVP_PKEY_CTX_new(rsa_key_, nullptr /* engine */));
-    if (!ctx.get())
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    EVP_PKEY_CTX_Ptr ctx(EVP_PKEY_CTX_new(rsa_key_, nullptr /* engine */));
+    if (!ctx.get()) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
-    if (EVP_PKEY_encrypt_init(ctx.get()) <= 0)
-        return TranslateLastOpenSslError();
+    if (EVP_PKEY_encrypt_init(ctx.get()) <= 0) return TranslateLastOpenSslError();
 
     error = SetRsaPaddingInEvpContext(ctx.get(), false /* signing */);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
     error = SetOaepDigestIfRequired(ctx.get());
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     size_t outlen;
     if (EVP_PKEY_encrypt(ctx.get(), nullptr /* out */, &outlen, data_.peek_read(),
                          data_.available_read()) <= 0)
         return TranslateLastOpenSslError();
 
-    if (!output->Reinitialize(outlen))
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!output->Reinitialize(outlen)) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
     const uint8_t* to_encrypt = data_.peek_read();
     size_t to_encrypt_len = data_.available_read();
     UniquePtr<uint8_t[]> zero_padded;
     if (padding_ == KM_PAD_NONE && to_encrypt_len < outlen) {
         keymaster_error_t error = zero_pad_left(&zero_padded, outlen, data_);
-        if (error != KM_ERROR_OK)
-            return error;
+        if (error != KM_ERROR_OK) return error;
         to_encrypt = zero_padded.get();
         to_encrypt_len = outlen;
     }
 
     if (EVP_PKEY_encrypt(ctx.get(), output->peek_write(), &outlen, to_encrypt, to_encrypt_len) <= 0)
         return TranslateLastOpenSslError();
-    if (!output->advance_write(outlen))
-        return KM_ERROR_UNKNOWN_ERROR;
+    if (!output->advance_write(outlen)) return KM_ERROR_UNKNOWN_ERROR;
 
     return KM_ERROR_OK;
 }
@@ -578,51 +571,41 @@
                                               const Buffer& input, const Buffer& /* signature */,
                                               AuthorizationSet* /* output_params */,
                                               Buffer* output) {
-    if (!output)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    if (!output) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     keymaster_error_t error = UpdateForFinish(additional_params, input);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
-    UniquePtr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(
-        EVP_PKEY_CTX_new(rsa_key_, nullptr /* engine */));
-    if (!ctx.get())
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    EVP_PKEY_CTX_Ptr ctx(EVP_PKEY_CTX_new(rsa_key_, nullptr /* engine */));
+    if (!ctx.get()) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
-    if (EVP_PKEY_decrypt_init(ctx.get()) <= 0)
-        return TranslateLastOpenSslError();
+    if (EVP_PKEY_decrypt_init(ctx.get()) <= 0) return TranslateLastOpenSslError();
 
     error = SetRsaPaddingInEvpContext(ctx.get(), false /* signing */);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
     error = SetOaepDigestIfRequired(ctx.get());
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     size_t outlen;
     if (EVP_PKEY_decrypt(ctx.get(), nullptr /* out */, &outlen, data_.peek_read(),
                          data_.available_read()) <= 0)
         return TranslateLastOpenSslError();
 
-    if (!output->Reinitialize(outlen))
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!output->Reinitialize(outlen)) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
     const uint8_t* to_decrypt = data_.peek_read();
     size_t to_decrypt_len = data_.available_read();
     UniquePtr<uint8_t[]> zero_padded;
     if (padding_ == KM_PAD_NONE && to_decrypt_len < outlen) {
         keymaster_error_t error = zero_pad_left(&zero_padded, outlen, data_);
-        if (error != KM_ERROR_OK)
-            return error;
+        if (error != KM_ERROR_OK) return error;
         to_decrypt = zero_padded.get();
         to_decrypt_len = outlen;
     }
 
     if (EVP_PKEY_decrypt(ctx.get(), output->peek_write(), &outlen, to_decrypt, to_decrypt_len) <= 0)
         return TranslateLastOpenSslError();
-    if (!output->advance_write(outlen))
-        return KM_ERROR_UNKNOWN_ERROR;
+    if (!output->advance_write(outlen)) return KM_ERROR_UNKNOWN_ERROR;
 
     return KM_ERROR_OK;
 }
diff --git a/km_openssl/soft_keymaster_enforcement.cpp b/km_openssl/soft_keymaster_enforcement.cpp
index cc8bac9..0a3c2f6 100644
--- a/km_openssl/soft_keymaster_enforcement.cpp
+++ b/km_openssl/soft_keymaster_enforcement.cpp
@@ -181,7 +181,7 @@
     // is an acceptable implementation strategy for production use as well.  Additional verification
     // need only be provided by an implementation if it is interoperating with another
     // implementation that requires more.
-    VerifyAuthorizationResponse response;
+    VerifyAuthorizationResponse response(request.message_version);
     response.token.challenge = request.challenge;
     response.token.timestamp = get_current_time_ms();
     response.token.security_level = SecurityLevel();
@@ -197,4 +197,16 @@
     return response;
 }
 
+keymaster_error_t SoftKeymasterEnforcement::GenerateTimestampToken(TimestampToken* token) {
+    token->timestamp = get_current_time_ms();
+    token->security_level = SecurityLevel();
+    keymaster_blob_t data_chunks[] = {
+        toBlob(kAuthVerificationLabel),
+        toBlob(token->challenge),
+        toBlob(token->timestamp),
+        toBlob(token->security_level),
+    };
+    return hmacSha256(hmac_key_, data_chunks, 4, &token->mac);
+}
+
 }  // namespace keymaster
diff --git a/km_openssl/software_random_source.cpp b/km_openssl/software_random_source.cpp
index fe49cc7..48238b9 100644
--- a/km_openssl/software_random_source.cpp
+++ b/km_openssl/software_random_source.cpp
@@ -21,9 +21,8 @@
 namespace keymaster {
 
 keymaster_error_t SoftwareRandomSource::GenerateRandom(uint8_t* buffer, size_t length) const {
-    if (RAND_bytes(buffer, length) != 1)
-        return KM_ERROR_UNKNOWN_ERROR;
+    if (RAND_bytes(buffer, length) != 1) return KM_ERROR_UNKNOWN_ERROR;
     return KM_ERROR_OK;
 }
 
-}
+}  // namespace keymaster
diff --git a/km_openssl/symmetric_key.cpp b/km_openssl/symmetric_key.cpp
index 2ef7d9e..1b89d66 100644
--- a/km_openssl/symmetric_key.cpp
+++ b/km_openssl/symmetric_key.cpp
@@ -31,11 +31,13 @@
 namespace keymaster {
 
 keymaster_error_t SymmetricKeyFactory::GenerateKey(const AuthorizationSet& key_description,
+                                                   UniquePtr<Key> /* attest_key */,
+                                                   const KeymasterBlob& /* issuer_subject */,
                                                    KeymasterKeyBlob* key_blob,
                                                    AuthorizationSet* hw_enforced,
-                                                   AuthorizationSet* sw_enforced) const {
-    if (!key_blob || !hw_enforced || !sw_enforced)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+                                                   AuthorizationSet* sw_enforced,
+                                                   CertificateChain* /* cert_chain */) const {
+    if (!key_blob || !hw_enforced || !sw_enforced) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     uint32_t key_size_bits;
     if (!key_description.GetTagValue(TAG_KEY_SIZE, &key_size_bits) ||
@@ -43,13 +45,11 @@
         return KM_ERROR_UNSUPPORTED_KEY_SIZE;
 
     keymaster_error_t error = validate_algorithm_specific_new_key_params(key_description);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     size_t key_data_size = key_size_bytes(key_size_bits);
     KeymasterKeyBlob key_material(key_data_size);
-    if (!key_material.key_material)
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!key_material.key_material) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
     error = random_source_.GenerateRandom(key_material.writable_data(), key_data_size);
     if (error != KM_ERROR_OK) {
@@ -61,14 +61,16 @@
                                      hw_enforced, sw_enforced);
 }
 
-keymaster_error_t SymmetricKeyFactory::ImportKey(const AuthorizationSet& key_description,
+keymaster_error_t SymmetricKeyFactory::ImportKey(const AuthorizationSet& key_description,  //
                                                  keymaster_key_format_t input_key_material_format,
-                                                 const KeymasterKeyBlob& input_key_material,
+                                                 const KeymasterKeyBlob& input_key_material,  //
+                                                 UniquePtr<Key> /* attest_key */,
+                                                 const KeymasterBlob& /* issuer_subject */,
                                                  KeymasterKeyBlob* output_key_blob,
                                                  AuthorizationSet* hw_enforced,
-                                                 AuthorizationSet* sw_enforced) const {
-    if (!output_key_blob || !hw_enforced || !sw_enforced)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+                                                 AuthorizationSet* sw_enforced,
+                                                 CertificateChain* /* cert_chain */) const {
+    if (!output_key_blob || !hw_enforced || !sw_enforced) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     AuthorizationSet authorizations(key_description);
 
@@ -91,7 +93,7 @@
     }
 
     return blob_maker_.CreateKeyBlob(authorizations, KM_ORIGIN_IMPORTED, input_key_material,
-                                   output_key_blob, hw_enforced, sw_enforced);
+                                     output_key_blob, hw_enforced, sw_enforced);
 }
 
 static const keymaster_key_format_t supported_import_formats[] = {KM_KEY_FORMAT_RAW};
@@ -101,9 +103,8 @@
     return supported_import_formats;
 }
 
-SymmetricKey::SymmetricKey(KeymasterKeyBlob&& key_material,
-                           AuthorizationSet&& hw_enforced, AuthorizationSet&& sw_enforced,
-                           const KeyFactory* key_factory)
+SymmetricKey::SymmetricKey(KeymasterKeyBlob&& key_material, AuthorizationSet&& hw_enforced,
+                           AuthorizationSet&& sw_enforced, const KeyFactory* key_factory)
     : Key(move(hw_enforced), move(sw_enforced), key_factory) {
     key_material_ = move(key_material);
 }
diff --git a/km_openssl/triple_des_key.cpp b/km_openssl/triple_des_key.cpp
index 654e40e..8c267e6 100644
--- a/km_openssl/triple_des_key.cpp
+++ b/km_openssl/triple_des_key.cpp
@@ -18,8 +18,6 @@
 
 #include <assert.h>
 
-#include <keymaster/new.h>
-
 #include <openssl/err.h>
 #include <openssl/rand.h>
 
diff --git a/km_openssl/wrapped_key.cpp b/km_openssl/wrapped_key.cpp
index e619f2a..79cba00 100644
--- a/km_openssl/wrapped_key.cpp
+++ b/km_openssl/wrapped_key.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <keymaster/attestation_record.h>
 #include <keymaster/logger.h>
 #include <keymaster/wrapped_key.h>
 
diff --git a/legacy_support/ec_keymaster0_key.cpp b/legacy_support/ec_keymaster0_key.cpp
deleted file mode 100644
index 9bf8556..0000000
--- a/legacy_support/ec_keymaster0_key.cpp
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright 2015 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 <keymaster/legacy_support/ec_keymaster0_key.h>
-
-#include <memory>
-
-#include <keymaster/android_keymaster_utils.h>
-#include <keymaster/contexts/soft_keymaster_context.h>
-#include <keymaster/km_openssl/openssl_utils.h>
-#include <keymaster/legacy_support/keymaster0_engine.h>
-#include <keymaster/logger.h>
-
-
-using std::unique_ptr;
-
-namespace keymaster {
-
-EcdsaKeymaster0KeyFactory::EcdsaKeymaster0KeyFactory(const SoftwareKeyBlobMaker* blob_maker,
-                                                     const Keymaster0Engine* engine)
-    : EcKeyFactory(blob_maker), engine_(engine) {}
-
-keymaster_error_t EcdsaKeymaster0KeyFactory::GenerateKey(const AuthorizationSet& key_description,
-                                                         KeymasterKeyBlob* key_blob,
-                                                         AuthorizationSet* hw_enforced,
-                                                         AuthorizationSet* sw_enforced) const {
-    if (!key_blob || !hw_enforced || !sw_enforced)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
-
-    if (!engine_ || !engine_->supports_ec())
-        return super::GenerateKey(key_description, key_blob, hw_enforced, sw_enforced);
-
-    keymaster_ec_curve_t ec_curve;
-    uint32_t key_size;
-    keymaster_error_t error = GetCurveAndSize(key_description, &ec_curve, &key_size);
-    if (error != KM_ERROR_OK) {
-        return error;
-    }
-
-    KeymasterKeyBlob key_material;
-    if (!engine_->GenerateEcKey(key_size, &key_material))
-        return KM_ERROR_UNKNOWN_ERROR;
-
-    // These tags are hardware-enforced.  Putting them in the hw_enforced set here will ensure that
-    // blob_maker_->CreateKeyBlob doesn't put them in sw_enforced.
-    hw_enforced->push_back(TAG_ALGORITHM, KM_ALGORITHM_EC);
-    hw_enforced->push_back(TAG_KEY_SIZE, key_size);
-    hw_enforced->push_back(TAG_EC_CURVE, ec_curve);
-    hw_enforced->push_back(TAG_ORIGIN, KM_ORIGIN_UNKNOWN);
-
-    return blob_maker_.CreateKeyBlob(key_description, KM_ORIGIN_UNKNOWN, key_material, key_blob,
-                                     hw_enforced, sw_enforced);
-}
-
-keymaster_error_t EcdsaKeymaster0KeyFactory::ImportKey(
-    const AuthorizationSet& key_description, keymaster_key_format_t input_key_material_format,
-    const KeymasterKeyBlob& input_key_material, KeymasterKeyBlob* output_key_blob,
-    AuthorizationSet* hw_enforced, AuthorizationSet* sw_enforced) const {
-    if (!output_key_blob || !hw_enforced || !sw_enforced)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
-
-    if (!engine_ || !engine_->supports_ec())
-        return super::ImportKey(key_description, input_key_material_format, input_key_material,
-                                output_key_blob, hw_enforced, sw_enforced);
-
-    AuthorizationSet authorizations;
-    uint32_t key_size;
-    keymaster_error_t error = UpdateImportKeyDescription(
-        key_description, input_key_material_format, input_key_material, &authorizations, &key_size);
-    if (error != KM_ERROR_OK)
-        return error;
-
-    KeymasterKeyBlob imported_hw_key;
-    if (!engine_->ImportKey(input_key_material_format, input_key_material, &imported_hw_key))
-        return KM_ERROR_UNKNOWN_ERROR;
-
-    // These tags are hardware-enforced.  Putting them in the hw_enforced set here will ensure that
-    // blob_maker_->CreateKeyBlob doesn't put them in sw_enforced.
-    hw_enforced->push_back(TAG_ALGORITHM, KM_ALGORITHM_EC);
-    hw_enforced->push_back(TAG_KEY_SIZE, key_size);
-    hw_enforced->push_back(TAG_ORIGIN, KM_ORIGIN_UNKNOWN);
-
-    return blob_maker_.CreateKeyBlob(authorizations, KM_ORIGIN_UNKNOWN, imported_hw_key,
-                                     output_key_blob, hw_enforced, sw_enforced);
-}
-
-keymaster_error_t EcdsaKeymaster0KeyFactory::LoadKey(KeymasterKeyBlob&& key_material,
-                                                     const AuthorizationSet& additional_params,
-                                                     AuthorizationSet&& hw_enforced,
-                                                     AuthorizationSet&& sw_enforced,
-                                                     UniquePtr<Key>* key) const {
-    if (!key)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
-
-    if (sw_enforced.GetTagCount(TAG_ALGORITHM) == 1)
-        return super::LoadKey(move(key_material), additional_params, move(hw_enforced), move(sw_enforced), key);
-
-    unique_ptr<EC_KEY, EC_KEY_Delete> ec_key(engine_->BlobToEcKey(key_material));
-    if (!ec_key)
-        return KM_ERROR_UNKNOWN_ERROR;
-
-    key->reset(new (std::nothrow)
-                   EcKeymaster0Key(ec_key.release(), move(hw_enforced), move(sw_enforced), this));
-    if (!(*key))
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
-    (*key)->key_material() = move(key_material);
-    return KM_ERROR_OK;
-}
-
-}  // namespace keymaster
diff --git a/legacy_support/ec_keymaster1_key.cpp b/legacy_support/ec_keymaster1_key.cpp
index 8dcc07f..fa4dc07 100644
--- a/legacy_support/ec_keymaster1_key.cpp
+++ b/legacy_support/ec_keymaster1_key.cpp
@@ -27,9 +27,10 @@
 
 namespace keymaster {
 
-EcdsaKeymaster1KeyFactory::EcdsaKeymaster1KeyFactory(const SoftwareKeyBlobMaker* blob_maker,
+EcdsaKeymaster1KeyFactory::EcdsaKeymaster1KeyFactory(const SoftwareKeyBlobMaker& blob_maker,
+                                                     const KeymasterContext& context,
                                                      const Keymaster1Engine* engine)
-    : EcKeyFactory(blob_maker), engine_(engine),
+    : EcKeyFactory(blob_maker, context), engine_(engine),
       sign_factory_(new EcdsaKeymaster1OperationFactory(KM_PURPOSE_SIGN, engine)),
       // For pubkey ops we can use the normal operation factories.
       verify_factory_(new EcdsaVerifyOperationFactory) {}
@@ -62,9 +63,12 @@
 }
 
 keymaster_error_t EcdsaKeymaster1KeyFactory::GenerateKey(const AuthorizationSet& key_description,
+                                                         UniquePtr<Key> /* attest_key */,
+                                                         const KeymasterBlob& /* issuer_subject */,
                                                          KeymasterKeyBlob* key_blob,
                                                          AuthorizationSet* hw_enforced,
-                                                         AuthorizationSet* sw_enforced) const {
+                                                         AuthorizationSet* sw_enforced,
+                                                         CertificateChain* /* cert_chain */) const {
     AuthorizationSet key_params_copy;
     UpdateToWorkAroundUnsupportedDigests(key_description, &key_params_copy);
 
@@ -79,10 +83,16 @@
     return engine_->GenerateKey(key_params_copy, key_blob, hw_enforced, sw_enforced);
 }
 
-keymaster_error_t EcdsaKeymaster1KeyFactory::ImportKey(
-    const AuthorizationSet& key_description, keymaster_key_format_t input_key_material_format,
-    const KeymasterKeyBlob& input_key_material, KeymasterKeyBlob* output_key_blob,
-    AuthorizationSet* hw_enforced, AuthorizationSet* sw_enforced) const {
+keymaster_error_t
+EcdsaKeymaster1KeyFactory::ImportKey(const AuthorizationSet& key_description,           //
+                                     keymaster_key_format_t input_key_material_format,  //
+                                     const KeymasterKeyBlob& input_key_material,        //
+                                     UniquePtr<Key> /* attest_key */,                   //
+                                     const KeymasterBlob& /* issuer_subject */,
+                                     KeymasterKeyBlob* output_key_blob,  //
+                                     AuthorizationSet* hw_enforced,      //
+                                     AuthorizationSet* sw_enforced,
+                                     CertificateChain* /* cert_chain */) const {
     AuthorizationSet key_params_copy;
     UpdateToWorkAroundUnsupportedDigests(key_description, &key_params_copy);
     return engine_->ImportKey(key_params_copy, input_key_material_format, input_key_material,
@@ -94,19 +104,16 @@
                                                      AuthorizationSet&& hw_enforced,
                                                      AuthorizationSet&& sw_enforced,
                                                      UniquePtr<Key>* key) const {
-    if (!key)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    if (!key) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     keymaster_error_t error;
     unique_ptr<EC_KEY, EC_KEY_Delete> ecdsa(
         engine_->BuildEcKey(key_material, additional_params, &error));
-    if (!ecdsa)
-        return error;
+    if (!ecdsa) return error;
 
     key->reset(new (std::nothrow)
                    EcdsaKeymaster1Key(ecdsa.release(), move(hw_enforced), move(sw_enforced), this));
-    if (!(*key))
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!(*key)) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
     (*key)->key_material() = move(key_material);
     return KM_ERROR_OK;
diff --git a/legacy_support/ecdsa_keymaster1_operation.cpp b/legacy_support/ecdsa_keymaster1_operation.cpp
index e3d2ace..01b6061 100644
--- a/legacy_support/ecdsa_keymaster1_operation.cpp
+++ b/legacy_support/ecdsa_keymaster1_operation.cpp
@@ -30,8 +30,7 @@
 keymaster_error_t EcdsaKeymaster1WrappedOperation::Begin(EVP_PKEY* ecdsa_key,
                                                          const AuthorizationSet& input_params) {
     Keymaster1Engine::KeyData* key_data = engine_->GetData(ecdsa_key);
-    if (!key_data)
-        return KM_ERROR_UNKNOWN_ERROR;
+    if (!key_data) return KM_ERROR_UNKNOWN_ERROR;
 
     // Copy the input params and substitute KM_DIGEST_NONE for whatever was specified.  Also change
     // KM_PAD_ECDSA_PSS and KM_PAD_OAEP to KM_PAD_NONE, if necessary. These are the params we'll
@@ -48,8 +47,7 @@
     // that layer.
     AuthorizationSet begin_params(input_params);
     int pos = begin_params.find(TAG_DIGEST);
-    if (pos == -1)
-        return KM_ERROR_UNSUPPORTED_DIGEST;
+    if (pos == -1) return KM_ERROR_UNSUPPORTED_DIGEST;
     begin_params[pos].enumerated = KM_DIGEST_NONE;
 
     return engine_->device()->begin(engine_->device(), purpose_, &key_data->key_material,
@@ -76,8 +74,7 @@
 
 keymaster_error_t EcdsaKeymaster1WrappedOperation::GetError(EVP_PKEY* ecdsa_key) {
     Keymaster1Engine::KeyData* key_data = engine_->GetData(ecdsa_key);
-    if (!key_data)
-        return KM_ERROR_UNKNOWN_ERROR;
+    if (!key_data) return KM_ERROR_UNKNOWN_ERROR;
     return key_data->error;
 }
 
diff --git a/legacy_support/ecdsa_keymaster1_operation.h b/legacy_support/ecdsa_keymaster1_operation.h
index a24cc2b..e52deae 100644
--- a/legacy_support/ecdsa_keymaster1_operation.h
+++ b/legacy_support/ecdsa_keymaster1_operation.h
@@ -32,8 +32,7 @@
     EcdsaKeymaster1WrappedOperation(keymaster_purpose_t purpose, const Keymaster1Engine* engine)
         : purpose_(purpose), operation_handle_(0), engine_(engine) {}
     ~EcdsaKeymaster1WrappedOperation() {
-        if (operation_handle_)
-            Abort();
+        if (operation_handle_) Abort();
     }
 
     keymaster_error_t Begin(EVP_PKEY* ecdsa_key, const AuthorizationSet& input_params);
@@ -43,6 +42,7 @@
     keymaster_error_t GetError(EVP_PKEY* ecdsa_key);
 
     keymaster_operation_handle_t GetOperationHandle() const { return operation_handle_; }
+
   protected:
     keymaster_purpose_t purpose_;
     keymaster_operation_handle_t operation_handle_;
@@ -66,8 +66,7 @@
     keymaster_error_t Begin(const AuthorizationSet& input_params,
                             AuthorizationSet* output_params) override {
         keymaster_error_t error = wrapped_operation_.Begin(super::ecdsa_key_, input_params);
-        if (error != KM_ERROR_OK)
-            return error;
+        if (error != KM_ERROR_OK) return error;
         return super::Begin(input_params, output_params);
     }
 
@@ -75,8 +74,7 @@
                              const Buffer& signature, AuthorizationSet* output_params,
                              Buffer* output) override {
         keymaster_error_t error = wrapped_operation_.PrepareFinish(super::ecdsa_key_, input_params);
-        if (error != KM_ERROR_OK)
-            return error;
+        if (error != KM_ERROR_OK) return error;
         error = super::Finish(input_params, input, signature, output_params, output);
         if (wrapped_operation_.GetError(super::ecdsa_key_) != KM_ERROR_OK)
             error = wrapped_operation_.GetError(super::ecdsa_key_);
@@ -85,14 +83,14 @@
 
     keymaster_error_t Abort() override {
         keymaster_error_t error = wrapped_operation_.Abort();
-        if (error != KM_ERROR_OK)
-            return error;
+        if (error != KM_ERROR_OK) return error;
         return super::Abort();
     }
 
     keymaster_operation_handle_t operation_handle() const override {
         return wrapped_operation_.GetOperationHandle();
     }
+
   private:
     EcdsaKeymaster1WrappedOperation wrapped_operation_;
 };
diff --git a/legacy_support/keymaster0_engine.cpp b/legacy_support/keymaster0_engine.cpp
deleted file mode 100644
index e856318..0000000
--- a/legacy_support/keymaster0_engine.cpp
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * Copyright 2015 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 <keymaster/legacy_support/keymaster0_engine.h>
-
-#include <assert.h>
-#include <string.h>
-
-#include <memory>
-
-#define LOG_TAG "Keymaster0Engine"
-#include <log/log.h>
-
-#include <keymaster/android_keymaster_utils.h>
-#include <keymaster/km_openssl/openssl_utils.h>
-
-#include <openssl/bn.h>
-#include <openssl/ec_key.h>
-#include <openssl/ecdsa.h>
-
-
-using std::shared_ptr;
-using std::unique_ptr;
-
-namespace keymaster {
-
-Keymaster0Engine* Keymaster0Engine::instance_ = nullptr;
-
-Keymaster0Engine::Keymaster0Engine(const keymaster0_device_t* keymaster0_device)
-    : keymaster0_device_(keymaster0_device), engine_(ENGINE_new()), supports_ec_(false) {
-    assert(!instance_);
-    instance_ = this;
-
-    rsa_index_ = RSA_get_ex_new_index(0 /* argl */, nullptr /* argp */, nullptr /* new_func */,
-                                      keyblob_dup, keyblob_free);
-    ec_key_index_ = EC_KEY_get_ex_new_index(0 /* argl */, nullptr /* argp */, nullptr /* new_func */,
-                                            keyblob_dup, keyblob_free);
-
-    memset(&rsa_method_, 0, sizeof(rsa_method_));
-    rsa_method_.common.is_static = 1;
-    rsa_method_.private_transform = Keymaster0Engine::rsa_private_transform;
-    rsa_method_.flags = RSA_FLAG_OPAQUE;
-
-    ENGINE_set_RSA_method(engine_, &rsa_method_, sizeof(rsa_method_));
-
-    if ((keymaster0_device_->flags & KEYMASTER_SUPPORTS_EC) != 0) {
-        supports_ec_ = true;
-
-        memset(&ecdsa_method_, 0, sizeof(ecdsa_method_));
-        ecdsa_method_.common.is_static = 1;
-        ecdsa_method_.sign = Keymaster0Engine::ecdsa_sign;
-        ecdsa_method_.flags = ECDSA_FLAG_OPAQUE;
-
-        ENGINE_set_ECDSA_method(engine_, &ecdsa_method_, sizeof(ecdsa_method_));
-    }
-}
-
-Keymaster0Engine::~Keymaster0Engine() {
-    if (keymaster0_device_)
-        keymaster0_device_->common.close(
-            reinterpret_cast<hw_device_t*>(const_cast<keymaster0_device_t*>(keymaster0_device_)));
-    ENGINE_free(engine_);
-    instance_ = nullptr;
-}
-
-bool Keymaster0Engine::GenerateRsaKey(uint64_t public_exponent, uint32_t public_modulus,
-                                      KeymasterKeyBlob* key_material) const {
-    assert(key_material);
-    keymaster_rsa_keygen_params_t params;
-    params.public_exponent = public_exponent;
-    params.modulus_size = public_modulus;
-
-    uint8_t* key_blob = nullptr;
-    if (keymaster0_device_->generate_keypair(keymaster0_device_, TYPE_RSA, &params, &key_blob,
-                                             &key_material->key_material_size) < 0) {
-        ALOGE("Error generating RSA key pair with keymaster0 device");
-        return false;
-    }
-    unique_ptr<uint8_t, Malloc_Delete> key_blob_deleter(key_blob);
-    key_material->key_material = dup_buffer(key_blob, key_material->key_material_size);
-    return true;
-}
-
-bool Keymaster0Engine::GenerateEcKey(uint32_t key_size, KeymasterKeyBlob* key_material) const {
-    assert(key_material);
-    keymaster_ec_keygen_params_t params;
-    params.field_size = key_size;
-
-    uint8_t* key_blob = nullptr;
-    if (keymaster0_device_->generate_keypair(keymaster0_device_, TYPE_EC, &params, &key_blob,
-                                             &key_material->key_material_size) < 0) {
-        ALOGE("Error generating EC key pair with keymaster0 device");
-        return false;
-    }
-    unique_ptr<uint8_t, Malloc_Delete> key_blob_deleter(key_blob);
-    key_material->key_material = dup_buffer(key_blob, key_material->key_material_size);
-    return true;
-}
-
-bool Keymaster0Engine::ImportKey(keymaster_key_format_t key_format,
-                                 const KeymasterKeyBlob& to_import,
-                                 KeymasterKeyBlob* imported_key) const {
-    assert(imported_key);
-    if (key_format != KM_KEY_FORMAT_PKCS8)
-        return false;
-
-    uint8_t* key_blob = nullptr;
-    if (keymaster0_device_->import_keypair(keymaster0_device_, to_import.key_material,
-                                           to_import.key_material_size, &key_blob,
-                                           &imported_key->key_material_size) < 0) {
-        ALOGW("Error importing keypair with keymaster0 device");
-        return false;
-    }
-    unique_ptr<uint8_t, Malloc_Delete> key_blob_deleter(key_blob);
-    imported_key->key_material = dup_buffer(key_blob, imported_key->key_material_size);
-    return true;
-}
-
-bool Keymaster0Engine::DeleteKey(const KeymasterKeyBlob& blob) const {
-    if (!keymaster0_device_->delete_keypair)
-        return true;
-    return (keymaster0_device_->delete_keypair(keymaster0_device_, blob.key_material,
-                                               blob.key_material_size) == 0);
-}
-
-bool Keymaster0Engine::DeleteAllKeys() const {
-    if (!keymaster0_device_->delete_all)
-        return true;
-    return (keymaster0_device_->delete_all(keymaster0_device_) == 0);
-}
-
-static keymaster_key_blob_t* duplicate_blob(const uint8_t* key_data, size_t key_data_size) {
-    unique_ptr<uint8_t[]> key_material_copy(dup_buffer(key_data, key_data_size));
-    if (!key_material_copy)
-        return nullptr;
-
-    unique_ptr<keymaster_key_blob_t> blob_copy(new (std::nothrow) keymaster_key_blob_t);
-    if (!blob_copy.get())
-        return nullptr;
-    blob_copy->key_material_size = key_data_size;
-    blob_copy->key_material = key_material_copy.release();
-    return blob_copy.release();
-}
-
-inline keymaster_key_blob_t* duplicate_blob(const keymaster_key_blob_t& blob) {
-    return duplicate_blob(blob.key_material, blob.key_material_size);
-}
-
-RSA* Keymaster0Engine::BlobToRsaKey(const KeymasterKeyBlob& blob) const {
-    // Create new RSA key (with engine methods) and insert blob
-    unique_ptr<RSA, RSA_Delete> rsa(RSA_new_method(engine_));
-    if (!rsa)
-        return nullptr;
-
-    keymaster_key_blob_t* blob_copy = duplicate_blob(blob);
-    if (!blob_copy->key_material || !RSA_set_ex_data(rsa.get(), rsa_index_, blob_copy))
-        return nullptr;
-
-    // Copy public key into new RSA key
-    unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(GetKeymaster0PublicKey(blob));
-    if (!pkey)
-        return nullptr;
-    unique_ptr<RSA, RSA_Delete> public_rsa(EVP_PKEY_get1_RSA(pkey.get()));
-    if (!public_rsa)
-        return nullptr;
-    rsa->n = BN_dup(public_rsa->n);
-    rsa->e = BN_dup(public_rsa->e);
-    if (!rsa->n || !rsa->e)
-        return nullptr;
-
-    return rsa.release();
-}
-
-EC_KEY* Keymaster0Engine::BlobToEcKey(const KeymasterKeyBlob& blob) const {
-    // Create new EC key (with engine methods) and insert blob
-    unique_ptr<EC_KEY, EC_KEY_Delete> ec_key(EC_KEY_new_method(engine_));
-    if (!ec_key)
-        return nullptr;
-
-    keymaster_key_blob_t* blob_copy = duplicate_blob(blob);
-    if (!blob_copy->key_material || !EC_KEY_set_ex_data(ec_key.get(), ec_key_index_, blob_copy))
-        return nullptr;
-
-    // Copy public key into new EC key
-    unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(GetKeymaster0PublicKey(blob));
-    if (!pkey)
-        return nullptr;
-
-    unique_ptr<EC_KEY, EC_KEY_Delete> public_ec_key(EVP_PKEY_get1_EC_KEY(pkey.get()));
-    if (!public_ec_key)
-        return nullptr;
-
-    if (!EC_KEY_set_group(ec_key.get(), EC_KEY_get0_group(public_ec_key.get())) ||
-        !EC_KEY_set_public_key(ec_key.get(), EC_KEY_get0_public_key(public_ec_key.get())))
-        return nullptr;
-
-    return ec_key.release();
-}
-
-const keymaster_key_blob_t* Keymaster0Engine::RsaKeyToBlob(const RSA* rsa) const {
-    return reinterpret_cast<keymaster_key_blob_t*>(RSA_get_ex_data(rsa, rsa_index_));
-}
-
-const keymaster_key_blob_t* Keymaster0Engine::EcKeyToBlob(const EC_KEY* ec_key) const {
-    return reinterpret_cast<keymaster_key_blob_t*>(EC_KEY_get_ex_data(ec_key, ec_key_index_));
-}
-
-/* static */
-int Keymaster0Engine::keyblob_dup(CRYPTO_EX_DATA* /* to */, const CRYPTO_EX_DATA* /* from */,
-                                  void** from_d, int /* index */, long /* argl */,
-                                  void* /* argp */) {
-    keymaster_key_blob_t* blob = reinterpret_cast<keymaster_key_blob_t*>(*from_d);
-    if (!blob)
-        return 1;
-    *from_d = duplicate_blob(*blob);
-    if (*from_d)
-        return 1;
-    return 0;
-}
-
-/* static */
-void Keymaster0Engine::keyblob_free(void* /* parent */, void* ptr, CRYPTO_EX_DATA* /* data */,
-                                    int /* index*/, long /* argl */, void* /* argp */) {
-    keymaster_key_blob_t* blob = reinterpret_cast<keymaster_key_blob_t*>(ptr);
-    if (blob) {
-        delete[] blob->key_material;
-        delete blob;
-    }
-}
-
-/* static */
-int Keymaster0Engine::rsa_private_transform(RSA* rsa, uint8_t* out, const uint8_t* in, size_t len) {
-    ALOGV("rsa_private_transform(%p, %p, %p, %u)", rsa, out, in, (unsigned)len);
-
-    assert(instance_);
-    return instance_->RsaPrivateTransform(rsa, out, in, len);
-}
-
-/* static */
-int Keymaster0Engine::ecdsa_sign(const uint8_t* digest, size_t digest_len, uint8_t* sig,
-                                 unsigned int* sig_len, EC_KEY* ec_key) {
-    ALOGV("ecdsa_sign(%p, %u, %p)", digest, (unsigned)digest_len, ec_key);
-    assert(instance_);
-    return instance_->EcdsaSign(digest, digest_len, sig, sig_len, ec_key);
-}
-
-bool Keymaster0Engine::Keymaster0Sign(const void* signing_params, const keymaster_key_blob_t& blob,
-                                      const uint8_t* data, const size_t data_length,
-                                      unique_ptr<uint8_t[], Malloc_Delete>* signature,
-                                      size_t* signature_length) const {
-    uint8_t* signed_data;
-    int err = keymaster0_device_->sign_data(keymaster0_device_, signing_params, blob.key_material,
-                                            blob.key_material_size, data, data_length, &signed_data,
-                                            signature_length);
-    if (err < 0) {
-        ALOGE("Keymaster0 signing failed with error %d", err);
-        return false;
-    }
-
-    signature->reset(signed_data);
-    return true;
-}
-
-EVP_PKEY* Keymaster0Engine::GetKeymaster0PublicKey(const KeymasterKeyBlob& blob) const {
-    uint8_t* pub_key_data;
-    size_t pub_key_data_length;
-    int err = keymaster0_device_->get_keypair_public(keymaster0_device_, blob.key_material,
-                                                     blob.key_material_size, &pub_key_data,
-                                                     &pub_key_data_length);
-    if (err < 0) {
-        ALOGE("Error %d extracting public key", err);
-        return nullptr;
-    }
-    unique_ptr<uint8_t, Malloc_Delete> pub_key(pub_key_data);
-
-    const uint8_t* p = pub_key_data;
-    return d2i_PUBKEY(nullptr /* allocate new struct */, &p, pub_key_data_length);
-}
-
-static bool data_too_large_for_public_modulus(const uint8_t* data, size_t len, const RSA* rsa) {
-    unique_ptr<BIGNUM, BIGNUM_Delete> input_as_bn(
-        BN_bin2bn(data, len, nullptr /* allocate result */));
-    return input_as_bn && BN_ucmp(input_as_bn.get(), rsa->n) >= 0;
-}
-
-int Keymaster0Engine::RsaPrivateTransform(RSA* rsa, uint8_t* out, const uint8_t* in,
-                                          size_t len) const {
-    const keymaster_key_blob_t* key_blob = RsaKeyToBlob(rsa);
-    if (key_blob == nullptr) {
-        ALOGE("key had no key_blob!");
-        return 0;
-    }
-
-    keymaster_rsa_sign_params_t sign_params = {DIGEST_NONE, PADDING_NONE};
-    unique_ptr<uint8_t[], Malloc_Delete> signature;
-    size_t signature_length;
-    if (!Keymaster0Sign(&sign_params, *key_blob, in, len, &signature, &signature_length)) {
-        if (data_too_large_for_public_modulus(in, len, rsa)) {
-            ALOGE("Keymaster0 signing failed because data is too large.");
-            OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_MODULUS);
-        } else {
-            // We don't know what error code is correct; force an "unknown error" return
-            OPENSSL_PUT_ERROR(USER, KM_ERROR_UNKNOWN_ERROR);
-        }
-        return 0;
-    }
-    Eraser eraser(signature.get(), signature_length);
-
-    if (signature_length > len) {
-        /* The result of the RSA operation can never be larger than the size of
-         * the modulus so we assume that the result has extra zeros on the
-         * left. This provides attackers with an oracle, but there's nothing
-         * that we can do about it here. */
-        memcpy(out, signature.get() + signature_length - len, len);
-    } else if (signature_length < len) {
-        /* If the keymaster0 implementation returns a short value we assume that
-         * it's because it removed leading zeros from the left side. This is
-         * bad because it provides attackers with an oracle but we cannot do
-         * anything about a broken keymaster0 implementation here. */
-        memset(out, 0, len);
-        memcpy(out + len - signature_length, signature.get(), signature_length);
-    } else {
-        memcpy(out, signature.get(), len);
-    }
-
-    ALOGV("rsa=%p keystore_rsa_priv_dec successful", rsa);
-    return 1;
-}
-
-int Keymaster0Engine::EcdsaSign(const uint8_t* digest, size_t digest_len, uint8_t* sig,
-                                unsigned int* sig_len, EC_KEY* ec_key) const {
-    const keymaster_key_blob_t* key_blob = EcKeyToBlob(ec_key);
-    if (key_blob == nullptr) {
-        ALOGE("key had no key_blob!");
-        return 0;
-    }
-
-    // Truncate digest if it's too long
-    size_t max_input_len = (ec_group_size_bits(ec_key) + 7) / 8;
-    if (digest_len > max_input_len)
-        digest_len = max_input_len;
-
-    keymaster_ec_sign_params_t sign_params = {DIGEST_NONE};
-    unique_ptr<uint8_t[], Malloc_Delete> signature;
-    size_t signature_length;
-    if (!Keymaster0Sign(&sign_params, *key_blob, digest, digest_len, &signature,
-                        &signature_length)) {
-        // We don't know what error code is correct; force an "unknown error" return
-        OPENSSL_PUT_ERROR(USER, KM_ERROR_UNKNOWN_ERROR);
-        return 0;
-    }
-    Eraser eraser(signature.get(), signature_length);
-
-    if (signature_length == 0) {
-        ALOGW("No valid signature returned");
-        return 0;
-    } else if (signature_length > ECDSA_size(ec_key)) {
-        ALOGW("Signature is too large");
-        return 0;
-    } else {
-        memcpy(sig, signature.get(), signature_length);
-        *sig_len = signature_length;
-    }
-
-    ALOGV("ecdsa_sign(%p, %u, %p) => success", digest, (unsigned)digest_len, ec_key);
-    return 1;
-}
-
-}  // namespace keymaster
diff --git a/legacy_support/keymaster1_engine.cpp b/legacy_support/keymaster1_engine.cpp
index 7dd2c8a..28a64ad 100644
--- a/legacy_support/keymaster1_engine.cpp
+++ b/legacy_support/keymaster1_engine.cpp
@@ -32,7 +32,6 @@
 #include <openssl/ec_key.h>
 #include <openssl/ecdsa.h>
 
-using std::shared_ptr;
 using std::unique_ptr;
 
 namespace keymaster {
@@ -44,9 +43,9 @@
       rsa_index_(RSA_get_ex_new_index(0 /* argl */, nullptr /* argp */, nullptr /* new_func */,
                                       Keymaster1Engine::duplicate_key_data,
                                       Keymaster1Engine::free_key_data)),
-      ec_key_index_(EC_KEY_get_ex_new_index(0 /* argl */, nullptr /* argp */, nullptr /* new_func */,
-                                            Keymaster1Engine::duplicate_key_data,
-                                            Keymaster1Engine::free_key_data)),
+      ec_key_index_(EC_KEY_get_ex_new_index(
+          0 /* argl */, nullptr /* argp */, nullptr /* new_func */,
+          Keymaster1Engine::duplicate_key_data, Keymaster1Engine::free_key_data)),
       rsa_method_(BuildRsaMethod()), ecdsa_method_(BuildEcdsaMethod()) {
     assert(rsa_index_ != -1);
     assert(ec_key_index_ != -1);
@@ -69,10 +68,8 @@
                                    AuthorizationSet* hw_enforced, AuthorizationSet* sw_enforced) {
     unique_ptr<keymaster_key_characteristics_t, Characteristics_Delete> characteristics_deleter(
         characteristics);
-    if (hw_enforced)
-        hw_enforced->Reinitialize(characteristics->hw_enforced);
-    if (sw_enforced)
-        sw_enforced->Reinitialize(characteristics->sw_enforced);
+    if (hw_enforced) hw_enforced->Reinitialize(characteristics->hw_enforced);
+    if (sw_enforced) sw_enforced->Reinitialize(characteristics->sw_enforced);
 }
 
 keymaster_error_t Keymaster1Engine::GenerateKey(const AuthorizationSet& key_description,
@@ -85,8 +82,7 @@
     keymaster_key_blob_t blob;
     keymaster_error_t error = keymaster1_device_->generate_key(keymaster1_device_, &key_description,
                                                                &blob, &characteristics);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
     unique_ptr<uint8_t, Malloc_Delete> blob_deleter(const_cast<uint8_t*>(blob.key_material));
     key_blob->key_material = dup_buffer(blob.key_material, blob.key_material_size);
     key_blob->key_material_size = blob.key_material_size;
@@ -110,8 +106,7 @@
     keymaster_error_t error = keymaster1_device_->import_key(keymaster1_device_, &key_description,
                                                              input_key_material_format, &input_key,
                                                              &blob, &characteristics);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
     unique_ptr<uint8_t, Malloc_Delete> blob_deleter(const_cast<uint8_t*>(blob.key_material));
     output_key_blob->key_material = dup_buffer(blob.key_material, blob.key_material_size);
     output_key_blob->key_material_size = blob.key_material_size;
@@ -121,14 +116,12 @@
 }
 
 keymaster_error_t Keymaster1Engine::DeleteKey(const KeymasterKeyBlob& blob) const {
-    if (!keymaster1_device_->delete_key)
-        return KM_ERROR_OK;
+    if (!keymaster1_device_->delete_key) return KM_ERROR_OK;
     return keymaster1_device_->delete_key(keymaster1_device_, &blob);
 }
 
 keymaster_error_t Keymaster1Engine::DeleteAllKeys() const {
-    if (!keymaster1_device_->delete_all_keys)
-        return KM_ERROR_OK;
+    if (!keymaster1_device_->delete_all_keys) return KM_ERROR_OK;
     return keymaster1_device_->delete_all_keys(keymaster1_device_);
 }
 
@@ -152,8 +145,7 @@
     // Copy public key into new RSA key
     unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(
         GetKeymaster1PublicKey(key_data->key_material, key_data->begin_params, error));
-    if (*error != KM_ERROR_OK)
-        return nullptr;
+    if (*error != KM_ERROR_OK) return nullptr;
 
     unique_ptr<RSA, RSA_Delete> public_rsa(EVP_PKEY_get1_RSA(pkey.get()));
     if (!public_rsa) {
@@ -192,8 +184,7 @@
     // Copy public key into new EC key
     unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(
         GetKeymaster1PublicKey(blob, additional_params, error));
-    if (*error != KM_ERROR_OK)
-        return nullptr;
+    if (*error != KM_ERROR_OK) return nullptr;
 
     unique_ptr<EC_KEY, EC_KEY_Delete> public_ec_key(EVP_PKEY_get1_EC_KEY(pkey.get()));
     if (!public_ec_key) {
@@ -229,34 +220,32 @@
 }
 
 Keymaster1Engine::KeyData* Keymaster1Engine::GetData(const RSA* rsa) const {
-    if (!rsa)
-        return nullptr;
+    if (!rsa) return nullptr;
     return reinterpret_cast<KeyData*>(RSA_get_ex_data(rsa, rsa_index_));
 }
 
 Keymaster1Engine::KeyData* Keymaster1Engine::GetData(const EC_KEY* ec_key) const {
-    if (!ec_key)
-        return nullptr;
+    if (!ec_key) return nullptr;
     return reinterpret_cast<KeyData*>(EC_KEY_get_ex_data(ec_key, ec_key_index_));
 }
 
 /* static */
 int Keymaster1Engine::duplicate_key_data(CRYPTO_EX_DATA* /* to */, const CRYPTO_EX_DATA* /* from */,
+                                         // NOLINTNEXTLINE(google-runtime-int)
                                          void** from_d, int /* index */, long /* argl */,
                                          void* /* argp */) {
     KeyData* data = reinterpret_cast<KeyData*>(*from_d);
-    if (!data)
-        return 1;
+    if (!data) return 1;
 
     // Default copy ctor is good.
     *from_d = new KeyData(*data);
-    if (*from_d)
-        return 1;
+    if (*from_d) return 1;
     return 0;
 }
 
 /* static */
 void Keymaster1Engine::free_key_data(void* /* parent */, void* ptr, CRYPTO_EX_DATA* /* data */,
+                                     // NOLINTNEXTLINE(google-runtime-int)
                                      int /* index*/, long /* argl */, void* /* argp */) {
     delete reinterpret_cast<KeyData*>(ptr);
 }
@@ -264,8 +253,7 @@
 keymaster_error_t Keymaster1Engine::Keymaster1Finish(const KeyData* key_data,
                                                      const keymaster_blob_t& input,
                                                      keymaster_blob_t* output) {
-    if (key_data->op_handle == 0)
-        return KM_ERROR_UNKNOWN_ERROR;
+    if (key_data->op_handle == 0) return KM_ERROR_UNKNOWN_ERROR;
 
     size_t input_consumed;
     // Note: devices are required to consume all input in a single update call for undigested
@@ -273,8 +261,7 @@
     keymaster_error_t error =
         device()->update(device(), key_data->op_handle, &key_data->finish_params, &input,
                          &input_consumed, nullptr /* out_params */, nullptr /* output */);
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     return device()->finish(device(), key_data->op_handle, &key_data->finish_params,
                             nullptr /* signature */, nullptr /* out_params */, output);
@@ -284,8 +271,7 @@
 int Keymaster1Engine::rsa_sign_raw(RSA* rsa, size_t* out_len, uint8_t* out, size_t max_out,
                                    const uint8_t* in, size_t in_len, int padding) {
     KeyData* key_data = instance_->GetData(rsa);
-    if (!key_data)
-        return 0;
+    if (!key_data) return 0;
 
     if (padding != key_data->expected_openssl_padding) {
         LOG_E("Expected sign_raw with padding %d but got padding %d",
@@ -296,8 +282,7 @@
     keymaster_blob_t input = {in, in_len};
     keymaster_blob_t output;
     key_data->error = instance_->Keymaster1Finish(key_data, input, &output);
-    if (key_data->error != KM_ERROR_OK)
-        return 0;
+    if (key_data->error != KM_ERROR_OK) return 0;
     unique_ptr<uint8_t, Malloc_Delete> output_deleter(const_cast<uint8_t*>(output.data));
 
     *out_len = std::min(output.data_length, max_out);
@@ -309,8 +294,7 @@
 int Keymaster1Engine::rsa_decrypt(RSA* rsa, size_t* out_len, uint8_t* out, size_t max_out,
                                   const uint8_t* in, size_t in_len, int padding) {
     KeyData* key_data = instance_->GetData(rsa);
-    if (!key_data)
-        return 0;
+    if (!key_data) return 0;
 
     if (padding != key_data->expected_openssl_padding) {
         LOG_E("Expected sign_raw with padding %d but got padding %d",
@@ -321,8 +305,7 @@
     keymaster_blob_t input = {in, in_len};
     keymaster_blob_t output;
     key_data->error = instance_->Keymaster1Finish(key_data, input, &output);
-    if (key_data->error != KM_ERROR_OK)
-        return 0;
+    if (key_data->error != KM_ERROR_OK) return 0;
     unique_ptr<uint8_t, Malloc_Delete> output_deleter(const_cast<uint8_t*>(output.data));
 
     *out_len = std::min(output.data_length, max_out);
@@ -334,19 +317,16 @@
 int Keymaster1Engine::ecdsa_sign(const uint8_t* digest, size_t digest_len, uint8_t* sig,
                                  unsigned int* sig_len, EC_KEY* ec_key) {
     KeyData* key_data = instance_->GetData(ec_key);
-    if (!key_data)
-        return 0;
+    if (!key_data) return 0;
 
     // Truncate digest if it's too long
     size_t max_input_len = (ec_group_size_bits(ec_key) + 7) / 8;
-    if (digest_len > max_input_len)
-        digest_len = max_input_len;
+    if (digest_len > max_input_len) digest_len = max_input_len;
 
     keymaster_blob_t input = {digest, digest_len};
     keymaster_blob_t output;
     key_data->error = instance_->Keymaster1Finish(key_data, input, &output);
-    if (key_data->error != KM_ERROR_OK)
-        return 0;
+    if (key_data->error != KM_ERROR_OK) return 0;
     unique_ptr<uint8_t, Malloc_Delete> output_deleter(const_cast<uint8_t*>(output.data));
 
     *sig_len = std::min(output.data_length, ECDSA_size(ec_key));
@@ -361,16 +341,13 @@
     keymaster_blob_t app_data = {nullptr, 0};
     keymaster_blob_t* client_id_ptr = nullptr;
     keymaster_blob_t* app_data_ptr = nullptr;
-    if (additional_params.GetTagValue(TAG_APPLICATION_ID, &client_id))
-        client_id_ptr = &client_id;
-    if (additional_params.GetTagValue(TAG_APPLICATION_DATA, &app_data))
-        app_data_ptr = &app_data;
+    if (additional_params.GetTagValue(TAG_APPLICATION_ID, &client_id)) client_id_ptr = &client_id;
+    if (additional_params.GetTagValue(TAG_APPLICATION_DATA, &app_data)) app_data_ptr = &app_data;
 
     keymaster_blob_t export_data = {nullptr, 0};
     *error = keymaster1_device_->export_key(keymaster1_device_, KM_KEY_FORMAT_X509, &blob,
                                             client_id_ptr, app_data_ptr, &export_data);
-    if (*error != KM_ERROR_OK)
-        return nullptr;
+    if (*error != KM_ERROR_OK) return nullptr;
 
     unique_ptr<uint8_t, Malloc_Delete> pub_key(const_cast<uint8_t*>(export_data.data));
 
diff --git a/legacy_support/keymaster1_legacy_support.cpp b/legacy_support/keymaster1_legacy_support.cpp
index b0fe3f2..3fd5cb4 100644
--- a/legacy_support/keymaster1_legacy_support.cpp
+++ b/legacy_support/keymaster1_legacy_support.cpp
@@ -54,8 +54,8 @@
     return counter.count == full_digest_list.size();
 }
 
-static keymaster_error_t add_digests(const keymaster1_device_t* dev, keymaster_algorithm_t algorithm,
-                                     keymaster_purpose_t purpose,
+static keymaster_error_t add_digests(const keymaster1_device_t* dev,
+                                     keymaster_algorithm_t algorithm, keymaster_purpose_t purpose,
                                      Keymaster1LegacySupport::DigestMap* map, bool* supports_all) {
     auto key = std::make_pair(algorithm, purpose);
 
@@ -76,8 +76,7 @@
 }
 
 static keymaster_error_t map_digests(const keymaster1_device_t* dev,
-                                     Keymaster1LegacySupport::DigestMap* map,
-                                     bool* supports_all) {
+                                     Keymaster1LegacySupport::DigestMap* map, bool* supports_all) {
     map->clear();
     *supports_all = true;
 
@@ -88,8 +87,7 @@
             bool alg_purpose_supports_all;
             keymaster_error_t error =
                 add_digests(dev, algorithm, purpose, map, &alg_purpose_supports_all);
-            if (error != KM_ERROR_OK)
-                return error;
+            if (error != KM_ERROR_OK) return error;
             *supports_all &= alg_purpose_supports_all;
         }
 
@@ -100,8 +98,7 @@
             bool alg_purpose_supports_all;
             keymaster_error_t error =
                 add_digests(dev, algorithm, purpose, map, &alg_purpose_supports_all);
-            if (error != KM_ERROR_OK)
-                return error;
+            if (error != KM_ERROR_OK) return error;
             *supports_all &= alg_purpose_supports_all;
         }
 
@@ -117,10 +114,8 @@
 }
 
 template <typename T>
-static bool findUnsupportedDigest(keymaster_algorithm_t algorithm,
-                                  keymaster_purpose_t purpose,
-                                  keymaster_digest_t digest,
-                                  const T& params,
+static bool findUnsupportedDigest(keymaster_algorithm_t algorithm, keymaster_purpose_t purpose,
+                                  keymaster_digest_t digest, const T& params,
                                   const Keymaster1LegacySupport::DigestMap& digest_map) {
     auto supported_digests = digest_map.find(std::make_pair(algorithm, purpose));
     if (supported_digests == digest_map.end())
@@ -135,7 +130,8 @@
     for (auto& entry : params)
         if (entry.tag == TAG_DIGEST)
             if (!contains(supported_digests->second, entry.enumerated)) {
-                LOG(WARNING) << "Digest " << entry.enumerated << " requested but not supported by KM1 hal";
+                LOG(WARNING) << "Digest " << entry.enumerated
+                             << " requested but not supported by KM1 hal";
                 return true;
             }
     return false;
@@ -143,8 +139,7 @@
 
 template <typename T>
 bool requiresSoftwareDigesting(keymaster_algorithm_t algorithm, keymaster_purpose_t purpose,
-                               keymaster_digest_t digest,
-                               const T& params,
+                               keymaster_digest_t digest, const T& params,
                                const Keymaster1LegacySupport::DigestMap& digest_map) {
     switch (algorithm) {
     case KM_ALGORITHM_AES:
@@ -158,14 +153,15 @@
     }
 
     if (!findUnsupportedDigest(algorithm, purpose, digest, params, digest_map)) {
-        LOG(DEBUG) << "Requested digest(s) supported for algorithm " << algorithm << " and purpose " << purpose;
+        LOG(DEBUG) << "Requested digest(s) supported for algorithm " << algorithm << " and purpose "
+                   << purpose;
         return false;
     }
 
     return true;
 }
 bool Keymaster1LegacySupport::RequiresSoftwareDigesting(
-        const AuthorizationSet& key_description) const {
+    const AuthorizationSet& key_description) const {
 
     keymaster_algorithm_t algorithm;
     if (!key_description.GetTagValue(TAG_ALGORITHM, &algorithm)) {
@@ -189,7 +185,7 @@
 }
 
 bool Keymaster1LegacySupport::RequiresSoftwareDigesting(const keymaster_digest_t digest,
-        const AuthProxy& key_description) const {
+                                                        const AuthProxy& key_description) const {
 
     keymaster_algorithm_t algorithm;
     if (!key_description.GetTagValue(TAG_ALGORITHM, &algorithm)) {
@@ -222,15 +218,19 @@
     return !has_purpose;
 }
 
-template<>
-keymaster_error_t
-Keymaster1ArbitrationFactory<EcdsaKeymaster1KeyFactory>::GenerateKey(
-        const AuthorizationSet& key_description,
-        KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
-        AuthorizationSet* sw_enforced) const {
+template <>
+keymaster_error_t Keymaster1ArbitrationFactory<EcdsaKeymaster1KeyFactory>::GenerateKey(
+    const AuthorizationSet& key_description,  //
+    UniquePtr<Key> attest_key,                //
+    const KeymasterBlob& issuer_subject,      //
+    KeymasterKeyBlob* key_blob,               //
+    AuthorizationSet* hw_enforced,            //
+    AuthorizationSet* sw_enforced,            //
+    CertificateChain* cert_chain) const {
     if (legacy_support_.RequiresSoftwareDigesting(key_description)) {
-        return software_digest_factory_.GenerateKey(key_description, key_blob, hw_enforced,
-                                             sw_enforced);
+        return software_digest_factory_.GenerateKey(key_description, move(attest_key),
+                                                    issuer_subject, key_blob, hw_enforced,
+                                                    sw_enforced, cert_chain);
     } else {
         AuthorizationSet mutable_key_description = key_description;
         keymaster_ec_curve_t curve;
@@ -252,54 +252,48 @@
             }
         }
 
-        return passthrough_factory_.GenerateKey(mutable_key_description, key_blob, hw_enforced,
-                                                sw_enforced);
+        return passthrough_factory_.GenerateKey(mutable_key_description, move(attest_key),
+                                                issuer_subject, key_blob, hw_enforced, sw_enforced,
+                                                cert_chain);
     }
 }
 
-template<>
-keymaster_error_t
-Keymaster1ArbitrationFactory<EcdsaKeymaster1KeyFactory>::LoadKey(KeymasterKeyBlob&& key_material,
-        const AuthorizationSet& additional_params,
-        AuthorizationSet&& hw_enforced,
-        AuthorizationSet&& sw_enforced,
-        UniquePtr<Key>* key) const {
+template <>
+keymaster_error_t Keymaster1ArbitrationFactory<EcdsaKeymaster1KeyFactory>::LoadKey(
+    KeymasterKeyBlob&& key_material, const AuthorizationSet& additional_params,
+    AuthorizationSet&& hw_enforced, AuthorizationSet&& sw_enforced, UniquePtr<Key>* key) const {
     keymaster_digest_t digest;
     if (!additional_params.GetTagValue(TAG_DIGEST, &digest)) {
         digest = KM_DIGEST_NONE;
     }
-    bool requires_software_digesting = legacy_support_.RequiresSoftwareDigesting(digest,
-                                                           AuthProxy(hw_enforced, sw_enforced));
+    bool requires_software_digesting =
+        legacy_support_.RequiresSoftwareDigesting(digest, AuthProxy(hw_enforced, sw_enforced));
     auto rc = software_digest_factory_.LoadKey(move(key_material), additional_params,
                                                move(hw_enforced), move(sw_enforced), key);
     if (rc != KM_ERROR_OK) return rc;
     if (!requires_software_digesting) {
-        (*key)->key_factory() = & passthrough_factory_;
+        (*key)->key_factory() = &passthrough_factory_;
     }
     return KM_ERROR_OK;
 }
 
-template<>
-keymaster_error_t
-Keymaster1ArbitrationFactory<RsaKeymaster1KeyFactory>::LoadKey(KeymasterKeyBlob&& key_material,
-        const AuthorizationSet& additional_params,
-        AuthorizationSet&& hw_enforced,
-        AuthorizationSet&& sw_enforced,
-        UniquePtr<Key>* key) const {
+template <>
+keymaster_error_t Keymaster1ArbitrationFactory<RsaKeymaster1KeyFactory>::LoadKey(
+    KeymasterKeyBlob&& key_material, const AuthorizationSet& additional_params,
+    AuthorizationSet&& hw_enforced, AuthorizationSet&& sw_enforced, UniquePtr<Key>* key) const {
     keymaster_digest_t digest;
     if (!additional_params.GetTagValue(TAG_DIGEST, &digest)) {
         digest = KM_DIGEST_NONE;
     }
-    bool requires_software_digesting = legacy_support_.RequiresSoftwareDigesting(digest,
-                                                           AuthProxy(hw_enforced, sw_enforced));
+    bool requires_software_digesting =
+        legacy_support_.RequiresSoftwareDigesting(digest, AuthProxy(hw_enforced, sw_enforced));
     auto rc = software_digest_factory_.LoadKey(move(key_material), additional_params,
                                                move(hw_enforced), move(sw_enforced), key);
     if (rc != KM_ERROR_OK) return rc;
     if (!requires_software_digesting) {
-        (*key)->key_factory() = & passthrough_factory_;
+        (*key)->key_factory() = &passthrough_factory_;
     }
     return KM_ERROR_OK;
 }
 
-
-} // namespace keymaster
+}  // namespace keymaster
diff --git a/legacy_support/keymaster_passthrough_engine.cpp b/legacy_support/keymaster_passthrough_engine.cpp
index bd8f5b4..ed22320 100644
--- a/legacy_support/keymaster_passthrough_engine.cpp
+++ b/legacy_support/keymaster_passthrough_engine.cpp
@@ -30,7 +30,6 @@
 #define LOG_TAG "Keymaster2Engine"
 #include <android/log.h>
 
-using std::shared_ptr;
 using std::unique_ptr;
 
 namespace keymaster {
@@ -79,7 +78,7 @@
         //        For KM1 the Keymaster1Engine takes ownership
         if (std::is_same<KeymasterDeviceType, keymaster2_device_t>::value)
             km_device_->common.close(
-                    reinterpret_cast<hw_device_t*>(const_cast<KeymasterDeviceType*>(km_device_)));
+                reinterpret_cast<hw_device_t*>(const_cast<KeymasterDeviceType*>(km_device_)));
     }
 
     keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
@@ -91,16 +90,13 @@
                                 const KeymasterKeyBlob& input_key_material,
                                 KeymasterKeyBlob* output_key_blob, AuthorizationSet* hw_enforced,
                                 AuthorizationSet* sw_enforced) const override;
-    keymaster_error_t ExportKey(keymaster_key_format_t format,
-                                const KeymasterKeyBlob& blob,
-                                const KeymasterBlob& client_id,
-                                const KeymasterBlob& app_data,
+    keymaster_error_t ExportKey(keymaster_key_format_t format, const KeymasterKeyBlob& blob,
+                                const KeymasterBlob& client_id, const KeymasterBlob& app_data,
                                 KeymasterBlob* export_data) const override {
         keymaster_blob_t my_export_data = {};
         keymaster_error_t error = km_device_->export_key(km_device_, format, &blob, &client_id,
                                                          &app_data, &my_export_data);
-        if (error != KM_ERROR_OK)
-            return error;
+        if (error != KM_ERROR_OK) return error;
         *export_data = KeymasterBlob(my_export_data.data, my_export_data.data_length);
         free(const_cast<uint8_t*>(my_export_data.data));
         if (export_data->data == nullptr) {
@@ -116,9 +112,9 @@
     }
     OperationFactory* GetOperationFactory(keymaster_purpose_t purpose,
                                           keymaster_algorithm_t algorithm) const override {
-        switch(algorithm) {
+        switch (algorithm) {
         case KM_ALGORITHM_RSA:
-            switch(purpose) {
+            switch (purpose) {
             case KM_PURPOSE_ENCRYPT:
                 return rsa_encrypt_op_factory_.get();
             case KM_PURPOSE_DECRYPT:
@@ -131,7 +127,7 @@
                 return nullptr;
             }
         case KM_ALGORITHM_EC:
-            switch(purpose) {
+            switch (purpose) {
             case KM_PURPOSE_ENCRYPT:
                 return ec_encrypt_op_factory_.get();
             case KM_PURPOSE_DECRYPT:
@@ -146,7 +142,7 @@
                 return nullptr;
             }
         case KM_ALGORITHM_AES:
-            switch(purpose) {
+            switch (purpose) {
             case KM_PURPOSE_ENCRYPT:
                 return aes_encrypt_op_factory_.get();
             case KM_PURPOSE_DECRYPT:
@@ -179,7 +175,7 @@
 
   private:
     TKeymasterPassthroughEngine(const KeymasterPassthroughEngine&) = delete;  // Uncopyable
-    void operator=(const KeymasterPassthroughEngine&) = delete;    // Unassignable
+    void operator=(const KeymasterPassthroughEngine&) = delete;               // Unassignable
 
     const KeymasterDeviceType* const km_device_;
     std::unique_ptr<opfactory_t> rsa_encrypt_op_factory_;
@@ -201,49 +197,41 @@
 
 static void ConvertCharacteristics(const keymaster_key_characteristics_t& characteristics,
                                    AuthorizationSet* hw_enforced, AuthorizationSet* sw_enforced) {
-    if (hw_enforced)
-        hw_enforced->Reinitialize(characteristics.hw_enforced);
-    if (sw_enforced)
-        sw_enforced->Reinitialize(characteristics.sw_enforced);
+    if (hw_enforced) hw_enforced->Reinitialize(characteristics.hw_enforced);
+    if (sw_enforced) sw_enforced->Reinitialize(characteristics.sw_enforced);
 }
 
-template<>
-keymaster_error_t
-TKeymasterPassthroughEngine<keymaster1_device_t>::GenerateKey(const AuthorizationSet& key_description,
-                                                KeymasterKeyBlob* key_blob,
-                                                AuthorizationSet* hw_enforced,
-                                                AuthorizationSet* sw_enforced) const {
+template <>
+keymaster_error_t TKeymasterPassthroughEngine<keymaster1_device_t>::GenerateKey(
+    const AuthorizationSet& key_description, KeymasterKeyBlob* key_blob,
+    AuthorizationSet* hw_enforced, AuthorizationSet* sw_enforced) const {
     assert(key_blob);
 
     keymaster_key_characteristics_t* characteristics = nullptr;
     keymaster_key_blob_t blob = {};
-    keymaster_error_t error = km_device_->generate_key(km_device_, &key_description,
-                                                               &blob, &characteristics);
-    if (error != KM_ERROR_OK)
-        return error;
+    keymaster_error_t error =
+        km_device_->generate_key(km_device_, &key_description, &blob, &characteristics);
+    if (error != KM_ERROR_OK) return error;
     unique_ptr<uint8_t, Malloc_Delete> blob_deleter(const_cast<uint8_t*>(blob.key_material));
     key_blob->key_material = dup_buffer(blob.key_material, blob.key_material_size);
     key_blob->key_material_size = blob.key_material_size;
 
     ConvertCharacteristics(*characteristics, hw_enforced, sw_enforced);
     keymaster_free_characteristics(characteristics);
-    free (characteristics);
+    free(characteristics);
     return error;
 }
-template<>
-keymaster_error_t
-TKeymasterPassthroughEngine<keymaster2_device_t>::GenerateKey(const AuthorizationSet& key_description,
-                                                KeymasterKeyBlob* key_blob,
-                                                AuthorizationSet* hw_enforced,
-                                                AuthorizationSet* sw_enforced) const {
+template <>
+keymaster_error_t TKeymasterPassthroughEngine<keymaster2_device_t>::GenerateKey(
+    const AuthorizationSet& key_description, KeymasterKeyBlob* key_blob,
+    AuthorizationSet* hw_enforced, AuthorizationSet* sw_enforced) const {
     assert(key_blob);
 
     keymaster_key_characteristics_t characteristics = {};
     keymaster_key_blob_t blob = {};
-    keymaster_error_t error = km_device_->generate_key(km_device_, &key_description,
-                                                               &blob, &characteristics);
-    if (error != KM_ERROR_OK)
-        return error;
+    keymaster_error_t error =
+        km_device_->generate_key(km_device_, &key_description, &blob, &characteristics);
+    if (error != KM_ERROR_OK) return error;
     unique_ptr<uint8_t, Malloc_Delete> blob_deleter(const_cast<uint8_t*>(blob.key_material));
     key_blob->key_material = dup_buffer(blob.key_material, blob.key_material_size);
     key_blob->key_material_size = blob.key_material_size;
@@ -253,25 +241,21 @@
     return error;
 }
 
-template<>
-keymaster_error_t
-TKeymasterPassthroughEngine<keymaster1_device_t>::ImportKey(const AuthorizationSet& key_description,
-                                              keymaster_key_format_t input_key_material_format,
-                                              const KeymasterKeyBlob& input_key_material,
-                                              KeymasterKeyBlob* output_key_blob,
-                                              AuthorizationSet* hw_enforced,
-                                              AuthorizationSet* sw_enforced) const {
+template <>
+keymaster_error_t TKeymasterPassthroughEngine<keymaster1_device_t>::ImportKey(
+    const AuthorizationSet& key_description, keymaster_key_format_t input_key_material_format,
+    const KeymasterKeyBlob& input_key_material, KeymasterKeyBlob* output_key_blob,
+    AuthorizationSet* hw_enforced, AuthorizationSet* sw_enforced) const {
     assert(output_key_blob);
 
     keymaster_key_characteristics_t* characteristics = {};
     const keymaster_blob_t input_key = {input_key_material.key_material,
                                         input_key_material.key_material_size};
     keymaster_key_blob_t blob = {};
-    keymaster_error_t error = km_device_->import_key(km_device_, &key_description,
-                                                     input_key_material_format, &input_key,
-                                                     &blob, &characteristics);
-    if (error != KM_ERROR_OK)
-        return error;
+    keymaster_error_t error =
+        km_device_->import_key(km_device_, &key_description, input_key_material_format, &input_key,
+                               &blob, &characteristics);
+    if (error != KM_ERROR_OK) return error;
     unique_ptr<uint8_t, Malloc_Delete> blob_deleter(const_cast<uint8_t*>(blob.key_material));
 
     *output_key_blob = KeymasterKeyBlob(blob);
@@ -282,25 +266,21 @@
     return error;
 }
 
-template<>
-keymaster_error_t
-TKeymasterPassthroughEngine<keymaster2_device_t>::ImportKey(const AuthorizationSet& key_description,
-                                              keymaster_key_format_t input_key_material_format,
-                                              const KeymasterKeyBlob& input_key_material,
-                                              KeymasterKeyBlob* output_key_blob,
-                                              AuthorizationSet* hw_enforced,
-                                              AuthorizationSet* sw_enforced) const {
+template <>
+keymaster_error_t TKeymasterPassthroughEngine<keymaster2_device_t>::ImportKey(
+    const AuthorizationSet& key_description, keymaster_key_format_t input_key_material_format,
+    const KeymasterKeyBlob& input_key_material, KeymasterKeyBlob* output_key_blob,
+    AuthorizationSet* hw_enforced, AuthorizationSet* sw_enforced) const {
     assert(output_key_blob);
 
     keymaster_key_characteristics_t characteristics = {};
     const keymaster_blob_t input_key = {input_key_material.key_material,
                                         input_key_material.key_material_size};
     keymaster_key_blob_t blob = {};
-    keymaster_error_t error = km_device_->import_key(km_device_, &key_description,
-                                                     input_key_material_format, &input_key,
-                                                     &blob, &characteristics);
-    if (error != KM_ERROR_OK)
-        return error;
+    keymaster_error_t error =
+        km_device_->import_key(km_device_, &key_description, input_key_material_format, &input_key,
+                               &blob, &characteristics);
+    if (error != KM_ERROR_OK) return error;
     unique_ptr<uint8_t, Malloc_Delete> blob_deleter(const_cast<uint8_t*>(blob.key_material));
     // TODO why duplicate the blob if we have ownership here anyway?
     output_key_blob->key_material = dup_buffer(blob.key_material, blob.key_material_size);
@@ -313,12 +293,10 @@
 
 typedef UniquePtr<KeymasterPassthroughEngine> engine_ptr_t;
 
-engine_ptr_t
-KeymasterPassthroughEngine::createInstance(const keymaster1_device_t* dev) {
+engine_ptr_t KeymasterPassthroughEngine::createInstance(const keymaster1_device_t* dev) {
     return engine_ptr_t(new TKeymasterPassthroughEngine<keymaster1_device_t>(dev));
 }
-engine_ptr_t
-KeymasterPassthroughEngine::createInstance(const keymaster2_device_t* dev) {
+engine_ptr_t KeymasterPassthroughEngine::createInstance(const keymaster2_device_t* dev) {
     return engine_ptr_t(new TKeymasterPassthroughEngine<keymaster2_device_t>(dev));
 }
 
diff --git a/legacy_support/keymaster_passthrough_key.cpp b/legacy_support/keymaster_passthrough_key.cpp
index f8d8f62..52b56e8 100644
--- a/legacy_support/keymaster_passthrough_key.cpp
+++ b/legacy_support/keymaster_passthrough_key.cpp
@@ -19,21 +19,18 @@
 
 namespace keymaster {
 
-keymaster_error_t
-KeymasterPassthroughKeyFactory::LoadKey(KeymasterKeyBlob&& key_material,
-                          const AuthorizationSet& additional_params,
-                          AuthorizationSet&& hw_enforced,
-                          AuthorizationSet&& sw_enforced,
-                          UniquePtr<Key>* key) const {
+keymaster_error_t KeymasterPassthroughKeyFactory::LoadKey(KeymasterKeyBlob&& key_material,
+                                                          const AuthorizationSet& additional_params,
+                                                          AuthorizationSet&& hw_enforced,
+                                                          AuthorizationSet&& sw_enforced,
+                                                          UniquePtr<Key>* key) const {
     keymaster_error_t error = KM_ERROR_OK;
-    if (!key)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    if (!key) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
-    key->reset(new (std::nothrow) KeymasterPassthroughKey(move(key_material), move(hw_enforced),
-                                                          move(sw_enforced), this, &error,
-                                                          additional_params, engine_));
-    if (!key->get())
-        error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    key->reset(new (std::nothrow)
+                   KeymasterPassthroughKey(move(key_material), move(hw_enforced), move(sw_enforced),
+                                           this, &error, additional_params, engine_));
+    if (!key->get()) error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
     return error;
 }
@@ -49,11 +46,9 @@
     return nullptr;
 }
 
-
-keymaster_error_t
-KeymasterPassthroughKey::formatted_key_material(keymaster_key_format_t format,
-                                                UniquePtr<uint8_t[]>* material,
-                                                size_t* size) const {
+keymaster_error_t KeymasterPassthroughKey::formatted_key_material(keymaster_key_format_t format,
+                                                                  UniquePtr<uint8_t[]>* material,
+                                                                  size_t* size) const {
     if (!material || !size) {
         return KM_ERROR_OUTPUT_PARAMETER_NULL;
     }
@@ -71,8 +66,8 @@
 
     KeymasterBlob export_data;
 
-    keymaster_error_t error = engine_->ExportKey(format, key_material(), client_id, app_data,
-                                                 &export_data);
+    keymaster_error_t error =
+        engine_->ExportKey(format, key_material(), client_id, app_data, &export_data);
     if (error == KM_ERROR_OK) {
         keymaster_blob_t export_blob = export_data.release();
         material->reset(const_cast<uint8_t*>(export_blob.data));
diff --git a/legacy_support/keymaster_passthrough_operation.cpp b/legacy_support/keymaster_passthrough_operation.cpp
index 9b21058..7b10722 100644
--- a/legacy_support/keymaster_passthrough_operation.cpp
+++ b/legacy_support/keymaster_passthrough_operation.cpp
@@ -16,19 +16,17 @@
 */
 
 #include "keymaster_passthrough_operation.h"
-#include <vector>
 #include <keymaster/android_keymaster_utils.h>
+#include <vector>
 
 namespace keymaster {
 
-template<>
-keymaster_error_t
-KeymasterPassthroughOperation<keymaster1_device_t>::Finish(const AuthorizationSet& input_params,
-                                 const Buffer& input,
-                                 const Buffer& signature, AuthorizationSet* output_params,
-                                 Buffer* output) {
+template <>
+keymaster_error_t KeymasterPassthroughOperation<keymaster1_device_t>::Finish(
+    const AuthorizationSet& input_params, const Buffer& input, const Buffer& signature,
+    AuthorizationSet* output_params, Buffer* output) {
     keymaster_key_param_set_t out_params = {};
-    keymaster_blob_t in{ input.peek_read(), input.available_read() };
+    keymaster_blob_t in{input.peek_read(), input.available_read()};
     keymaster_blob_t out = {};
     keymaster_error_t rc;
     std::vector<KeymasterBlob> accumulate_output;
@@ -37,7 +35,8 @@
     AuthorizationSet mutable_input_params = input_params;
     while (in.data_length != 0) {
         size_t consumed = 0;
-        rc = km_device_->update(km_device_, operation_handle_, &mutable_input_params, &in, &consumed, &out_params, &out);
+        rc = km_device_->update(km_device_, operation_handle_, &mutable_input_params, &in,
+                                &consumed, &out_params, &out);
         if (rc == KM_ERROR_OK) {
             accumulate_output.push_back(KeymasterBlob(out));
             accumulated_output_size += out.data_length;
@@ -64,9 +63,10 @@
         }
     }
 
-    keymaster_blob_t sig{ signature.peek_read(), signature.available_read() };
+    keymaster_blob_t sig{signature.peek_read(), signature.available_read()};
 
-    rc = km_device_->finish(km_device_, operation_handle_, &mutable_input_params, &sig, &out_params, &out);
+    rc = km_device_->finish(km_device_, operation_handle_, &mutable_input_params, &sig, &out_params,
+                            &out);
     if (rc != KM_ERROR_OK) return rc;
     accumulate_output.push_back(KeymasterBlob(out));
     accumulated_output_size += out.data_length;
@@ -79,7 +79,7 @@
         if (!output->reserve(accumulated_output_size)) {
             return KM_ERROR_MEMORY_ALLOCATION_FAILED;
         }
-        for (auto& outBlob: accumulate_output) {
+        for (auto& outBlob : accumulate_output) {
             output->write(outBlob.data, outBlob.data_length);
         }
     }
@@ -90,17 +90,17 @@
     return KM_ERROR_OK;
 }
 
-template<>
-keymaster_error_t
-KeymasterPassthroughOperation<keymaster2_device_t>::Finish(const AuthorizationSet& input_params, const Buffer& input,
-                                 const Buffer& signature, AuthorizationSet* output_params,
-                                 Buffer* output) {
+template <>
+keymaster_error_t KeymasterPassthroughOperation<keymaster2_device_t>::Finish(
+    const AuthorizationSet& input_params, const Buffer& input, const Buffer& signature,
+    AuthorizationSet* output_params, Buffer* output) {
     keymaster_key_param_set_t out_params = {};
-    keymaster_blob_t sig{ signature.peek_read(), signature.available_read() };
-    keymaster_blob_t in{ input.peek_read(), input.available_read() };
+    keymaster_blob_t sig{signature.peek_read(), signature.available_read()};
+    keymaster_blob_t in{input.peek_read(), input.available_read()};
     keymaster_blob_t out = {};
     keymaster_error_t rc;
-    rc = km_device_->finish(km_device_, operation_handle_, &input_params, &in, &sig, &out_params, &out);
+    rc = km_device_->finish(km_device_, operation_handle_, &input_params, &in, &sig, &out_params,
+                            &out);
     if (rc == KM_ERROR_OK) {
         if (output) output->Reinitialize(out.data, out.data_length);
         if (output_params) output_params->Reinitialize(out_params);
diff --git a/legacy_support/rsa_keymaster0_key.cpp b/legacy_support/rsa_keymaster0_key.cpp
deleted file mode 100644
index 0f3bf27..0000000
--- a/legacy_support/rsa_keymaster0_key.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright 2015 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 <keymaster/legacy_support/rsa_keymaster0_key.h>
-
-#include <memory>
-
-#include <keymaster/android_keymaster_utils.h>
-#include <keymaster/contexts/soft_keymaster_context.h>
-#include <keymaster/km_openssl/openssl_utils.h>
-#include <keymaster/legacy_support/keymaster0_engine.h>
-#include <keymaster/logger.h>
-
-
-using std::unique_ptr;
-
-namespace keymaster {
-
-RsaKeymaster0KeyFactory::RsaKeymaster0KeyFactory(const SoftwareKeyBlobMaker* blob_maker,
-                                                 const Keymaster0Engine* engine)
-    : RsaKeyFactory(blob_maker), engine_(engine) {}
-
-keymaster_error_t RsaKeymaster0KeyFactory::GenerateKey(const AuthorizationSet& key_description,
-                                                       KeymasterKeyBlob* key_blob,
-                                                       AuthorizationSet* hw_enforced,
-                                                       AuthorizationSet* sw_enforced) const {
-    if (!key_blob || !hw_enforced || !sw_enforced)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
-
-    uint64_t public_exponent;
-    if (!key_description.GetTagValue(TAG_RSA_PUBLIC_EXPONENT, &public_exponent)) {
-        LOG_E("%s", "No public exponent specified for RSA key generation");
-        return KM_ERROR_INVALID_ARGUMENT;
-    }
-
-    uint32_t key_size;
-    if (!key_description.GetTagValue(TAG_KEY_SIZE, &key_size)) {
-        LOG_E("%s", "No key size specified for RSA key generation");
-        return KM_ERROR_UNSUPPORTED_KEY_SIZE;
-    }
-
-    KeymasterKeyBlob key_material;
-    if (!engine_->GenerateRsaKey(public_exponent, key_size, &key_material))
-        return KM_ERROR_UNKNOWN_ERROR;
-
-    // These tags are hardware-enforced.  Putting them in the hw_enforced set here will ensure that
-    // blob_maker_->CreateKeyBlob doesn't put them in sw_enforced.
-    hw_enforced->push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
-    hw_enforced->push_back(TAG_RSA_PUBLIC_EXPONENT, public_exponent);
-    hw_enforced->push_back(TAG_KEY_SIZE, key_size);
-    hw_enforced->push_back(TAG_ORIGIN, KM_ORIGIN_UNKNOWN);
-
-    return blob_maker_.CreateKeyBlob(key_description, KM_ORIGIN_UNKNOWN, key_material, key_blob,
-                                     hw_enforced, sw_enforced);
-}
-
-keymaster_error_t RsaKeymaster0KeyFactory::ImportKey(
-    const AuthorizationSet& key_description, keymaster_key_format_t input_key_material_format,
-    const KeymasterKeyBlob& input_key_material, KeymasterKeyBlob* output_key_blob,
-    AuthorizationSet* hw_enforced, AuthorizationSet* sw_enforced) const {
-    if (!output_key_blob || !hw_enforced || !sw_enforced)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
-
-    AuthorizationSet authorizations;
-    uint64_t public_exponent;
-    uint32_t key_size;
-    keymaster_error_t error =
-        UpdateImportKeyDescription(key_description, input_key_material_format, input_key_material,
-                                   &authorizations, &public_exponent, &key_size);
-    if (error != KM_ERROR_OK)
-        return error;
-
-    KeymasterKeyBlob imported_hw_key;
-    if (!engine_->ImportKey(input_key_material_format, input_key_material, &imported_hw_key))
-        return KM_ERROR_UNKNOWN_ERROR;
-
-    // These tags are hardware-enforced.  Putting them in the hw_enforced set here will ensure that
-    // blob_maker_->CreateKeyBlob doesn't put them in sw_enforced.
-    hw_enforced->push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
-    hw_enforced->push_back(TAG_RSA_PUBLIC_EXPONENT, public_exponent);
-    hw_enforced->push_back(TAG_KEY_SIZE, key_size);
-    hw_enforced->push_back(TAG_ORIGIN, KM_ORIGIN_UNKNOWN);
-
-    return blob_maker_.CreateKeyBlob(authorizations, KM_ORIGIN_UNKNOWN, imported_hw_key,
-                                     output_key_blob, hw_enforced, sw_enforced);
-}
-
-keymaster_error_t RsaKeymaster0KeyFactory::LoadKey(KeymasterKeyBlob&& key_material,
-                                                   const AuthorizationSet& additional_params,
-                                                   AuthorizationSet&& hw_enforced,
-                                                   AuthorizationSet&& sw_enforced,
-                                                   UniquePtr<Key>* key) const {
-    if (!key)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
-
-    if (sw_enforced.GetTagCount(TAG_ALGORITHM) == 1)
-        return super::LoadKey(move(key_material), additional_params, move(hw_enforced),
-                              move(sw_enforced), key);
-
-    unique_ptr<RSA, RSA_Delete> rsa(engine_->BlobToRsaKey(key_material));
-    if (!rsa)
-        return KM_ERROR_UNKNOWN_ERROR;
-
-    key->reset(new (std::nothrow)
-                   RsaKeymaster0Key(rsa.release(), move(hw_enforced), move(sw_enforced), this));
-    if (!(*key))
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
-    (*key)->key_material() = move(key_material);
-    return KM_ERROR_OK;
-}
-
-}  // namespace keymaster
diff --git a/legacy_support/rsa_keymaster1_key.cpp b/legacy_support/rsa_keymaster1_key.cpp
index 1644f3f..5859bde 100644
--- a/legacy_support/rsa_keymaster1_key.cpp
+++ b/legacy_support/rsa_keymaster1_key.cpp
@@ -24,9 +24,10 @@
 
 namespace keymaster {
 
-RsaKeymaster1KeyFactory::RsaKeymaster1KeyFactory(const SoftwareKeyBlobMaker* blob_maker,
+RsaKeymaster1KeyFactory::RsaKeymaster1KeyFactory(const SoftwareKeyBlobMaker& blob_maker,
+                                                 const KeymasterContext& context,
                                                  const Keymaster1Engine* engine)
-    : RsaKeyFactory(blob_maker), engine_(engine),
+    : RsaKeyFactory(blob_maker, context), engine_(engine),
       sign_factory_(new RsaKeymaster1OperationFactory(KM_PURPOSE_SIGN, engine)),
       decrypt_factory_(new RsaKeymaster1OperationFactory(KM_PURPOSE_DECRYPT, engine)),
       // For pubkey ops we can use the normal operation factories.
@@ -80,18 +81,27 @@
 }
 
 keymaster_error_t RsaKeymaster1KeyFactory::GenerateKey(const AuthorizationSet& key_description,
+                                                       UniquePtr<Key> /* attest_key */,
+                                                       const KeymasterBlob& /* issuer_subject */,
                                                        KeymasterKeyBlob* key_blob,
                                                        AuthorizationSet* hw_enforced,
-                                                       AuthorizationSet* sw_enforced) const {
+                                                       AuthorizationSet* sw_enforced,
+                                                       CertificateChain* /* cert_chain */) const {
     AuthorizationSet key_params_copy;
     UpdateToWorkAroundUnsupportedDigests(key_description, &key_params_copy);
     return engine_->GenerateKey(key_params_copy, key_blob, hw_enforced, sw_enforced);
 }
 
-keymaster_error_t RsaKeymaster1KeyFactory::ImportKey(
-    const AuthorizationSet& key_description, keymaster_key_format_t input_key_material_format,
-    const KeymasterKeyBlob& input_key_material, KeymasterKeyBlob* output_key_blob,
-    AuthorizationSet* hw_enforced, AuthorizationSet* sw_enforced) const {
+keymaster_error_t  //
+RsaKeymaster1KeyFactory::ImportKey(const AuthorizationSet& key_description,
+                                   keymaster_key_format_t input_key_material_format,
+                                   const KeymasterKeyBlob& input_key_material,
+                                   UniquePtr<Key> /* attest_key */,
+                                   const KeymasterBlob& /* issuer_subject */,
+                                   KeymasterKeyBlob* output_key_blob,  //
+                                   AuthorizationSet* hw_enforced,      //
+                                   AuthorizationSet* sw_enforced,
+                                   CertificateChain* /* cert_chain */) const {
     AuthorizationSet key_params_copy;
     UpdateToWorkAroundUnsupportedDigests(key_description, &key_params_copy);
     return engine_->ImportKey(key_params_copy, input_key_material_format, input_key_material,
@@ -103,18 +113,15 @@
                                                    AuthorizationSet&& hw_enforced,
                                                    AuthorizationSet&& sw_enforced,
                                                    UniquePtr<Key>* key) const {
-    if (!key)
-        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+    if (!key) return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     keymaster_error_t error;
     RSA_Ptr rsa(engine_->BuildRsaKey(key_material, additional_params, &error));
-    if (!rsa.get())
-        return error;
+    if (!rsa.get()) return error;
 
     key->reset(new (std::nothrow)
                    RsaKeymaster1Key(rsa.release(), move(hw_enforced), move(sw_enforced), this));
-    if (!(*key))
-        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    if (!(*key)) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
     (*key)->key_material() = move(key_material);
     return KM_ERROR_OK;
@@ -132,6 +139,8 @@
         return decrypt_factory_.get();
     case KM_PURPOSE_DERIVE_KEY:
     case KM_PURPOSE_WRAP:
+    case KM_PURPOSE_AGREE_KEY:
+    case KM_PURPOSE_ATTEST_KEY:
         break;
     }
     return nullptr;
diff --git a/legacy_support/rsa_keymaster1_operation.cpp b/legacy_support/rsa_keymaster1_operation.cpp
index dd2c094..cceff47 100644
--- a/legacy_support/rsa_keymaster1_operation.cpp
+++ b/legacy_support/rsa_keymaster1_operation.cpp
@@ -30,8 +30,7 @@
 keymaster_error_t RsaKeymaster1WrappedOperation::Begin(EVP_PKEY* rsa_key,
                                                        const AuthorizationSet& input_params) {
     Keymaster1Engine::KeyData* key_data = engine_->GetData(rsa_key);
-    if (!key_data)
-        return KM_ERROR_UNKNOWN_ERROR;
+    if (!key_data) return KM_ERROR_UNKNOWN_ERROR;
 
     // Copy the input params and substitute KM_DIGEST_NONE for whatever was specified.  Also change
     // KM_PAD_RSA_PSS and KM_PAD_OAEP to KM_PAD_NONE, if necessary. These are the params we'll pass
@@ -57,8 +56,7 @@
     }
 
     pos = begin_params.find(TAG_PADDING);
-    if (pos == -1)
-        return KM_ERROR_UNSUPPORTED_PADDING_MODE;
+    if (pos == -1) return KM_ERROR_UNSUPPORTED_PADDING_MODE;
     switch (begin_params[pos].enumerated) {
     case KM_PAD_NONE:
     case KM_PAD_RSA_PSS:
@@ -97,8 +95,7 @@
 
 keymaster_error_t RsaKeymaster1WrappedOperation::GetError(EVP_PKEY* rsa_key) {
     Keymaster1Engine::KeyData* key_data = engine_->GetData(rsa_key);  // key_data is owned by rsa
-    if (!key_data)
-        return KM_ERROR_UNKNOWN_ERROR;
+    if (!key_data) return KM_ERROR_UNKNOWN_ERROR;
     return key_data->error;
 }
 
@@ -157,10 +154,14 @@
 }
 
 static const keymaster_padding_t supported_sig_padding[] = {
-    KM_PAD_NONE, KM_PAD_RSA_PKCS1_1_5_SIGN, KM_PAD_RSA_PSS,
+    KM_PAD_NONE,
+    KM_PAD_RSA_PKCS1_1_5_SIGN,
+    KM_PAD_RSA_PSS,
 };
 static const keymaster_padding_t supported_crypt_padding[] = {
-    KM_PAD_NONE, KM_PAD_RSA_PKCS1_1_5_ENCRYPT, KM_PAD_RSA_OAEP,
+    KM_PAD_NONE,
+    KM_PAD_RSA_PKCS1_1_5_ENCRYPT,
+    KM_PAD_RSA_OAEP,
 };
 
 const keymaster_padding_t*
diff --git a/legacy_support/rsa_keymaster1_operation.h b/legacy_support/rsa_keymaster1_operation.h
index c0219ea..124c4b7 100644
--- a/legacy_support/rsa_keymaster1_operation.h
+++ b/legacy_support/rsa_keymaster1_operation.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_RSA_KEYMASTER1_OPERATION_H_
-#define SYSTEM_KEYMASTER_RSA_KEYMASTER1_OPERATION_H_
+#pragma once
 
 #include <openssl/evp.h>
 
@@ -32,8 +31,7 @@
     RsaKeymaster1WrappedOperation(keymaster_purpose_t purpose, const Keymaster1Engine* engine)
         : purpose_(purpose), operation_handle_(0), engine_(engine) {}
     ~RsaKeymaster1WrappedOperation() {
-        if (operation_handle_)
-            Abort();
+        if (operation_handle_) Abort();
     }
 
     keymaster_error_t Begin(EVP_PKEY* rsa_key, const AuthorizationSet& input_params);
@@ -43,6 +41,7 @@
     keymaster_error_t GetError(EVP_PKEY* rsa_key);
 
     keymaster_operation_handle_t GetOperationHandle() const { return operation_handle_; }
+
   protected:
     keymaster_purpose_t purpose_;
     keymaster_operation_handle_t operation_handle_;
@@ -66,8 +65,7 @@
     keymaster_error_t Begin(const AuthorizationSet& input_params,
                             AuthorizationSet* output_params) override {
         keymaster_error_t error = wrapped_operation_.Begin(super::rsa_key_, input_params);
-        if (error != KM_ERROR_OK)
-            return error;
+        if (error != KM_ERROR_OK) return error;
         return super::Begin(input_params, output_params);
     }
 
@@ -75,8 +73,7 @@
                              const Buffer& signature, AuthorizationSet* output_params,
                              Buffer* output) override {
         keymaster_error_t error = wrapped_operation_.PrepareFinish(super::rsa_key_, input_params);
-        if (error != KM_ERROR_OK)
-            return error;
+        if (error != KM_ERROR_OK) return error;
         error = super::Finish(input_params, input, signature, output_params, output);
         if (wrapped_operation_.GetError(super::rsa_key_) != KM_ERROR_OK)
             error = wrapped_operation_.GetError(super::rsa_key_);
@@ -85,14 +82,14 @@
 
     keymaster_error_t Abort() override {
         keymaster_error_t error = wrapped_operation_.Abort();
-        if (error != KM_ERROR_OK)
-            return error;
+        if (error != KM_ERROR_OK) return error;
         return super::Abort();
     }
 
     keymaster_operation_handle_t operation_handle() const override {
         return wrapped_operation_.GetOperationHandle();
     }
+
   private:
     RsaKeymaster1WrappedOperation wrapped_operation_;
 };
@@ -119,5 +116,3 @@
 };
 
 }  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_RSA_KEYMASTER1_OPERATION_H_
diff --git a/ng/AndroidKeyMintDevice.cpp b/ng/AndroidKeyMintDevice.cpp
new file mode 100644
index 0000000..f511c3f
--- /dev/null
+++ b/ng/AndroidKeyMintDevice.cpp
@@ -0,0 +1,472 @@
+/*
+ * Copyright 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.security.keymint-impl"
+#include <android-base/logging.h>
+
+#include "AndroidKeyMintDevice.h"
+
+#include <aidl/android/hardware/security/keymint/ErrorCode.h>
+
+#include <keymaster/android_keymaster.h>
+#include <keymaster/contexts/pure_soft_keymaster_context.h>
+#include <keymaster/keymaster_configuration.h>
+
+#include "AndroidKeyMintOperation.h"
+#include "KeyMintUtils.h"
+
+namespace aidl::android::hardware::security::keymint {
+
+using namespace keymaster;  // NOLINT(google-build-using-namespace)
+
+using km_utils::authToken2AidlVec;
+using km_utils::kmBlob2vector;
+using km_utils::kmError2ScopedAStatus;
+using km_utils::kmParam2Aidl;
+using km_utils::KmParamSet;
+using km_utils::kmParamSet2Aidl;
+using km_utils::legacy_enum_conversion;
+using secureclock::TimeStampToken;
+
+namespace {
+
+vector<KeyCharacteristics> convertKeyCharacteristics(SecurityLevel keyMintSecurityLevel,
+                                                     const AuthorizationSet& requestParams,
+                                                     const AuthorizationSet& sw_enforced,
+                                                     const AuthorizationSet& hw_enforced,
+                                                     bool include_keystore_enforced = true) {
+    KeyCharacteristics keyMintEnforced{keyMintSecurityLevel, {}};
+
+    if (keyMintSecurityLevel != SecurityLevel::SOFTWARE) {
+        // We're pretending to be TRUSTED_ENVIRONMENT or STRONGBOX.
+        keyMintEnforced.authorizations = kmParamSet2Aidl(hw_enforced);
+        if (include_keystore_enforced) {
+            // Put all the software authorizations in the keystore list.
+            KeyCharacteristics keystoreEnforced{SecurityLevel::KEYSTORE,
+                                                kmParamSet2Aidl(sw_enforced)};
+            return {std::move(keyMintEnforced), std::move(keystoreEnforced)};
+        } else {
+            return {std::move(keyMintEnforced)};
+        }
+    }
+
+    KeyCharacteristics keystoreEnforced{SecurityLevel::KEYSTORE, {}};
+    CHECK(hw_enforced.empty()) << "Hardware-enforced list is non-empty for pure SW KeyMint";
+
+    // This is a pure software implementation, so all tags are in sw_enforced.
+    // We need to walk through the SW-enforced list and figure out which tags to
+    // return in the software list and which in the keystore list.
+
+    for (auto& entry : sw_enforced) {
+        switch (entry.tag) {
+        /* Invalid and unused */
+        case KM_TAG_ECIES_SINGLE_HASH_MODE:
+        case KM_TAG_INVALID:
+        case KM_TAG_KDF:
+        case KM_TAG_ROLLBACK_RESISTANCE:
+            CHECK(false) << "We shouldn't see tag " << entry.tag;
+            break;
+
+        /* Unimplemented */
+        case KM_TAG_ALLOW_WHILE_ON_BODY:
+        case KM_TAG_BOOTLOADER_ONLY:
+        case KM_TAG_ROLLBACK_RESISTANT:
+        case KM_TAG_STORAGE_KEY:
+            break;
+
+        /* Keystore-enforced if not locally generated. */
+        case KM_TAG_CREATION_DATETIME:
+            // A KeyMaster implementation is required to add this tag to generated/imported keys.
+            // A KeyMint implementation is not required to create this tag, only to echo it back if
+            // it was included in the key generation/import request.
+            if (requestParams.Contains(KM_TAG_CREATION_DATETIME)) {
+                keystoreEnforced.authorizations.push_back(kmParam2Aidl(entry));
+            }
+            break;
+
+        /* Disallowed in KeyCharacteristics */
+        case KM_TAG_APPLICATION_DATA:
+        case KM_TAG_ATTESTATION_APPLICATION_ID:
+            break;
+
+        /* Not key characteristics */
+        case KM_TAG_ASSOCIATED_DATA:
+        case KM_TAG_ATTESTATION_CHALLENGE:
+        case KM_TAG_ATTESTATION_ID_BRAND:
+        case KM_TAG_ATTESTATION_ID_DEVICE:
+        case KM_TAG_ATTESTATION_ID_IMEI:
+        case KM_TAG_ATTESTATION_ID_MANUFACTURER:
+        case KM_TAG_ATTESTATION_ID_MEID:
+        case KM_TAG_ATTESTATION_ID_MODEL:
+        case KM_TAG_ATTESTATION_ID_PRODUCT:
+        case KM_TAG_ATTESTATION_ID_SERIAL:
+        case KM_TAG_AUTH_TOKEN:
+        case KM_TAG_CERTIFICATE_SERIAL:
+        case KM_TAG_CERTIFICATE_SUBJECT:
+        case KM_TAG_CERTIFICATE_NOT_AFTER:
+        case KM_TAG_CERTIFICATE_NOT_BEFORE:
+        case KM_TAG_CONFIRMATION_TOKEN:
+        case KM_TAG_DEVICE_UNIQUE_ATTESTATION:
+        case KM_TAG_IDENTITY_CREDENTIAL_KEY:
+        case KM_TAG_MAC_LENGTH:
+        case KM_TAG_NONCE:
+        case KM_TAG_RESET_SINCE_ID_ROTATION:
+        case KM_TAG_ROOT_OF_TRUST:
+        case KM_TAG_UNIQUE_ID:
+            break;
+
+        /* KeyMint-enforced */
+        case KM_TAG_ALGORITHM:
+        case KM_TAG_APPLICATION_ID:
+        case KM_TAG_AUTH_TIMEOUT:
+        case KM_TAG_BLOB_USAGE_REQUIREMENTS:
+        case KM_TAG_BLOCK_MODE:
+        case KM_TAG_BOOT_PATCHLEVEL:
+        case KM_TAG_CALLER_NONCE:
+        case KM_TAG_DIGEST:
+        case KM_TAG_EARLY_BOOT_ONLY:
+        case KM_TAG_EC_CURVE:
+        case KM_TAG_EXPORTABLE:
+        case KM_TAG_INCLUDE_UNIQUE_ID:
+        case KM_TAG_KEY_SIZE:
+        case KM_TAG_MAX_USES_PER_BOOT:
+        case KM_TAG_MIN_MAC_LENGTH:
+        case KM_TAG_MIN_SECONDS_BETWEEN_OPS:
+        case KM_TAG_NO_AUTH_REQUIRED:
+        case KM_TAG_ORIGIN:
+        case KM_TAG_OS_PATCHLEVEL:
+        case KM_TAG_OS_VERSION:
+        case KM_TAG_PADDING:
+        case KM_TAG_PURPOSE:
+        case KM_TAG_RSA_OAEP_MGF_DIGEST:
+        case KM_TAG_RSA_PUBLIC_EXPONENT:
+        case KM_TAG_TRUSTED_CONFIRMATION_REQUIRED:
+        case KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED:
+        case KM_TAG_UNLOCKED_DEVICE_REQUIRED:
+        case KM_TAG_USER_AUTH_TYPE:
+        case KM_TAG_USER_SECURE_ID:
+        case KM_TAG_VENDOR_PATCHLEVEL:
+            keyMintEnforced.authorizations.push_back(kmParam2Aidl(entry));
+            break;
+
+        /* Keystore-enforced */
+        case KM_TAG_ACTIVE_DATETIME:
+        case KM_TAG_ALL_APPLICATIONS:
+        case KM_TAG_ALL_USERS:
+        case KM_TAG_MAX_BOOT_LEVEL:
+        case KM_TAG_ORIGINATION_EXPIRE_DATETIME:
+        case KM_TAG_USAGE_EXPIRE_DATETIME:
+        case KM_TAG_USER_ID:
+        case KM_TAG_USAGE_COUNT_LIMIT:
+            keystoreEnforced.authorizations.push_back(kmParam2Aidl(entry));
+            break;
+        }
+    }
+
+    vector<KeyCharacteristics> retval;
+    retval.reserve(2);
+    if (!keyMintEnforced.authorizations.empty()) retval.push_back(std::move(keyMintEnforced));
+    if (include_keystore_enforced && !keystoreEnforced.authorizations.empty()) {
+        retval.push_back(std::move(keystoreEnforced));
+    }
+
+    return retval;
+}
+
+Certificate convertCertificate(const keymaster_blob_t& cert) {
+    return {std::vector<uint8_t>(cert.data, cert.data + cert.data_length)};
+}
+
+vector<Certificate> convertCertificateChain(const CertificateChain& chain) {
+    vector<Certificate> retval;
+    retval.reserve(chain.entry_count);
+    std::transform(chain.begin(), chain.end(), std::back_inserter(retval), convertCertificate);
+    return retval;
+}
+
+void addClientAndAppData(const std::vector<uint8_t>& appId, const std::vector<uint8_t>& appData,
+                         ::keymaster::AuthorizationSet* params) {
+    params->Clear();
+    if (appId.size()) {
+        params->push_back(::keymaster::TAG_APPLICATION_ID, appId.data(), appId.size());
+    }
+    if (appData.size()) {
+        params->push_back(::keymaster::TAG_APPLICATION_DATA, appData.data(), appData.size());
+    }
+}
+
+}  // namespace
+
+constexpr size_t kOperationTableSize = 16;
+
+AndroidKeyMintDevice::AndroidKeyMintDevice(SecurityLevel securityLevel)
+    : impl_(new ::keymaster::AndroidKeymaster(
+          [&]() -> auto {
+              auto context = new PureSoftKeymasterContext(
+                  KmVersion::KEYMINT_1, static_cast<keymaster_security_level_t>(securityLevel));
+              context->SetSystemVersion(::keymaster::GetOsVersion(),
+                                        ::keymaster::GetOsPatchlevel());
+              return context;
+          }(),
+          kOperationTableSize)),
+      securityLevel_(securityLevel) {}
+
+AndroidKeyMintDevice::~AndroidKeyMintDevice() {}
+
+ScopedAStatus AndroidKeyMintDevice::getHardwareInfo(KeyMintHardwareInfo* info) {
+    info->versionNumber = 1;
+    info->securityLevel = securityLevel_;
+    info->keyMintName = "FakeKeyMintDevice";
+    info->keyMintAuthorName = "Google";
+    info->timestampTokenRequired = false;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus AndroidKeyMintDevice::addRngEntropy(const vector<uint8_t>& data) {
+    if (data.size() == 0) {
+        return ScopedAStatus::ok();
+    }
+
+    AddEntropyRequest request(impl_->message_version());
+    request.random_data.Reinitialize(data.data(), data.size());
+
+    AddEntropyResponse response(impl_->message_version());
+    impl_->AddRngEntropy(request, &response);
+
+    return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus AndroidKeyMintDevice::generateKey(const vector<KeyParameter>& keyParams,
+                                                const optional<AttestationKey>& attestationKey,
+                                                KeyCreationResult* creationResult) {
+
+    GenerateKeyRequest request(impl_->message_version());
+    request.key_description.Reinitialize(KmParamSet(keyParams));
+    if (attestationKey) {
+        request.attestation_signing_key_blob =
+            KeymasterKeyBlob(attestationKey->keyBlob.data(), attestationKey->keyBlob.size());
+        request.attest_key_params.Reinitialize(KmParamSet(attestationKey->attestKeyParams));
+        request.issuer_subject = KeymasterBlob(attestationKey->issuerSubjectName.data(),
+                                               attestationKey->issuerSubjectName.size());
+    }
+
+    GenerateKeyResponse response(impl_->message_version());
+    impl_->GenerateKey(request, &response);
+
+    if (response.error != KM_ERROR_OK) {
+        // Note a key difference between this current aidl and previous hal, is
+        // that hal returns void where as aidl returns the error status.  If
+        // aidl returns error, then aidl will not return any change you may make
+        // to the out parameters.  This is quite different from hal where all
+        // output variable can be modified due to hal returning void.
+        //
+        // So the caller need to be aware not to expect aidl functions to clear
+        // the output variables for you in case of error.  If you left some
+        // wrong data set in the out parameters, they will stay there.
+        return kmError2ScopedAStatus(response.error);
+    }
+
+    creationResult->keyBlob = kmBlob2vector(response.key_blob);
+    creationResult->keyCharacteristics = convertKeyCharacteristics(
+        securityLevel_, request.key_description, response.unenforced, response.enforced);
+    creationResult->certificateChain = convertCertificateChain(response.certificate_chain);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus AndroidKeyMintDevice::importKey(const vector<KeyParameter>& keyParams,
+                                              KeyFormat keyFormat, const vector<uint8_t>& keyData,
+                                              const optional<AttestationKey>& attestationKey,
+                                              KeyCreationResult* creationResult) {
+
+    ImportKeyRequest request(impl_->message_version());
+    request.key_description.Reinitialize(KmParamSet(keyParams));
+    request.key_format = legacy_enum_conversion(keyFormat);
+    request.key_data = KeymasterKeyBlob(keyData.data(), keyData.size());
+    if (attestationKey) {
+        request.attestation_signing_key_blob =
+            KeymasterKeyBlob(attestationKey->keyBlob.data(), attestationKey->keyBlob.size());
+        request.attest_key_params.Reinitialize(KmParamSet(attestationKey->attestKeyParams));
+        request.issuer_subject = KeymasterBlob(attestationKey->issuerSubjectName.data(),
+                                               attestationKey->issuerSubjectName.size());
+    }
+
+    ImportKeyResponse response(impl_->message_version());
+    impl_->ImportKey(request, &response);
+
+    if (response.error != KM_ERROR_OK) {
+        return kmError2ScopedAStatus(response.error);
+    }
+
+    creationResult->keyBlob = kmBlob2vector(response.key_blob);
+    creationResult->keyCharacteristics = convertKeyCharacteristics(
+        securityLevel_, request.key_description, response.unenforced, response.enforced);
+    creationResult->certificateChain = convertCertificateChain(response.certificate_chain);
+
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus
+AndroidKeyMintDevice::importWrappedKey(const vector<uint8_t>& wrappedKeyData,         //
+                                       const vector<uint8_t>& wrappingKeyBlob,        //
+                                       const vector<uint8_t>& maskingKey,             //
+                                       const vector<KeyParameter>& unwrappingParams,  //
+                                       int64_t passwordSid, int64_t biometricSid,     //
+                                       KeyCreationResult* creationResult) {
+
+    ImportWrappedKeyRequest request(impl_->message_version());
+    request.SetWrappedMaterial(wrappedKeyData.data(), wrappedKeyData.size());
+    request.SetWrappingMaterial(wrappingKeyBlob.data(), wrappingKeyBlob.size());
+    request.SetMaskingKeyMaterial(maskingKey.data(), maskingKey.size());
+    request.additional_params.Reinitialize(KmParamSet(unwrappingParams));
+    request.password_sid = static_cast<uint64_t>(passwordSid);
+    request.biometric_sid = static_cast<uint64_t>(biometricSid);
+
+    ImportWrappedKeyResponse response(impl_->message_version());
+    impl_->ImportWrappedKey(request, &response);
+
+    if (response.error != KM_ERROR_OK) {
+        return kmError2ScopedAStatus(response.error);
+    }
+
+    creationResult->keyBlob = kmBlob2vector(response.key_blob);
+    creationResult->keyCharacteristics = convertKeyCharacteristics(
+        securityLevel_, request.additional_params, response.unenforced, response.enforced);
+    creationResult->certificateChain = convertCertificateChain(response.certificate_chain);
+
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus AndroidKeyMintDevice::upgradeKey(const vector<uint8_t>& keyBlobToUpgrade,
+                                               const vector<KeyParameter>& upgradeParams,
+                                               vector<uint8_t>* keyBlob) {
+
+    UpgradeKeyRequest request(impl_->message_version());
+    request.SetKeyMaterial(keyBlobToUpgrade.data(), keyBlobToUpgrade.size());
+    request.upgrade_params.Reinitialize(KmParamSet(upgradeParams));
+
+    UpgradeKeyResponse response(impl_->message_version());
+    impl_->UpgradeKey(request, &response);
+
+    if (response.error != KM_ERROR_OK) {
+        return kmError2ScopedAStatus(response.error);
+    }
+
+    *keyBlob = kmBlob2vector(response.upgraded_key);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus AndroidKeyMintDevice::deleteKey(const vector<uint8_t>& keyBlob) {
+    DeleteKeyRequest request(impl_->message_version());
+    request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
+
+    DeleteKeyResponse response(impl_->message_version());
+    impl_->DeleteKey(request, &response);
+
+    return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus AndroidKeyMintDevice::deleteAllKeys() {
+    // There's nothing to be done to delete software key blobs.
+    DeleteAllKeysRequest request(impl_->message_version());
+    DeleteAllKeysResponse response(impl_->message_version());
+    impl_->DeleteAllKeys(request, &response);
+
+    return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus AndroidKeyMintDevice::destroyAttestationIds() {
+    return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
+}
+
+ScopedAStatus AndroidKeyMintDevice::begin(KeyPurpose purpose, const vector<uint8_t>& keyBlob,
+                                          const vector<KeyParameter>& params,
+                                          const optional<HardwareAuthToken>& authToken,
+                                          BeginResult* result) {
+
+    BeginOperationRequest request(impl_->message_version());
+    request.purpose = legacy_enum_conversion(purpose);
+    request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
+    request.additional_params.Reinitialize(KmParamSet(params));
+
+    vector<uint8_t> vector_token = authToken2AidlVec(authToken);
+    request.additional_params.push_back(
+        TAG_AUTH_TOKEN, reinterpret_cast<uint8_t*>(vector_token.data()), vector_token.size());
+
+    BeginOperationResponse response(impl_->message_version());
+    impl_->BeginOperation(request, &response);
+
+    if (response.error != KM_ERROR_OK) {
+        return kmError2ScopedAStatus(response.error);
+    }
+
+    result->params = kmParamSet2Aidl(response.output_params);
+    result->challenge = response.op_handle;
+    result->operation =
+        ndk::SharedRefBase::make<AndroidKeyMintOperation>(impl_, response.op_handle);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus AndroidKeyMintDevice::deviceLocked(
+    bool passwordOnly, const std::optional<secureclock::TimeStampToken>& timestampToken) {
+    DeviceLockedRequest request(impl_->message_version());
+    request.passwordOnly = passwordOnly;
+    if (timestampToken.has_value()) {
+        request.token.challenge = timestampToken->challenge;
+        request.token.mac = {timestampToken->mac.data(), timestampToken->mac.size()};
+        request.token.timestamp = timestampToken->timestamp.milliSeconds;
+    }
+    DeviceLockedResponse response = impl_->DeviceLocked(request);
+    return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus AndroidKeyMintDevice::earlyBootEnded() {
+    EarlyBootEndedResponse response = impl_->EarlyBootEnded();
+    return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus
+AndroidKeyMintDevice::convertStorageKeyToEphemeral(const std::vector<uint8_t>& /* storageKeyBlob */,
+                                                   std::vector<uint8_t>* /* ephemeralKeyBlob */) {
+    return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
+}
+
+ScopedAStatus AndroidKeyMintDevice::getKeyCharacteristics(
+    const std::vector<uint8_t>& keyBlob, const std::vector<uint8_t>& appId,
+    const std::vector<uint8_t>& appData, std::vector<KeyCharacteristics>* keyCharacteristics) {
+    GetKeyCharacteristicsRequest request(impl_->message_version());
+    request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
+    addClientAndAppData(appId, appData, &request.additional_params);
+
+    GetKeyCharacteristicsResponse response(impl_->message_version());
+    impl_->GetKeyCharacteristics(request, &response);
+
+    if (response.error != KM_ERROR_OK) {
+        return kmError2ScopedAStatus(response.error);
+    }
+
+    AuthorizationSet emptySet;
+    *keyCharacteristics =
+        convertKeyCharacteristics(securityLevel_, emptySet, response.unenforced, response.enforced,
+                                  /* include_keystore_enforced = */ false);
+
+    return ScopedAStatus::ok();
+}
+
+IKeyMintDevice* CreateKeyMintDevice(SecurityLevel securityLevel) {
+    return ::new AndroidKeyMintDevice(securityLevel);
+}
+
+}  // namespace aidl::android::hardware::security::keymint
diff --git a/ng/AndroidKeyMintOperation.cpp b/ng/AndroidKeyMintOperation.cpp
new file mode 100644
index 0000000..17f6b33
--- /dev/null
+++ b/ng/AndroidKeyMintOperation.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.security.keymint-impl"
+#include <log/log.h>
+
+#include "AndroidKeyMintOperation.h"
+
+#include <aidl/android/hardware/security/keymint/ErrorCode.h>
+#include <aidl/android/hardware/security/secureclock/ISecureClock.h>
+
+#include <keymaster/android_keymaster.h>
+
+#include "KeyMintUtils.h"
+
+namespace aidl::android::hardware::security::keymint {
+
+using ::keymaster::AbortOperationRequest;
+using ::keymaster::AbortOperationResponse;
+using ::keymaster::FinishOperationRequest;
+using ::keymaster::FinishOperationResponse;
+using ::keymaster::TAG_ASSOCIATED_DATA;
+using ::keymaster::UpdateOperationRequest;
+using ::keymaster::UpdateOperationResponse;
+using secureclock::TimeStampToken;
+using namespace km_utils;  // NOLINT(google-build-using-namespace)
+
+AndroidKeyMintOperation::AndroidKeyMintOperation(
+    shared_ptr<::keymaster::AndroidKeymaster> implementation, keymaster_operation_handle_t opHandle)
+    : impl_(std::move(implementation)), opHandle_(opHandle) {}
+
+AndroidKeyMintOperation::~AndroidKeyMintOperation() {
+    if (opHandle_ != 0) {
+        abort();
+    }
+}
+
+ScopedAStatus
+AndroidKeyMintOperation::updateAad(const vector<uint8_t>& input,
+                                   const optional<HardwareAuthToken>& /* authToken */,
+                                   const optional<TimeStampToken>& /* timestampToken */) {
+    UpdateOperationRequest request(impl_->message_version());
+    request.op_handle = opHandle_;
+    request.additional_params.push_back(TAG_ASSOCIATED_DATA, input.data(), input.size());
+
+    UpdateOperationResponse response(impl_->message_version());
+    impl_->UpdateOperation(request, &response);
+
+    return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus AndroidKeyMintOperation::update(const vector<uint8_t>& input,
+                                              const optional<HardwareAuthToken>& /* authToken */,
+                                              const optional<TimeStampToken>&
+                                              /* timestampToken */,
+                                              vector<uint8_t>* output) {
+    if (!output) return kmError2ScopedAStatus(KM_ERROR_OUTPUT_PARAMETER_NULL);
+
+    UpdateOperationRequest request(impl_->message_version());
+    request.op_handle = opHandle_;
+    request.input.Reinitialize(input.data(), input.size());
+
+    UpdateOperationResponse response(impl_->message_version());
+    impl_->UpdateOperation(request, &response);
+
+    if (response.error != KM_ERROR_OK) return kmError2ScopedAStatus(response.error);
+    if (response.input_consumed != request.input.buffer_size()) {
+        return kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR);
+    }
+
+    *output = kmBuffer2vector(response.output);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus
+AndroidKeyMintOperation::finish(const optional<vector<uint8_t>>& input,      //
+                                const optional<vector<uint8_t>>& signature,  //
+                                const optional<HardwareAuthToken>& /* authToken */,
+                                const optional<TimeStampToken>& /* timestampToken */,
+                                const optional<vector<uint8_t>>& /* confirmationToken */,
+                                vector<uint8_t>* output) {
+
+    if (!output) {
+        return ScopedAStatus(AStatus_fromServiceSpecificError(
+            static_cast<int32_t>(ErrorCode::OUTPUT_PARAMETER_NULL)));
+    }
+
+    FinishOperationRequest request(impl_->message_version());
+    request.op_handle = opHandle_;
+    if (input) request.input.Reinitialize(input->data(), input->size());
+    if (signature) request.signature.Reinitialize(signature->data(), signature->size());
+
+    FinishOperationResponse response(impl_->message_version());
+    impl_->FinishOperation(request, &response);
+    opHandle_ = 0;
+
+    if (response.error != KM_ERROR_OK) return kmError2ScopedAStatus(response.error);
+
+    *output = kmBuffer2vector(response.output);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus AndroidKeyMintOperation::abort() {
+    AbortOperationRequest request(impl_->message_version());
+    request.op_handle = opHandle_;
+
+    AbortOperationResponse response(impl_->message_version());
+    impl_->AbortOperation(request, &response);
+    opHandle_ = 0;
+
+    return kmError2ScopedAStatus(response.error);
+}
+
+}  // namespace aidl::android::hardware::security::keymint
diff --git a/ng/AndroidKeymaster3Device.cpp b/ng/AndroidKeymaster3Device.cpp
index da00d96..4539cc2 100644
--- a/ng/AndroidKeymaster3Device.cpp
+++ b/ng/AndroidKeymaster3Device.cpp
@@ -25,36 +25,35 @@
 
 #include <keymaster/android_keymaster.h>
 #include <keymaster/android_keymaster_messages.h>
-#include <keymaster/contexts/soft_keymaster_context.h>
-#include <keymaster/contexts/keymaster0_passthrough_context.h>
 #include <keymaster/contexts/keymaster1_passthrough_context.h>
 #include <keymaster/contexts/keymaster2_passthrough_context.h>
 #include <keymaster/contexts/pure_soft_keymaster_context.h>
+#include <keymaster/contexts/soft_keymaster_context.h>
 #include <keymaster/keymaster_configuration.h>
 #include <keymaster/keymaster_enforcement.h>
 #include <keymaster/km_openssl/soft_keymaster_enforcement.h>
 
+using ::keymaster::AbortOperationRequest;
+using ::keymaster::AbortOperationResponse;
 using ::keymaster::AddEntropyRequest;
 using ::keymaster::AddEntropyResponse;
 using ::keymaster::AttestKeyRequest;
 using ::keymaster::AttestKeyResponse;
 using ::keymaster::AuthorizationSet;
+using ::keymaster::BeginOperationRequest;
+using ::keymaster::BeginOperationResponse;
 using ::keymaster::ExportKeyRequest;
 using ::keymaster::ExportKeyResponse;
+using ::keymaster::FinishOperationRequest;
+using ::keymaster::FinishOperationResponse;
 using ::keymaster::GenerateKeyRequest;
 using ::keymaster::GenerateKeyResponse;
 using ::keymaster::GetKeyCharacteristicsRequest;
 using ::keymaster::GetKeyCharacteristicsResponse;
 using ::keymaster::ImportKeyRequest;
 using ::keymaster::ImportKeyResponse;
-using ::keymaster::BeginOperationRequest;
-using ::keymaster::BeginOperationResponse;
 using ::keymaster::UpdateOperationRequest;
 using ::keymaster::UpdateOperationResponse;
-using ::keymaster::FinishOperationRequest;
-using ::keymaster::FinishOperationResponse;
-using ::keymaster::AbortOperationRequest;
-using ::keymaster::AbortOperationResponse;
 
 namespace keymaster {
 namespace ng {
@@ -222,21 +221,23 @@
 
 AndroidKeymaster3Device::AndroidKeymaster3Device()
     : impl_(new ::keymaster::AndroidKeymaster(
-            [] () -> auto {
-                auto context = new PureSoftKeymasterContext();
-                context->SetSystemVersion(GetOsVersion(), GetOsPatchlevel());
-                return context;
-            } (), kOperationTableSize)), profile_(KeymasterHardwareProfile::SW) {}
+          []() -> auto {
+              auto context = new PureSoftKeymasterContext(KmVersion::KEYMASTER_3);
+              context->SetSystemVersion(GetOsVersion(), GetOsPatchlevel());
+              return context;
+          }(),
+          kOperationTableSize)),
+      profile_(KeymasterHardwareProfile::SW) {}
 
-
-AndroidKeymaster3Device::AndroidKeymaster3Device(KeymasterContext* context, KeymasterHardwareProfile profile)
+AndroidKeymaster3Device::AndroidKeymaster3Device(KeymasterContext* context,
+                                                 KeymasterHardwareProfile profile)
     : impl_(new ::keymaster::AndroidKeymaster(context, kOperationTableSize)), profile_(profile) {}
 
 AndroidKeymaster3Device::~AndroidKeymaster3Device() {}
 
 // Methods from ::android::hardware::keymaster::V3_0::IKeymasterDevice follow.
 Return<void> AndroidKeymaster3Device::getHardwareFeatures(getHardwareFeatures_cb _hidl_cb) {
-    switch(profile_) {
+    switch (profile_) {
     case KeymasterHardwareProfile::KM0:
         _hidl_cb(true /* is_secure */, false /* supports_ec */,
                  false /* supports_symmetric_cryptography */, false /* supports_attestation */,
@@ -264,21 +265,21 @@
 
 Return<ErrorCode> AndroidKeymaster3Device::addRngEntropy(const hidl_vec<uint8_t>& data) {
     if (data.size() == 0) return ErrorCode::OK;
-    AddEntropyRequest request;
+    AddEntropyRequest request(impl_->message_version());
     request.random_data.Reinitialize(data.data(), data.size());
 
-    AddEntropyResponse response;
+    AddEntropyResponse response(impl_->message_version());
     impl_->AddRngEntropy(request, &response);
 
     return legacy_enum_conversion(response.error);
 }
 
 Return<void> AndroidKeymaster3Device::generateKey(const hidl_vec<KeyParameter>& keyParams,
-                                              generateKey_cb _hidl_cb) {
-    GenerateKeyRequest request;
+                                                  generateKey_cb _hidl_cb) {
+    GenerateKeyRequest request(impl_->message_version());
     request.key_description.Reinitialize(KmParamSet(keyParams));
 
-    GenerateKeyResponse response;
+    GenerateKeyResponse response(impl_->message_version());
     impl_->GenerateKey(request, &response);
 
     KeyCharacteristics resultCharacteristics;
@@ -293,14 +294,14 @@
 }
 
 Return<void> AndroidKeymaster3Device::getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
-                                                        const hidl_vec<uint8_t>& clientId,
-                                                        const hidl_vec<uint8_t>& appData,
-                                                        getKeyCharacteristics_cb _hidl_cb) {
-    GetKeyCharacteristicsRequest request;
+                                                            const hidl_vec<uint8_t>& clientId,
+                                                            const hidl_vec<uint8_t>& appData,
+                                                            getKeyCharacteristics_cb _hidl_cb) {
+    GetKeyCharacteristicsRequest request(impl_->message_version());
     request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
     addClientAndAppData(clientId, appData, &request.additional_params);
 
-    GetKeyCharacteristicsResponse response;
+    GetKeyCharacteristicsResponse response(impl_->message_version());
     impl_->GetKeyCharacteristics(request, &response);
 
     KeyCharacteristics resultCharacteristics;
@@ -313,14 +314,15 @@
 }
 
 Return<void> AndroidKeymaster3Device::importKey(const hidl_vec<KeyParameter>& params,
-                                            KeyFormat keyFormat, const hidl_vec<uint8_t>& keyData,
-                                            importKey_cb _hidl_cb) {
-    ImportKeyRequest request;
+                                                KeyFormat keyFormat,
+                                                const hidl_vec<uint8_t>& keyData,
+                                                importKey_cb _hidl_cb) {
+    ImportKeyRequest request(impl_->message_version());
     request.key_description.Reinitialize(KmParamSet(params));
     request.key_format = legacy_enum_conversion(keyFormat);
-    request.SetKeyMaterial(keyData.data(), keyData.size());
+    request.key_data = KeymasterKeyBlob(keyData.data(), keyData.size());
 
-    ImportKeyResponse response;
+    ImportKeyResponse response(impl_->message_version());
     impl_->ImportKey(request, &response);
 
     KeyCharacteristics resultCharacteristics;
@@ -335,16 +337,16 @@
 }
 
 Return<void> AndroidKeymaster3Device::exportKey(KeyFormat exportFormat,
-                                            const hidl_vec<uint8_t>& keyBlob,
-                                            const hidl_vec<uint8_t>& clientId,
-                                            const hidl_vec<uint8_t>& appData,
-                                            exportKey_cb _hidl_cb) {
-    ExportKeyRequest request;
+                                                const hidl_vec<uint8_t>& keyBlob,
+                                                const hidl_vec<uint8_t>& clientId,
+                                                const hidl_vec<uint8_t>& appData,
+                                                exportKey_cb _hidl_cb) {
+    ExportKeyRequest request(impl_->message_version());
     request.key_format = legacy_enum_conversion(exportFormat);
     request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
     addClientAndAppData(clientId, appData, &request.additional_params);
 
-    ExportKeyResponse response;
+    ExportKeyResponse response(impl_->message_version());
     impl_->ExportKey(request, &response);
 
     hidl_vec<uint8_t> resultKeyBlob;
@@ -356,13 +358,13 @@
 }
 
 Return<void> AndroidKeymaster3Device::attestKey(const hidl_vec<uint8_t>& keyToAttest,
-                                            const hidl_vec<KeyParameter>& attestParams,
-                                            attestKey_cb _hidl_cb) {
-    AttestKeyRequest request;
+                                                const hidl_vec<KeyParameter>& attestParams,
+                                                attestKey_cb _hidl_cb) {
+    AttestKeyRequest request(impl_->message_version());
     request.SetKeyMaterial(keyToAttest.data(), keyToAttest.size());
     request.attest_params.Reinitialize(KmParamSet(attestParams));
 
-    AttestKeyResponse response;
+    AttestKeyResponse response(impl_->message_version());
     impl_->AttestKey(request, &response);
 
     hidl_vec<hidl_vec<uint8_t>> resultCertChain;
@@ -374,18 +376,18 @@
 }
 
 Return<void> AndroidKeymaster3Device::upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
-                                             const hidl_vec<KeyParameter>& upgradeParams,
-                                             upgradeKey_cb _hidl_cb) {
+                                                 const hidl_vec<KeyParameter>& upgradeParams,
+                                                 upgradeKey_cb _hidl_cb) {
     // There's nothing to be done to upgrade software key blobs.  Further, the software
     // implementation never returns ErrorCode::KEY_REQUIRES_UPGRADE, so this should never be called.
-    UpgradeKeyRequest request;
+    UpgradeKeyRequest request(impl_->message_version());
     request.SetKeyMaterial(keyBlobToUpgrade.data(), keyBlobToUpgrade.size());
     request.upgrade_params.Reinitialize(KmParamSet(upgradeParams));
 
-    UpgradeKeyResponse response;
+    UpgradeKeyResponse response(impl_->message_version());
     impl_->UpgradeKey(request, &response);
 
-    if (response.error == KM_ERROR_OK){
+    if (response.error == KM_ERROR_OK) {
         _hidl_cb(ErrorCode::OK, kmBlob2hidlVec(response.upgraded_key));
     } else {
         _hidl_cb(legacy_enum_conversion(response.error), hidl_vec<uint8_t>());
@@ -395,10 +397,10 @@
 
 Return<ErrorCode> AndroidKeymaster3Device::deleteKey(const hidl_vec<uint8_t>& keyBlob) {
     // There's nothing to be done to delete software key blobs.
-    DeleteKeyRequest request;
+    DeleteKeyRequest request(impl_->message_version());
     request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
 
-    DeleteKeyResponse response;
+    DeleteKeyResponse response(impl_->message_version());
     impl_->DeleteKey(request, &response);
 
     return legacy_enum_conversion(response.error);
@@ -406,8 +408,8 @@
 
 Return<ErrorCode> AndroidKeymaster3Device::deleteAllKeys() {
     // There's nothing to be done to delete software key blobs.
-    DeleteAllKeysRequest request;
-    DeleteAllKeysResponse response;
+    DeleteAllKeysRequest request(impl_->message_version());
+    DeleteAllKeysResponse response(impl_->message_version());
     impl_->DeleteAllKeys(request, &response);
 
     return legacy_enum_conversion(response.error);
@@ -418,14 +420,15 @@
 }
 
 Return<void> AndroidKeymaster3Device::begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
-                                        const hidl_vec<KeyParameter>& inParams, begin_cb _hidl_cb) {
+                                            const hidl_vec<KeyParameter>& inParams,
+                                            begin_cb _hidl_cb) {
 
-    BeginOperationRequest request;
+    BeginOperationRequest request(impl_->message_version());
     request.purpose = legacy_enum_conversion(purpose);
     request.SetKeyMaterial(key.data(), key.size());
     request.additional_params.Reinitialize(KmParamSet(inParams));
 
-    BeginOperationResponse response;
+    BeginOperationResponse response(impl_->message_version());
     impl_->BeginOperation(request, &response);
 
     hidl_vec<KeyParameter> resultParams;
@@ -438,14 +441,14 @@
 }
 
 Return<void> AndroidKeymaster3Device::update(uint64_t operationHandle,
-                                         const hidl_vec<KeyParameter>& inParams,
-                                         const hidl_vec<uint8_t>& input, update_cb _hidl_cb) {
-    UpdateOperationRequest request;
+                                             const hidl_vec<KeyParameter>& inParams,
+                                             const hidl_vec<uint8_t>& input, update_cb _hidl_cb) {
+    UpdateOperationRequest request(impl_->message_version());
     request.op_handle = operationHandle;
     request.input.Reinitialize(input.data(), input.size());
     request.additional_params.Reinitialize(KmParamSet(inParams));
 
-    UpdateOperationResponse response;
+    UpdateOperationResponse response(impl_->message_version());
     impl_->UpdateOperation(request, &response);
 
     uint32_t resultConsumed = 0;
@@ -461,16 +464,17 @@
 }
 
 Return<void> AndroidKeymaster3Device::finish(uint64_t operationHandle,
-                                         const hidl_vec<KeyParameter>& inParams,
-                                         const hidl_vec<uint8_t>& input,
-                                         const hidl_vec<uint8_t>& signature, finish_cb _hidl_cb) {
-    FinishOperationRequest request;
+                                             const hidl_vec<KeyParameter>& inParams,
+                                             const hidl_vec<uint8_t>& input,
+                                             const hidl_vec<uint8_t>& signature,
+                                             finish_cb _hidl_cb) {
+    FinishOperationRequest request(impl_->message_version());
     request.op_handle = operationHandle;
     request.input.Reinitialize(input.data(), input.size());
     request.signature.Reinitialize(signature.data(), signature.size());
     request.additional_params.Reinitialize(KmParamSet(inParams));
 
-    FinishOperationResponse response;
+    FinishOperationResponse response(impl_->message_version());
     impl_->FinishOperation(request, &response);
 
     hidl_vec<KeyParameter> resultParams;
@@ -484,10 +488,10 @@
 }
 
 Return<ErrorCode> AndroidKeymaster3Device::abort(uint64_t operationHandle) {
-    AbortOperationRequest request;
+    AbortOperationRequest request(impl_->message_version());
     request.op_handle = operationHandle;
 
-    AbortOperationResponse response;
+    AbortOperationResponse response(impl_->message_version());
     impl_->AbortOperation(request, &response);
 
     return legacy_enum_conversion(response.error);
@@ -496,22 +500,19 @@
 IKeymasterDevice* CreateKeymasterDevice() {
     return new AndroidKeymaster3Device();
 }
+
 IKeymasterDevice* CreateKeymasterDevice(keymaster2_device_t* km2_device) {
     if (ConfigureDevice(km2_device) != KM_ERROR_OK) return nullptr;
-    auto context = new Keymaster2PassthroughContext(km2_device);
+    auto context = new Keymaster2PassthroughContext(KmVersion::KEYMASTER_3, km2_device);
     context->SetSystemVersion(GetOsVersion(), GetOsPatchlevel());
     return new AndroidKeymaster3Device(context, KeymasterHardwareProfile::KM2);
 }
+
 IKeymasterDevice* CreateKeymasterDevice(keymaster1_device_t* km1_device) {
-    auto context = new Keymaster1PassthroughContext(km1_device);
+    auto context = new Keymaster1PassthroughContext(KmVersion::KEYMASTER_3, km1_device);
     context->SetSystemVersion(GetOsVersion(), GetOsPatchlevel());
     return new AndroidKeymaster3Device(context, KeymasterHardwareProfile::KM1);
 }
-IKeymasterDevice* CreateKeymasterDevice(keymaster0_device_t* km0_device) {
-    auto context = new Keymaster0PassthroughContext(km0_device);
-    context->SetSystemVersion(GetOsVersion(), GetOsPatchlevel());
-    return new AndroidKeymaster3Device(context, KeymasterHardwareProfile::KM0);
-}
 
 }  // namespace ng
 }  // namespace keymaster
diff --git a/ng/AndroidKeymaster41Device.cpp b/ng/AndroidKeymaster41Device.cpp
index 295d3f5..c360ff2 100644
--- a/ng/AndroidKeymaster41Device.cpp
+++ b/ng/AndroidKeymaster41Device.cpp
@@ -15,12 +15,50 @@
  ** limitations under the License.
  */
 
+#define LOG_TAG "android.hardware.keymaster@4.1 ref impl"
+#include <log/log.h>
+
 #include "include/AndroidKeymaster41Device.h"
 
+#include <keymaster/android_keymaster.h>
+
 namespace keymaster::V4_1 {
 
+using V4_0::ng::hidlKeyParams2Km;
+
+namespace {
+
+inline V41ErrorCode legacy_enum_conversion(const keymaster_error_t value) {
+    return static_cast<V41ErrorCode>(value);
+}
+
+}  // namespace
+
 IKeymasterDevice* CreateKeymasterDevice(SecurityLevel securityLevel) {
     return new AndroidKeymaster41Device(securityLevel);
 }
 
+Return<V41ErrorCode>
+AndroidKeymaster41Device::deviceLocked(bool passwordOnly,
+                                       const VerificationToken& verificationToken) {
+    keymaster::VerificationToken serializableToken;
+    serializableToken.challenge = verificationToken.challenge;
+    serializableToken.timestamp = verificationToken.timestamp;
+    serializableToken.parameters_verified.Reinitialize(
+        hidlKeyParams2Km(verificationToken.parametersVerified));
+    serializableToken.security_level =
+        static_cast<keymaster_security_level_t>(verificationToken.securityLevel);
+    serializableToken.mac =
+        KeymasterBlob(verificationToken.mac.data(), verificationToken.mac.size());
+    return legacy_enum_conversion(
+        impl_
+            ->DeviceLocked(DeviceLockedRequest(impl_->message_version(), passwordOnly,
+                                               std::move(serializableToken)))
+            .error);
+}
+
+Return<V41ErrorCode> AndroidKeymaster41Device::earlyBootEnded() {
+    return legacy_enum_conversion(impl_->EarlyBootEnded().error);
+}
+
 }  // namespace keymaster::V4_1
diff --git a/ng/AndroidKeymaster4Device.cpp b/ng/AndroidKeymaster4Device.cpp
index b42a19b..18d7fb4 100644
--- a/ng/AndroidKeymaster4Device.cpp
+++ b/ng/AndroidKeymaster4Device.cpp
@@ -21,6 +21,7 @@
 #include "include/AndroidKeymaster4Device.h"
 
 #include <keymasterV4_0/authorization_set.h>
+#include <keymasterV4_0/keymaster_utils.h>
 
 #include <keymaster/android_keymaster.h>
 #include <keymaster/android_keymaster_messages.h>
@@ -30,6 +31,8 @@
 #include <keymaster/keymaster_enforcement.h>
 #include <keymaster/km_openssl/soft_keymaster_enforcement.h>
 
+using android::hardware::keymaster::V4_0::support::authToken2HidlVec;
+
 namespace keymaster {
 namespace V4_0 {
 namespace ng {
@@ -72,46 +75,8 @@
 
 class KmParamSet : public keymaster_key_param_set_t {
   public:
-    explicit KmParamSet(const hidl_vec<KeyParameter>& keyParams) {
-        params = new keymaster_key_param_t[keyParams.size()];
-        length = keyParams.size();
-        for (size_t i = 0; i < keyParams.size(); ++i) {
-            auto tag = legacy_enum_conversion(keyParams[i].tag);
-            switch (typeFromTag(tag)) {
-            case KM_ENUM:
-            case KM_ENUM_REP:
-                params[i] = keymaster_param_enum(tag, keyParams[i].f.integer);
-                break;
-            case KM_UINT:
-            case KM_UINT_REP:
-                params[i] = keymaster_param_int(tag, keyParams[i].f.integer);
-                break;
-            case KM_ULONG:
-            case KM_ULONG_REP:
-                params[i] = keymaster_param_long(tag, keyParams[i].f.longInteger);
-                break;
-            case KM_DATE:
-                params[i] = keymaster_param_date(tag, keyParams[i].f.dateTime);
-                break;
-            case KM_BOOL:
-                if (keyParams[i].f.boolValue)
-                    params[i] = keymaster_param_bool(tag);
-                else
-                    params[i].tag = KM_TAG_INVALID;
-                break;
-            case KM_BIGNUM:
-            case KM_BYTES:
-                params[i] =
-                    keymaster_param_blob(tag, &keyParams[i].blob[0], keyParams[i].blob.size());
-                break;
-            case KM_INVALID:
-            default:
-                params[i].tag = KM_TAG_INVALID;
-                /* just skip */
-                break;
-            }
-        }
-    }
+    explicit KmParamSet(const hidl_vec<KeyParameter>& keyParams)
+        : keymaster_key_param_set_t(hidlKeyParams2Km(keyParams)) {}
     KmParamSet(KmParamSet&& other) : keymaster_key_param_set_t{other.params, other.length} {
         other.length = 0;
         other.params = nullptr;
@@ -141,8 +106,7 @@
 inline static hidl_vec<hidl_vec<uint8_t>>
 kmCertChain2Hidl(const keymaster_cert_chain_t& cert_chain) {
     hidl_vec<hidl_vec<uint8_t>> result;
-    if (!cert_chain.entry_count || !cert_chain.entries)
-        return result;
+    if (!cert_chain.entry_count || !cert_chain.entries) return result;
 
     result.resize(cert_chain.entry_count);
     for (size_t i = 0; i < cert_chain.entry_count; ++i) {
@@ -154,8 +118,7 @@
 
 static inline hidl_vec<KeyParameter> kmParamSet2Hidl(const keymaster_key_param_set_t& set) {
     hidl_vec<KeyParameter> result;
-    if (set.length == 0 || set.params == nullptr)
-        return result;
+    if (set.length == 0 || set.params == nullptr) return result;
 
     result.resize(set.length);
     keymaster_key_param_t* params = set.params;
@@ -209,11 +172,57 @@
 
 }  // anonymous namespace
 
-AndroidKeymaster4Device::AndroidKeymaster4Device(SecurityLevel securityLevel)
+keymaster_key_param_set_t hidlKeyParams2Km(const hidl_vec<KeyParameter>& keyParams) {
+    keymaster_key_param_set_t set;
+
+    set.params = new keymaster_key_param_t[keyParams.size()];
+    set.length = keyParams.size();
+
+    for (size_t i = 0; i < keyParams.size(); ++i) {
+        auto tag = legacy_enum_conversion(keyParams[i].tag);
+        switch (typeFromTag(tag)) {
+        case KM_ENUM:
+        case KM_ENUM_REP:
+            set.params[i] = keymaster_param_enum(tag, keyParams[i].f.integer);
+            break;
+        case KM_UINT:
+        case KM_UINT_REP:
+            set.params[i] = keymaster_param_int(tag, keyParams[i].f.integer);
+            break;
+        case KM_ULONG:
+        case KM_ULONG_REP:
+            set.params[i] = keymaster_param_long(tag, keyParams[i].f.longInteger);
+            break;
+        case KM_DATE:
+            set.params[i] = keymaster_param_date(tag, keyParams[i].f.dateTime);
+            break;
+        case KM_BOOL:
+            if (keyParams[i].f.boolValue)
+                set.params[i] = keymaster_param_bool(tag);
+            else
+                set.params[i].tag = KM_TAG_INVALID;
+            break;
+        case KM_BIGNUM:
+        case KM_BYTES:
+            set.params[i] =
+                keymaster_param_blob(tag, &keyParams[i].blob[0], keyParams[i].blob.size());
+            break;
+        case KM_INVALID:
+        default:
+            set.params[i].tag = KM_TAG_INVALID;
+            /* just skip */
+            break;
+        }
+    }
+
+    return set;
+}
+
+AndroidKeymaster4Device::AndroidKeymaster4Device(KmVersion version, SecurityLevel securityLevel)
     : impl_(new ::keymaster::AndroidKeymaster(
           [&]() -> auto {
               auto context = new PureSoftKeymasterContext(
-                  static_cast<keymaster_security_level_t>(securityLevel));
+                  version, static_cast<keymaster_security_level_t>(securityLevel));
               context->SetSystemVersion(GetOsVersion(), GetOsPatchlevel());
               return context;
           }(),
@@ -223,8 +232,7 @@
 AndroidKeymaster4Device::~AndroidKeymaster4Device() {}
 
 Return<void> AndroidKeymaster4Device::getHardwareInfo(getHardwareInfo_cb _hidl_cb) {
-    _hidl_cb(securityLevel_,
-             "SoftwareKeymasterDevice", "Google");
+    _hidl_cb(securityLevel_, "SoftwareKeymasterDevice", "Google");
     return Void();
 }
 
@@ -244,7 +252,7 @@
 Return<void> AndroidKeymaster4Device::computeSharedHmac(
     const hidl_vec<::android::hardware::keymaster::V4_0::HmacSharingParameters>& params,
     computeSharedHmac_cb _hidl_cb) {
-    ComputeSharedHmacRequest request;
+    ComputeSharedHmacRequest request(impl_->message_version());
     request.params_array.params_array = new keymaster::HmacSharingParameters[params.size()];
     request.params_array.num_params = params.size();
     for (size_t i = 0; i < params.size(); ++i) {
@@ -269,7 +277,7 @@
     const ::android::hardware::keymaster::V4_0::HardwareAuthToken& authToken,
     verifyAuthorization_cb _hidl_cb) {
 
-    VerifyAuthorizationRequest request;
+    VerifyAuthorizationRequest request(impl_->message_version());
     request.challenge = challenge;
     request.parameters_to_verify.Reinitialize(KmParamSet(parametersToVerify));
     request.auth_token.challenge = authToken.challenge;
@@ -295,12 +303,11 @@
 }
 
 Return<ErrorCode> AndroidKeymaster4Device::addRngEntropy(const hidl_vec<uint8_t>& data) {
-    if (data.size() == 0)
-        return ErrorCode::OK;
-    AddEntropyRequest request;
+    if (data.size() == 0) return ErrorCode::OK;
+    AddEntropyRequest request(impl_->message_version());
     request.random_data.Reinitialize(data.data(), data.size());
 
-    AddEntropyResponse response;
+    AddEntropyResponse response(impl_->message_version());
     impl_->AddRngEntropy(request, &response);
 
     return legacy_enum_conversion(response.error);
@@ -308,10 +315,10 @@
 
 Return<void> AndroidKeymaster4Device::generateKey(const hidl_vec<KeyParameter>& keyParams,
                                                   generateKey_cb _hidl_cb) {
-    GenerateKeyRequest request;
+    GenerateKeyRequest request(impl_->message_version());
     request.key_description.Reinitialize(KmParamSet(keyParams));
 
-    GenerateKeyResponse response;
+    GenerateKeyResponse response(impl_->message_version());
     impl_->GenerateKey(request, &response);
 
     KeyCharacteristics resultCharacteristics;
@@ -329,11 +336,11 @@
                                                             const hidl_vec<uint8_t>& clientId,
                                                             const hidl_vec<uint8_t>& appData,
                                                             getKeyCharacteristics_cb _hidl_cb) {
-    GetKeyCharacteristicsRequest request;
+    GetKeyCharacteristicsRequest request(impl_->message_version());
     request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
     addClientAndAppData(clientId, appData, &request.additional_params);
 
-    GetKeyCharacteristicsResponse response;
+    GetKeyCharacteristicsResponse response(impl_->message_version());
     impl_->GetKeyCharacteristics(request, &response);
 
     KeyCharacteristics resultCharacteristics;
@@ -349,12 +356,12 @@
                                                 KeyFormat keyFormat,
                                                 const hidl_vec<uint8_t>& keyData,
                                                 importKey_cb _hidl_cb) {
-    ImportKeyRequest request;
+    ImportKeyRequest request(impl_->message_version());
     request.key_description.Reinitialize(KmParamSet(params));
     request.key_format = legacy_enum_conversion(keyFormat);
-    request.SetKeyMaterial(keyData.data(), keyData.size());
+    request.key_data = KeymasterKeyBlob(keyData.data(), keyData.size());
 
-    ImportKeyResponse response;
+    ImportKeyResponse response(impl_->message_version());
     impl_->ImportKey(request, &response);
 
     KeyCharacteristics resultCharacteristics;
@@ -373,7 +380,7 @@
     const hidl_vec<uint8_t>& maskingKey, const hidl_vec<KeyParameter>& unwrappingParams,
     uint64_t passwordSid, uint64_t biometricSid, importWrappedKey_cb _hidl_cb) {
 
-    ImportWrappedKeyRequest request;
+    ImportWrappedKeyRequest request(impl_->message_version());
     request.SetWrappedMaterial(wrappedKeyData.data(), wrappedKeyData.size());
     request.SetWrappingMaterial(wrappingKeyBlob.data(), wrappingKeyBlob.size());
     request.SetMaskingKeyMaterial(maskingKey.data(), maskingKey.size());
@@ -381,7 +388,7 @@
     request.password_sid = passwordSid;
     request.biometric_sid = biometricSid;
 
-    ImportWrappedKeyResponse response;
+    ImportWrappedKeyResponse response(impl_->message_version());
     impl_->ImportWrappedKey(request, &response);
 
     KeyCharacteristics resultCharacteristics;
@@ -400,12 +407,12 @@
                                                 const hidl_vec<uint8_t>& clientId,
                                                 const hidl_vec<uint8_t>& appData,
                                                 exportKey_cb _hidl_cb) {
-    ExportKeyRequest request;
+    ExportKeyRequest request(impl_->message_version());
     request.key_format = legacy_enum_conversion(exportFormat);
     request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
     addClientAndAppData(clientId, appData, &request.additional_params);
 
-    ExportKeyResponse response;
+    ExportKeyResponse response(impl_->message_version());
     impl_->ExportKey(request, &response);
 
     hidl_vec<uint8_t> resultKeyBlob;
@@ -419,11 +426,11 @@
 Return<void> AndroidKeymaster4Device::attestKey(const hidl_vec<uint8_t>& keyToAttest,
                                                 const hidl_vec<KeyParameter>& attestParams,
                                                 attestKey_cb _hidl_cb) {
-    AttestKeyRequest request;
+    AttestKeyRequest request(impl_->message_version());
     request.SetKeyMaterial(keyToAttest.data(), keyToAttest.size());
     request.attest_params.Reinitialize(KmParamSet(attestParams));
 
-    AttestKeyResponse response;
+    AttestKeyResponse response(impl_->message_version());
     impl_->AttestKey(request, &response);
 
     hidl_vec<hidl_vec<uint8_t>> resultCertChain;
@@ -439,11 +446,11 @@
                                                  upgradeKey_cb _hidl_cb) {
     // There's nothing to be done to upgrade software key blobs.  Further, the software
     // implementation never returns ErrorCode::KEY_REQUIRES_UPGRADE, so this should never be called.
-    UpgradeKeyRequest request;
+    UpgradeKeyRequest request(impl_->message_version());
     request.SetKeyMaterial(keyBlobToUpgrade.data(), keyBlobToUpgrade.size());
     request.upgrade_params.Reinitialize(KmParamSet(upgradeParams));
 
-    UpgradeKeyResponse response;
+    UpgradeKeyResponse response(impl_->message_version());
     impl_->UpgradeKey(request, &response);
 
     if (response.error == KM_ERROR_OK) {
@@ -456,10 +463,10 @@
 
 Return<ErrorCode> AndroidKeymaster4Device::deleteKey(const hidl_vec<uint8_t>& keyBlob) {
     // There's nothing to be done to delete software key blobs.
-    DeleteKeyRequest request;
+    DeleteKeyRequest request(impl_->message_version());
     request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
 
-    DeleteKeyResponse response;
+    DeleteKeyResponse response(impl_->message_version());
     impl_->DeleteKey(request, &response);
 
     return legacy_enum_conversion(response.error);
@@ -467,8 +474,8 @@
 
 Return<ErrorCode> AndroidKeymaster4Device::deleteAllKeys() {
     // There's nothing to be done to delete software key blobs.
-    DeleteAllKeysRequest request;
-    DeleteAllKeysResponse response;
+    DeleteAllKeysRequest request(impl_->message_version());
+    DeleteAllKeysResponse response(impl_->message_version());
     impl_->DeleteAllKeys(request, &response);
 
     return legacy_enum_conversion(response.error);
@@ -480,21 +487,22 @@
 
 Return<void> AndroidKeymaster4Device::begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
                                             const hidl_vec<KeyParameter>& inParams,
-                                            const HardwareAuthToken& /* authToken */,
-                                            begin_cb _hidl_cb) {
+                                            const HardwareAuthToken& authToken, begin_cb _hidl_cb) {
 
-    BeginOperationRequest request;
+    BeginOperationRequest request(impl_->message_version());
     request.purpose = legacy_enum_conversion(purpose);
     request.SetKeyMaterial(key.data(), key.size());
     request.additional_params.Reinitialize(KmParamSet(inParams));
 
-    BeginOperationResponse response;
+    hidl_vec<uint8_t> hidl_vec_token = authToken2HidlVec(authToken);
+    request.additional_params.push_back(
+        TAG_AUTH_TOKEN, reinterpret_cast<uint8_t*>(hidl_vec_token.data()), hidl_vec_token.size());
+
+    BeginOperationResponse response(impl_->message_version());
     impl_->BeginOperation(request, &response);
 
     hidl_vec<KeyParameter> resultParams;
-    if (response.error == KM_ERROR_OK) {
-        resultParams = kmParamSet2Hidl(response.output_params);
-    }
+    if (response.error == KM_ERROR_OK) resultParams = kmParamSet2Hidl(response.output_params);
 
     _hidl_cb(legacy_enum_conversion(response.error), resultParams, response.op_handle);
     return Void();
@@ -503,15 +511,19 @@
 Return<void> AndroidKeymaster4Device::update(uint64_t operationHandle,
                                              const hidl_vec<KeyParameter>& inParams,
                                              const hidl_vec<uint8_t>& input,
-                                             const HardwareAuthToken& /* authToken */,
+                                             const HardwareAuthToken&  authToken ,
                                              const VerificationToken& /* verificationToken */,
                                              update_cb _hidl_cb) {
-    UpdateOperationRequest request;
+    UpdateOperationRequest request(impl_->message_version());
     request.op_handle = operationHandle;
     request.input.Reinitialize(input.data(), input.size());
     request.additional_params.Reinitialize(KmParamSet(inParams));
 
-    UpdateOperationResponse response;
+    hidl_vec<uint8_t> hidl_vec_token = authToken2HidlVec(authToken);
+    request.additional_params.push_back(
+        TAG_AUTH_TOKEN, reinterpret_cast<uint8_t*>(hidl_vec_token.data()), hidl_vec_token.size());
+
+    UpdateOperationResponse response(impl_->message_version());
     impl_->UpdateOperation(request, &response);
 
     uint32_t resultConsumed = 0;
@@ -530,16 +542,21 @@
                                              const hidl_vec<KeyParameter>& inParams,
                                              const hidl_vec<uint8_t>& input,
                                              const hidl_vec<uint8_t>& signature,
-                                             const HardwareAuthToken& /* authToken */,
+                                             const HardwareAuthToken&  authToken ,
                                              const VerificationToken& /* verificationToken */,
                                              finish_cb _hidl_cb) {
-    FinishOperationRequest request;
+    FinishOperationRequest request(impl_->message_version());
     request.op_handle = operationHandle;
     request.input.Reinitialize(input.data(), input.size());
     request.signature.Reinitialize(signature.data(), signature.size());
     request.additional_params.Reinitialize(KmParamSet(inParams));
 
-    FinishOperationResponse response;
+    hidl_vec<uint8_t> hidl_vec_token = authToken2HidlVec(authToken);
+    request.additional_params.push_back(
+        TAG_AUTH_TOKEN, reinterpret_cast<uint8_t*>(hidl_vec_token.data()), hidl_vec_token.size());
+
+
+    FinishOperationResponse response(impl_->message_version());
     impl_->FinishOperation(request, &response);
 
     hidl_vec<KeyParameter> resultParams;
@@ -553,10 +570,10 @@
 }
 
 Return<ErrorCode> AndroidKeymaster4Device::abort(uint64_t operationHandle) {
-    AbortOperationRequest request;
+    AbortOperationRequest request(impl_->message_version());
     request.op_handle = operationHandle;
 
-    AbortOperationResponse response;
+    AbortOperationResponse response(impl_->message_version());
     impl_->AbortOperation(request, &response);
 
     return legacy_enum_conversion(response.error);
diff --git a/ng/AndroidRemotelyProvisionedComponentDevice.cpp b/ng/AndroidRemotelyProvisionedComponentDevice.cpp
new file mode 100644
index 0000000..ccd13d5
--- /dev/null
+++ b/ng/AndroidRemotelyProvisionedComponentDevice.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "AndroidRemotelyProvisionedComponentDevice.h"
+
+#include <assert.h>
+#include <variant>
+
+#include <cppbor.h>
+#include <cppbor_parse.h>
+
+#include <KeyMintUtils.h>
+#include <keymaster/cppcose/cppcose.h>
+#include <keymaster/keymaster_configuration.h>
+
+#include <openssl/bn.h>
+#include <openssl/ec.h>
+#include <openssl/rand.h>
+#include <openssl/x509.h>
+
+namespace aidl::android::hardware::security::keymint {
+
+using keymaster::GenerateCsrRequest;
+using keymaster::GenerateCsrResponse;
+using keymaster::GenerateRkpKeyRequest;
+using keymaster::GenerateRkpKeyResponse;
+using keymaster::KeymasterBlob;
+using ::std::string;
+using ::std::unique_ptr;
+using ::std::vector;
+using bytevec = ::std::vector<uint8_t>;
+
+namespace {
+
+constexpr auto STATUS_FAILED = IRemotelyProvisionedComponent::STATUS_FAILED;
+
+struct AStatusDeleter {
+    void operator()(AStatus* p) { AStatus_delete(p); }
+};
+
+class Status {
+  public:
+    Status() : status_(AStatus_newOk()) {}
+    Status(int32_t errCode, const std::string& errMsg)
+        : status_(AStatus_fromServiceSpecificErrorWithMessage(errCode, errMsg.c_str())) {}
+    explicit Status(const std::string& errMsg)
+        : status_(AStatus_fromServiceSpecificErrorWithMessage(STATUS_FAILED, errMsg.c_str())) {}
+    explicit Status(AStatus* status) : status_(status ? status : AStatus_newOk()) {}
+
+    Status(Status&&) = default;
+    Status(const Status&) = delete;
+
+    operator ::ndk::ScopedAStatus() && {  // NOLINT(google-explicit-constructor)
+        return ndk::ScopedAStatus(status_.release());
+    }
+
+    bool isOk() const { return AStatus_isOk(status_.get()); }
+
+    const char* getMessage() const { return AStatus_getMessage(status_.get()); }
+
+  private:
+    std::unique_ptr<AStatus, AStatusDeleter> status_;
+};
+
+}  // namespace
+
+AndroidRemotelyProvisionedComponentDevice::AndroidRemotelyProvisionedComponentDevice(
+    const std::shared_ptr<AndroidKeyMintDevice>& keymint) {
+    impl_ = keymint->getKeymasterImpl();
+}
+
+ScopedAStatus AndroidRemotelyProvisionedComponentDevice::getHardwareInfo(RpcHardwareInfo* info) {
+    info->versionNumber = 1;
+    info->rpcAuthorName = "Google";
+    info->supportedEekCurve = RpcHardwareInfo::CURVE_25519;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus AndroidRemotelyProvisionedComponentDevice::generateEcdsaP256KeyPair(
+    bool testMode, MacedPublicKey* macedPublicKey, bytevec* privateKeyHandle) {
+    GenerateRkpKeyRequest request(impl_->message_version());
+    request.test_mode = testMode;
+    GenerateRkpKeyResponse response(impl_->message_version());
+    impl_->GenerateRkpKey(request, &response);
+    if (response.error != KM_ERROR_OK) {
+        return Status(-static_cast<int32_t>(response.error), "Failure in key generation.");
+    }
+
+    macedPublicKey->macedKey = km_utils::kmBlob2vector(response.maced_public_key);
+    *privateKeyHandle = km_utils::kmBlob2vector(response.key_blob);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus AndroidRemotelyProvisionedComponentDevice::generateCertificateRequest(
+    bool testMode, const vector<MacedPublicKey>& keysToSign, const bytevec& endpointEncCertChain,
+    const bytevec& challenge, DeviceInfo* deviceInfo, ProtectedData* protectedData,
+    bytevec* keysToSignMac) {
+    GenerateCsrRequest request(impl_->message_version());
+    request.test_mode = testMode;
+    request.num_keys = keysToSign.size();
+    request.keys_to_sign_array = new KeymasterBlob[keysToSign.size()];
+    for (size_t i = 0; i < keysToSign.size(); i++) {
+        request.SetKeyToSign(i, keysToSign[i].macedKey.data(), keysToSign[i].macedKey.size());
+    }
+    request.SetEndpointEncCertChain(endpointEncCertChain.data(), endpointEncCertChain.size());
+    request.SetChallenge(challenge.data(), challenge.size());
+    GenerateCsrResponse response(impl_->message_version());
+    impl_->GenerateCsr(request, &response);
+
+    if (response.error != KM_ERROR_OK) {
+        return Status(-static_cast<int32_t>(response.error), "Failure in CSR Generation.");
+    }
+    deviceInfo->deviceInfo = km_utils::kmBlob2vector(response.device_info_blob);
+    protectedData->protectedData = km_utils::kmBlob2vector(response.protected_data_blob);
+    *keysToSignMac = km_utils::kmBlob2vector(response.keys_to_sign_mac);
+    return ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::security::keymint
diff --git a/ng/AndroidSecureClock.cpp b/ng/AndroidSecureClock.cpp
new file mode 100644
index 0000000..4c69621
--- /dev/null
+++ b/ng/AndroidSecureClock.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.security.secureclock-impl"
+#include <log/log.h>
+
+#include "AndroidSecureClock.h"
+
+#include <aidl/android/hardware/security/keymint/ErrorCode.h>
+
+#include "KeyMintUtils.h"
+#include <keymaster/android_keymaster.h>
+#include <keymaster/keymaster_configuration.h>
+
+namespace aidl::android::hardware::security::secureclock {
+
+using keymaster::GenerateTimestampTokenRequest;
+using keymaster::GenerateTimestampTokenResponse;
+using keymint::km_utils::kmBlob2vector;
+using keymint::km_utils::kmError2ScopedAStatus;
+
+AndroidSecureClock::AndroidSecureClock(
+    const std::shared_ptr<keymint::AndroidKeyMintDevice>& keymint)
+    : impl_(keymint->getKeymasterImpl()) {}
+
+AndroidSecureClock::~AndroidSecureClock() {}
+
+ScopedAStatus AndroidSecureClock::generateTimeStamp(int64_t challenge, TimeStampToken* token) {
+    GenerateTimestampTokenRequest request(impl_->message_version());
+    request.challenge = challenge;
+    GenerateTimestampTokenResponse response(request.message_version);
+    impl_->GenerateTimestampToken(request, &response);
+    if (response.error != KM_ERROR_OK) {
+        return kmError2ScopedAStatus(response.error);
+    }
+    token->challenge = response.token.challenge;
+    token->timestamp.milliSeconds = static_cast<int64_t>(response.token.timestamp);
+    token->mac = kmBlob2vector(response.token.mac);
+    return ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::security::secureclock
diff --git a/ng/AndroidSharedSecret.cpp b/ng/AndroidSharedSecret.cpp
new file mode 100644
index 0000000..0ae3d2d
--- /dev/null
+++ b/ng/AndroidSharedSecret.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.security.sharedsecret-impl"
+#include <log/log.h>
+
+#include "AndroidSharedSecret.h"
+#include "KeyMintUtils.h"
+#include <aidl/android/hardware/security/keymint/ErrorCode.h>
+#include <keymaster/android_keymaster.h>
+
+namespace aidl::android::hardware::security::sharedsecret {
+
+using keymaster::ComputeSharedHmacRequest;
+using keymint::km_utils::kmBlob2vector;
+using keymint::km_utils::kmError2ScopedAStatus;
+
+AndroidSharedSecret::AndroidSharedSecret(
+    const std::shared_ptr<keymint::AndroidKeyMintDevice>& keymint)
+    : impl_(keymint->getKeymasterImpl()) {}
+
+AndroidSharedSecret::~AndroidSharedSecret() {}
+
+ScopedAStatus AndroidSharedSecret::getSharedSecretParameters(SharedSecretParameters* params) {
+    auto response = impl_->GetHmacSharingParameters();
+    params->seed = kmBlob2vector(response.params.seed);
+    params->nonce = {std::begin(response.params.nonce), std::end(response.params.nonce)};
+    return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus AndroidSharedSecret::computeSharedSecret(const vector<SharedSecretParameters>& params,
+                                                       vector<uint8_t>* sharingCheck) {
+    ComputeSharedHmacRequest request(impl_->message_version());
+    request.params_array.params_array = new keymaster::HmacSharingParameters[params.size()];
+    request.params_array.num_params = params.size();
+    for (size_t i = 0; i < params.size(); ++i) {
+        request.params_array.params_array[i].seed = {params[i].seed.data(), params[i].seed.size()};
+        if (sizeof(request.params_array.params_array[i].nonce) != params[i].nonce.size()) {
+            return kmError2ScopedAStatus(KM_ERROR_INVALID_ARGUMENT);
+        }
+        memcpy(request.params_array.params_array[i].nonce, params[i].nonce.data(),
+               params[i].nonce.size());
+    }
+    auto response = impl_->ComputeSharedHmac(request);
+    if (response.error == KM_ERROR_OK) *sharingCheck = kmBlob2vector(response.sharing_check);
+    return kmError2ScopedAStatus(response.error);
+}
+
+}  // namespace aidl::android::hardware::security::sharedsecret
diff --git a/ng/KeyMintAidlUtils.cpp b/ng/KeyMintAidlUtils.cpp
new file mode 100644
index 0000000..17a53a5
--- /dev/null
+++ b/ng/KeyMintAidlUtils.cpp
@@ -0,0 +1,147 @@
+/*
+ *
+ * Copyright 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "include/KeyMintAidlUtils.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace keymint {
+
+using namespace ::keymaster;
+
+vector<uint8_t> authToken2AidlVec(const HardwareAuthToken& token) {
+    static_assert(1 /* version size */ + sizeof(token.challenge) + sizeof(token.userId) +
+                          sizeof(token.authenticatorId) + sizeof(token.authenticatorType) +
+                          sizeof(token.timestamp) + 32 /* HMAC size */
+                      == sizeof(hw_auth_token_t),
+                  "HardwareAuthToken content size does not match hw_auth_token_t size");
+
+    vector<uint8_t> result;
+
+    if (token.mac.size() <= 32) return result;
+
+    result.resize(sizeof(hw_auth_token_t));
+    auto pos = result.begin();
+    *pos++ = 0;  // Version byte
+    pos = copy_bytes_to_iterator(token.challenge, pos);
+    pos = copy_bytes_to_iterator(token.userId, pos);
+    pos = copy_bytes_to_iterator(token.authenticatorId, pos);
+    pos = copy_bytes_to_iterator(token.authenticatorType, pos);
+    pos = copy_bytes_to_iterator(token.timestamp, pos);
+    pos = std::copy(token.mac.data(), token.mac.data() + token.mac.size(), pos);
+
+    return result;
+}
+
+// TODO(seleneh): This needs to be modified depends on how aidl support for union came out to
+// be.
+vector<KeyParameter> kmParamSet2Aidl(const keymaster_key_param_set_t& set) {
+    vector<KeyParameter> result;
+    if (set.length == 0 || set.params == nullptr) return result;
+
+    result.resize(set.length);
+    keymaster_key_param_t* params = set.params;
+    for (size_t i = 0; i < set.length; ++i) {
+        auto tag = params[i].tag;
+        result[i].tag = legacy_enum_conversion(tag);
+        switch (typeFromTag(tag)) {
+        case KM_ENUM:
+        case KM_ENUM_REP:
+            result[i].integer = params[i].enumerated;
+            break;
+        case KM_UINT:
+        case KM_UINT_REP:
+            result[i].integer = params[i].integer;
+            break;
+        case KM_ULONG:
+        case KM_ULONG_REP:
+            result[i].longInteger = params[i].long_integer;
+            break;
+        case KM_DATE:
+            result[i].longInteger = params[i].date_time;
+            break;
+        case KM_BOOL:
+            result[i].boolValue = params[i].boolean;
+            break;
+        case KM_BIGNUM:
+        case KM_BYTES:
+            result[i].blob.assign(params[i].blob.data,
+                                  params[i].blob.data + params[i].blob.data_length);
+            break;
+        case KM_INVALID:
+        default:
+            params[i].tag = KM_TAG_INVALID;
+            /* just skip */
+            break;
+        }
+    }
+    return result;
+}
+
+// TODO(seleneh): This needs to be modified depends on how aidl support for union came out to
+// be.
+keymaster_key_param_set_t aidlKeyParams2Km(const vector<KeyParameter>& keyParams) {
+    keymaster_key_param_set_t set;
+
+    set.params = new keymaster_key_param_t[keyParams.size()];
+    set.length = keyParams.size();
+
+    for (size_t i = 0; i < keyParams.size(); ++i) {
+        auto tag = legacy_enum_conversion(keyParams[i].tag);
+        switch (typeFromTag(tag)) {
+        case KM_ENUM:
+        case KM_ENUM_REP:
+            set.params[i] = keymaster_param_enum(tag, keyParams[i].integer);
+            break;
+        case KM_UINT:
+        case KM_UINT_REP:
+            set.params[i] = keymaster_param_int(tag, keyParams[i].integer);
+            break;
+        case KM_ULONG:
+        case KM_ULONG_REP:
+            set.params[i] = keymaster_param_long(tag, keyParams[i].longInteger);
+            break;
+        case KM_DATE:
+            set.params[i] = keymaster_param_date(tag, keyParams[i].longInteger);
+            break;
+        case KM_BOOL:
+            if (keyParams[i].boolValue)
+                set.params[i] = keymaster_param_bool(tag);
+            else
+                set.params[i].tag = KM_TAG_INVALID;
+            break;
+        case KM_BIGNUM:
+        case KM_BYTES:
+            set.params[i] =
+                keymaster_param_blob(tag, keyParams[i].blob.data(), keyParams[i].blob.size());
+            break;
+        case KM_INVALID:
+        default:
+            set.params[i].tag = KM_TAG_INVALID;
+            /* just skip */
+            break;
+        }
+    }
+
+    return set;
+}
+
+}  // namespace keymint
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/ng/KeyMintUtils.cpp b/ng/KeyMintUtils.cpp
new file mode 100644
index 0000000..45967fd
--- /dev/null
+++ b/ng/KeyMintUtils.cpp
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.security.keymint-impl"
+#include <android-base/logging.h>
+
+#include "KeyMintUtils.h"
+
+namespace aidl::android::hardware::security::keymint::km_utils {
+
+namespace {
+
+using keymaster::hton;
+
+KeyParameter kmEnumParam2Aidl(const keymaster_key_param_t& param) {
+    switch (param.tag) {
+    case KM_TAG_PURPOSE:
+        return KeyParameter{Tag::PURPOSE, KeyParameterValue::make<KeyParameterValue::keyPurpose>(
+                                              static_cast<KeyPurpose>(param.enumerated))};
+    case KM_TAG_ALGORITHM:
+        return KeyParameter{Tag::ALGORITHM, KeyParameterValue::make<KeyParameterValue::algorithm>(
+                                                static_cast<Algorithm>(param.enumerated))};
+    case KM_TAG_BLOCK_MODE:
+        return KeyParameter{Tag::BLOCK_MODE, KeyParameterValue::make<KeyParameterValue::blockMode>(
+                                                 static_cast<BlockMode>(param.enumerated))};
+    case KM_TAG_DIGEST:
+        return KeyParameter{Tag::DIGEST, KeyParameterValue::make<KeyParameterValue::digest>(
+                                             static_cast<Digest>(param.enumerated))};
+    case KM_TAG_PADDING:
+        return KeyParameter{Tag::PADDING, KeyParameterValue::make<KeyParameterValue::paddingMode>(
+                                              static_cast<PaddingMode>(param.enumerated))};
+    case KM_TAG_EC_CURVE:
+        return KeyParameter{Tag::EC_CURVE, KeyParameterValue::make<KeyParameterValue::ecCurve>(
+                                               static_cast<EcCurve>(param.enumerated))};
+    case KM_TAG_USER_AUTH_TYPE:
+        return KeyParameter{Tag::USER_AUTH_TYPE,
+                            KeyParameterValue::make<KeyParameterValue::hardwareAuthenticatorType>(
+                                static_cast<HardwareAuthenticatorType>(param.enumerated))};
+    case KM_TAG_ORIGIN:
+        return KeyParameter{Tag::ORIGIN, KeyParameterValue::make<KeyParameterValue::origin>(
+                                             static_cast<KeyOrigin>(param.enumerated))};
+    case KM_TAG_BLOB_USAGE_REQUIREMENTS:
+    case KM_TAG_KDF:
+    default:
+        return KeyParameter{Tag::INVALID, false};
+    }
+}
+
+keymaster_key_param_t kInvalidTag{.tag = KM_TAG_INVALID, .integer = 0};
+
+template <KeyParameterValue::Tag aidl_tag>
+keymaster_key_param_t aidlEnumVal2Km(keymaster_tag_t km_tag, const KeyParameterValue& value) {
+    return value.getTag() == aidl_tag
+               ? keymaster_param_enum(km_tag, static_cast<uint32_t>(value.get<aidl_tag>()))
+               : kInvalidTag;
+}
+
+keymaster_key_param_t aidlEnumParam2Km(const KeyParameter& param) {
+    auto tag = km_utils::legacy_enum_conversion(param.tag);
+    switch (tag) {
+    case KM_TAG_PURPOSE:
+        return aidlEnumVal2Km<KeyParameterValue::keyPurpose>(tag, param.value);
+    case KM_TAG_ALGORITHM:
+        return aidlEnumVal2Km<KeyParameterValue::algorithm>(tag, param.value);
+    case KM_TAG_BLOCK_MODE:
+        return aidlEnumVal2Km<KeyParameterValue::blockMode>(tag, param.value);
+    case KM_TAG_DIGEST:
+    case KM_TAG_RSA_OAEP_MGF_DIGEST:
+        return aidlEnumVal2Km<KeyParameterValue::digest>(tag, param.value);
+    case KM_TAG_PADDING:
+        return aidlEnumVal2Km<KeyParameterValue::paddingMode>(tag, param.value);
+    case KM_TAG_EC_CURVE:
+        return aidlEnumVal2Km<KeyParameterValue::ecCurve>(tag, param.value);
+    case KM_TAG_USER_AUTH_TYPE:
+        return aidlEnumVal2Km<KeyParameterValue::hardwareAuthenticatorType>(tag, param.value);
+    case KM_TAG_ORIGIN:
+        return aidlEnumVal2Km<KeyParameterValue::origin>(tag, param.value);
+    case KM_TAG_BLOB_USAGE_REQUIREMENTS:
+    case KM_TAG_KDF:
+    default:
+        CHECK(false) << "Unknown or unused enum tag: Something is broken";
+        return keymaster_param_enum(tag, false);
+    }
+}
+
+}  // namespace
+
+vector<uint8_t> authToken2AidlVec(const std::optional<HardwareAuthToken>& token) {
+    static_assert(1 /* version size */ + sizeof(token->challenge) + sizeof(token->userId) +
+                          sizeof(token->authenticatorId) + sizeof(token->authenticatorType) +
+                          sizeof(token->timestamp) + 32 /* HMAC size */
+                      == sizeof(hw_auth_token_t),
+                  "HardwareAuthToken content size does not match hw_auth_token_t size");
+
+    vector<uint8_t> result;
+
+    if (!token.has_value()) return result;
+    if (token->mac.size() < 32) return result;
+
+    result.resize(sizeof(hw_auth_token_t));
+    auto pos = result.begin();
+    *pos++ = 0;  // Version byte
+    pos = copy_bytes_to_iterator(token->challenge, pos);
+    pos = copy_bytes_to_iterator(token->userId, pos);
+    pos = copy_bytes_to_iterator(token->authenticatorId, pos);
+    pos = copy_bytes_to_iterator(hton(static_cast<uint32_t>(token->authenticatorType)), pos);
+    pos = copy_bytes_to_iterator(hton(token->timestamp.milliSeconds), pos);
+    pos = std::copy(token->mac.data(), token->mac.data() + token->mac.size(), pos);
+
+    return result;
+}
+
+KeyParameter kmParam2Aidl(const keymaster_key_param_t& param) {
+    auto tag = legacy_enum_conversion(param.tag);
+    switch (typeFromTag(param.tag)) {
+    case KM_ENUM:
+    case KM_ENUM_REP:
+        return kmEnumParam2Aidl(param);
+        break;
+
+    case KM_UINT:
+    case KM_UINT_REP:
+        return KeyParameter{tag,
+                            KeyParameterValue::make<KeyParameterValue::integer>(param.integer)};
+
+    case KM_ULONG:
+    case KM_ULONG_REP:
+        return KeyParameter{
+            tag, KeyParameterValue::make<KeyParameterValue::longInteger>(param.long_integer)};
+        break;
+
+    case KM_DATE:
+        return KeyParameter{tag,
+                            KeyParameterValue::make<KeyParameterValue::dateTime>(param.date_time)};
+        break;
+
+    case KM_BOOL:
+        return KeyParameter{tag, param.boolean};
+        break;
+
+    case KM_BIGNUM:
+    case KM_BYTES:
+        return {tag, KeyParameterValue::make<KeyParameterValue::blob>(
+                         std::vector(param.blob.data, param.blob.data + param.blob.data_length))};
+        break;
+
+    case KM_INVALID:
+    default:
+        CHECK(false) << "Unknown or unused tag type: Something is broken";
+        return KeyParameter{Tag::INVALID, false};
+        break;
+    }
+}
+
+vector<KeyParameter> kmParamSet2Aidl(const keymaster_key_param_set_t& set) {
+    vector<KeyParameter> result;
+    if (set.length == 0 || set.params == nullptr) return result;
+
+    result.reserve(set.length);
+    for (size_t i = 0; i < set.length; ++i) {
+        result.push_back(kmParam2Aidl(set.params[i]));
+    }
+    return result;
+}
+
+keymaster_key_param_set_t aidlKeyParams2Km(const vector<KeyParameter>& keyParams) {
+    keymaster_key_param_set_t set;
+
+    set.params = static_cast<keymaster_key_param_t*>(
+        malloc(keyParams.size() * sizeof(keymaster_key_param_t)));
+    set.length = keyParams.size();
+
+    for (size_t i = 0; i < keyParams.size(); ++i) {
+        const auto& param = keyParams[i];
+        auto tag = legacy_enum_conversion(param.tag);
+        switch (typeFromTag(tag)) {
+
+        case KM_ENUM:
+        case KM_ENUM_REP:
+            set.params[i] = aidlEnumParam2Km(param);
+            break;
+
+        case KM_UINT:
+        case KM_UINT_REP:
+            set.params[i] =
+                param.value.getTag() == KeyParameterValue::integer
+                    ? keymaster_param_int(tag, param.value.get<KeyParameterValue::integer>())
+                    : kInvalidTag;
+            break;
+
+        case KM_ULONG:
+        case KM_ULONG_REP:
+            set.params[i] =
+                param.value.getTag() == KeyParameterValue::longInteger
+                    ? keymaster_param_long(tag, param.value.get<KeyParameterValue::longInteger>())
+                    : kInvalidTag;
+            break;
+
+        case KM_DATE:
+            set.params[i] =
+                param.value.getTag() == KeyParameterValue::dateTime
+                    ? keymaster_param_date(tag, param.value.get<KeyParameterValue::dateTime>())
+                    : kInvalidTag;
+            break;
+
+        case KM_BOOL:
+            set.params[i] = keymaster_param_bool(tag);
+            break;
+
+        case KM_BIGNUM:
+        case KM_BYTES:
+            if (param.value.getTag() == KeyParameterValue::blob) {
+                const auto& value = param.value.get<KeyParameterValue::blob>();
+                uint8_t* copy = static_cast<uint8_t*>(malloc(value.size()));
+                std::copy(value.begin(), value.end(), copy);
+                set.params[i] = keymaster_param_blob(tag, copy, value.size());
+            } else {
+                set.params[i] = kInvalidTag;
+            }
+            break;
+
+        case KM_INVALID:
+        default:
+            CHECK(false) << "Invalid tag: Something is broken";
+            set.params[i].tag = KM_TAG_INVALID;
+            /* just skip */
+            break;
+        }
+    }
+
+    return set;
+}
+
+}  // namespace aidl::android::hardware::security::keymint::km_utils
diff --git a/ng/include/AndroidKeyMintDevice.h b/ng/include/AndroidKeyMintDevice.h
new file mode 100644
index 0000000..e4ea976
--- /dev/null
+++ b/ng/include/AndroidKeyMintDevice.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/security/keymint/BnKeyMintDevice.h>
+#include <aidl/android/hardware/security/keymint/BnKeyMintOperation.h>
+#include <aidl/android/hardware/security/keymint/HardwareAuthToken.h>
+
+namespace keymaster {
+class AndroidKeymaster;
+}
+
+namespace aidl::android::hardware::security::keymint {
+using ::ndk::ScopedAStatus;
+using std::optional;
+using std::shared_ptr;
+using std::vector;
+
+using secureclock::TimeStampToken;
+
+class AndroidKeyMintDevice : public BnKeyMintDevice {
+  public:
+    explicit AndroidKeyMintDevice(SecurityLevel securityLevel);
+    virtual ~AndroidKeyMintDevice();
+
+    ScopedAStatus getHardwareInfo(KeyMintHardwareInfo* info) override;
+
+    ScopedAStatus addRngEntropy(const vector<uint8_t>& data) override;
+
+    ScopedAStatus generateKey(const vector<KeyParameter>& keyParams,
+                              const optional<AttestationKey>& attestationKey,
+                              KeyCreationResult* creationResult) override;
+
+    ScopedAStatus importKey(const vector<KeyParameter>& keyParams, KeyFormat keyFormat,
+                            const vector<uint8_t>& keyData,
+                            const optional<AttestationKey>& attestationKey,
+                            KeyCreationResult* creationResult) override;
+
+    ScopedAStatus importWrappedKey(const vector<uint8_t>& wrappedKeyData,
+                                   const vector<uint8_t>& wrappingKeyBlob,
+                                   const vector<uint8_t>& maskingKey,
+                                   const vector<KeyParameter>& unwrappingParams,
+                                   int64_t passwordSid, int64_t biometricSid,
+                                   KeyCreationResult* creationResult) override;
+
+    ScopedAStatus upgradeKey(const vector<uint8_t>& keyBlobToUpgrade,
+                             const vector<KeyParameter>& upgradeParams,
+                             vector<uint8_t>* keyBlob) override;
+
+    ScopedAStatus deleteKey(const vector<uint8_t>& keyBlob) override;
+    ScopedAStatus deleteAllKeys() override;
+    ScopedAStatus destroyAttestationIds() override;
+
+    ScopedAStatus begin(KeyPurpose purpose, const vector<uint8_t>& keyBlob,
+                        const vector<KeyParameter>& params,
+                        const optional<HardwareAuthToken>& authToken, BeginResult* result) override;
+
+    ScopedAStatus deviceLocked(bool passwordOnly,
+                               const optional<TimeStampToken>& timestampToken) override;
+    ScopedAStatus earlyBootEnded() override;
+
+    ScopedAStatus convertStorageKeyToEphemeral(const std::vector<uint8_t>& storageKeyBlob,
+                                               std::vector<uint8_t>* ephemeralKeyBlob) override;
+
+    ScopedAStatus
+    getKeyCharacteristics(const std::vector<uint8_t>& keyBlob, const std::vector<uint8_t>& appId,
+                          const std::vector<uint8_t>& appData,
+                          std::vector<KeyCharacteristics>* keyCharacteristics) override;
+
+    shared_ptr<::keymaster::AndroidKeymaster>& getKeymasterImpl() { return impl_; }
+
+  protected:
+    std::shared_ptr<::keymaster::AndroidKeymaster> impl_;
+    SecurityLevel securityLevel_;
+};
+
+IKeyMintDevice* CreateKeyMintDevice(SecurityLevel securityLevel);
+
+}  // namespace aidl::android::hardware::security::keymint
diff --git a/ng/include/AndroidKeyMintOperation.h b/ng/include/AndroidKeyMintOperation.h
new file mode 100644
index 0000000..064d05d
--- /dev/null
+++ b/ng/include/AndroidKeyMintOperation.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/security/keymint/BnKeyMintOperation.h>
+#include <aidl/android/hardware/security/secureclock/ISecureClock.h>
+
+#include <hardware/keymaster_defs.h>
+
+namespace keymaster {
+class AndroidKeymaster;
+}
+
+namespace aidl::android::hardware::security::keymint {
+
+using ::ndk::ScopedAStatus;
+using secureclock::TimeStampToken;
+using std::optional;
+using std::shared_ptr;
+using std::string;
+using std::vector;
+
+class AndroidKeyMintOperation : public BnKeyMintOperation {
+  public:
+    explicit AndroidKeyMintOperation(const shared_ptr<::keymaster::AndroidKeymaster> implementation,
+                                     keymaster_operation_handle_t opHandle);
+    virtual ~AndroidKeyMintOperation();
+
+    ScopedAStatus updateAad(const vector<uint8_t>& input,
+                            const optional<HardwareAuthToken>& authToken,
+                            const optional<TimeStampToken>& timestampToken) override;
+
+    ScopedAStatus update(const vector<uint8_t>& input, const optional<HardwareAuthToken>& authToken,
+                         const optional<TimeStampToken>& timestampToken,
+                         vector<uint8_t>* output) override;
+
+    ScopedAStatus finish(const optional<vector<uint8_t>>& input,        //
+                         const optional<vector<uint8_t>>& signature,    //
+                         const optional<HardwareAuthToken>& authToken,  //
+                         const optional<TimeStampToken>& timestampToken,
+                         const optional<vector<uint8_t>>& confirmationToken,
+                         vector<uint8_t>* output) override;
+
+    ScopedAStatus abort() override;
+
+  protected:
+    std::shared_ptr<::keymaster::AndroidKeymaster> impl_;
+    keymaster_operation_handle_t opHandle_;
+};
+
+}  // namespace aidl::android::hardware::security::keymint
diff --git a/ng/include/AndroidKeymaster3Device.h b/ng/include/AndroidKeymaster3Device.h
index 700fd1c..17f472a 100644
--- a/ng/include/AndroidKeymaster3Device.h
+++ b/ng/include/AndroidKeymaster3Device.h
@@ -15,8 +15,7 @@
  ** limitations under the License.
  */
 
-#ifndef HIDL_android_hardware_keymaster_V3_0_AndroidKeymaster3Device_H_
-#define HIDL_android_hardware_keymaster_V3_0_AndroidKeymaster3Device_H_
+#pragma once
 
 #include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
 
@@ -33,17 +32,17 @@
 
 namespace ng {
 
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
 using ::android::hardware::keymaster::V3_0::ErrorCode;
 using ::android::hardware::keymaster::V3_0::IKeymasterDevice;
 using ::android::hardware::keymaster::V3_0::KeyCharacteristics;
 using ::android::hardware::keymaster::V3_0::KeyFormat;
 using ::android::hardware::keymaster::V3_0::KeyParameter;
 using ::android::hardware::keymaster::V3_0::KeyPurpose;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
 
 enum class KeymasterHardwareProfile : uint32_t {
     SW,
@@ -103,5 +102,3 @@
 
 }  // namespace ng
 }  // namespace keymaster
-
-#endif  // HIDL_android_hardware_keymaster_V3_0_AndroidKeymaster3Device_H_
diff --git a/ng/include/AndroidKeymaster41Device.h b/ng/include/AndroidKeymaster41Device.h
index 2b3d0db..3a4b512 100644
--- a/ng/include/AndroidKeymaster41Device.h
+++ b/ng/include/AndroidKeymaster41Device.h
@@ -21,7 +21,6 @@
 #include <android/hardware/keymaster/4.1/IKeymasterDevice.h>
 #include <android/hardware/keymaster/4.1/types.h>
 #include <hidl/Status.h>
-#include <keymasterV4_1/Operation.h>
 
 #include "AndroidKeymaster4Device.h"
 
@@ -47,16 +46,15 @@
 using ::android::hardware::keymaster::V4_0::SecurityLevel;
 using ::android::hardware::keymaster::V4_0::VerificationToken;
 using ::android::hardware::keymaster::V4_1::IKeymasterDevice;
-using ::android::hardware::keymaster::V4_1::IOperation;
 using ::android::hardware::keymaster::V4_1::Tag;
 
 using V41ErrorCode = ::android::hardware::keymaster::V4_1::ErrorCode;
 
-V41ErrorCode convert(ErrorCode error_code) {
+inline V41ErrorCode convert(ErrorCode error_code) {
     return static_cast<V41ErrorCode>(error_code);
 }
 
-ErrorCode convert(V41ErrorCode error_code) {
+inline ErrorCode convert(V41ErrorCode error_code) {
     return static_cast<ErrorCode>(error_code);
 }
 
@@ -64,29 +62,13 @@
     using super = V4_0::ng::AndroidKeymaster4Device;
 
   public:
-    explicit AndroidKeymaster41Device(SecurityLevel securityLevel) : super(securityLevel) {}
+    explicit AndroidKeymaster41Device(SecurityLevel securityLevel)
+        : super(KmVersion::KEYMASTER_4_1, securityLevel) {}
     virtual ~AndroidKeymaster41Device() {}
 
     Return<V41ErrorCode> deviceLocked(bool /* passwordOnly */,
-                                      const VerificationToken& /* verificationToken */) override {
-        // TODO(swillden): Add feature to AndroidKeymaster and call from here.
-        return convert(ErrorCode::UNIMPLEMENTED);
-    }
-    Return<V41ErrorCode> earlyBootEnded() override {
-        // TODO(swillden): Add feature to AndroidKeymaster and call from here.
-        return convert(ErrorCode::UNIMPLEMENTED);
-    }
-
-    Return<void> beginOp(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
-                         const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
-                         beginOp_cb _hidl_cb) override {
-        return super::begin(
-            purpose, key, inParams, authToken,
-            [&](auto hidl_err, auto hidl_params, auto hidl_handle) {
-                _hidl_cb(convert(hidl_err), hidl_params,
-                         new ::android::hardware::keymaster::V4_1::support::Operation(hidl_handle));
-            });
-    }
+                                      const VerificationToken& /* verificationToken */) override;
+    Return<V41ErrorCode> earlyBootEnded() override;
 
     Return<void> getHardwareInfo(super::getHardwareInfo_cb _hidl_cb) override {
         return super::getHardwareInfo(_hidl_cb);
diff --git a/ng/include/AndroidKeymaster4Device.h b/ng/include/AndroidKeymaster4Device.h
index 688d08a..54b263e 100644
--- a/ng/include/AndroidKeymaster4Device.h
+++ b/ng/include/AndroidKeymaster4Device.h
@@ -20,7 +20,9 @@
 
 #include <android/hardware/keymaster/4.0/IKeymasterDevice.h>
 
+#include <hardware/keymaster_defs.h>
 #include <hidl/Status.h>
+#include <keymaster/km_version.h>
 
 namespace keymaster {
 class AndroidKeymaster;
@@ -48,7 +50,8 @@
 
 class AndroidKeymaster4Device : public IKeymasterDevice {
   public:
-    explicit AndroidKeymaster4Device(SecurityLevel securityLevel);
+    explicit AndroidKeymaster4Device(SecurityLevel securityLevel)
+        : AndroidKeymaster4Device(KmVersion::KEYMASTER_4, securityLevel) {}
     virtual ~AndroidKeymaster4Device();
 
     Return<void> getHardwareInfo(getHardwareInfo_cb _hidl_cb) override;
@@ -98,11 +101,18 @@
                         const VerificationToken& verificationToken, finish_cb _hidl_cb) override;
     Return<ErrorCode> abort(uint64_t operationHandle) override;
 
-  private:
+  protected:
+    AndroidKeymaster4Device(::keymaster::KmVersion version, SecurityLevel securityLevel);
+
     std::unique_ptr<::keymaster::AndroidKeymaster> impl_;
     SecurityLevel securityLevel_;
 };
 
+// Convert HIDL key parametes to old keymaster param set.  Note that this does *not* copy the blobs
+// from keyParams, only pointers to them.  The keyParams instance retains ownership and must
+// continue to exist.
+keymaster_key_param_set_t hidlKeyParams2Km(const hidl_vec<KeyParameter>& keyParams);
+
 IKeymasterDevice* CreateKeymasterDevice(SecurityLevel securityLevel);
 
 }  // namespace ng
diff --git a/ng/include/AndroidRemotelyProvisionedComponentDevice.h b/ng/include/AndroidRemotelyProvisionedComponentDevice.h
new file mode 100644
index 0000000..eef81f3
--- /dev/null
+++ b/ng/include/AndroidRemotelyProvisionedComponentDevice.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <AndroidKeyMintDevice.h>
+#include <aidl/android/hardware/security/keymint/BnRemotelyProvisionedComponent.h>
+#include <aidl/android/hardware/security/keymint/RpcHardwareInfo.h>
+#include <aidl/android/hardware/security/keymint/SecurityLevel.h>
+#include <cppbor.h>
+#include <keymaster/UniquePtr.h>
+#include <keymaster/android_keymaster.h>
+
+namespace aidl::android::hardware::security::keymint {
+
+class AndroidRemotelyProvisionedComponentDevice : public BnRemotelyProvisionedComponent {
+    using ScopedAStatus = ::ndk::ScopedAStatus;
+
+  public:
+    explicit AndroidRemotelyProvisionedComponentDevice(
+        const std::shared_ptr<AndroidKeyMintDevice>& keymint);
+    virtual ~AndroidRemotelyProvisionedComponentDevice() = default;
+
+    ScopedAStatus getHardwareInfo(RpcHardwareInfo* info) override;
+
+    ScopedAStatus generateEcdsaP256KeyPair(bool testMode, MacedPublicKey* macedPublicKey,
+                                           std::vector<uint8_t>* privateKeyHandle) override;
+
+    ScopedAStatus generateCertificateRequest(bool testMode,
+                                             const std::vector<MacedPublicKey>& keysToSign,
+                                             const std::vector<uint8_t>& endpointEncCertChain,
+                                             const std::vector<uint8_t>& challenge,
+                                             DeviceInfo* deviceInfo, ProtectedData* protectedData,
+                                             std::vector<uint8_t>* keysToSignMac) override;
+
+  private:
+    std::shared_ptr<::keymaster::AndroidKeymaster> impl_;
+};
+
+}  // namespace aidl::android::hardware::security::keymint
diff --git a/ng/include/AndroidSecureClock.h b/ng/include/AndroidSecureClock.h
new file mode 100644
index 0000000..e7564ca
--- /dev/null
+++ b/ng/include/AndroidSecureClock.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "AndroidKeyMintDevice.h"
+#include <aidl/android/hardware/security/secureclock/BnSecureClock.h>
+#include <aidl/android/hardware/security/secureclock/TimeStampToken.h>
+#include <aidl/android/hardware/security/secureclock/Timestamp.h>
+
+namespace keymaster {
+class AndroidKeymaster;
+}
+
+namespace aidl::android::hardware::security::secureclock {
+using ::ndk::ScopedAStatus;
+using std::shared_ptr;
+using std::vector;
+
+class AndroidSecureClock : public BnSecureClock {
+  public:
+    explicit AndroidSecureClock(const std::shared_ptr<keymint::AndroidKeyMintDevice>& keymint);
+    virtual ~AndroidSecureClock();
+    ScopedAStatus generateTimeStamp(int64_t challenge, TimeStampToken* token) override;
+
+  private:
+    shared_ptr<::keymaster::AndroidKeymaster>& impl_;
+};
+}  // namespace aidl::android::hardware::security::secureclock
diff --git a/ng/include/AndroidSharedSecret.h b/ng/include/AndroidSharedSecret.h
new file mode 100644
index 0000000..503fd0a
--- /dev/null
+++ b/ng/include/AndroidSharedSecret.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "AndroidKeyMintDevice.h"
+#include <aidl/android/hardware/security/sharedsecret/BnSharedSecret.h>
+#include <aidl/android/hardware/security/sharedsecret/SharedSecretParameters.h>
+
+namespace keymaster {
+class AndroidKeymaster;
+}
+namespace aidl::android::hardware::security::sharedsecret {
+using ::ndk::ScopedAStatus;
+using std::shared_ptr;
+using std::vector;
+
+class AndroidSharedSecret : public BnSharedSecret {
+  public:
+    explicit AndroidSharedSecret(const std::shared_ptr<keymint::AndroidKeyMintDevice>& keymint);
+    virtual ~AndroidSharedSecret();
+    ScopedAStatus getSharedSecretParameters(SharedSecretParameters* params) override;
+    ScopedAStatus computeSharedSecret(const vector<SharedSecretParameters>& params,
+                                      vector<uint8_t>* sharingCheck) override;
+
+  private:
+    shared_ptr<::keymaster::AndroidKeymaster>& impl_;
+};
+}  // namespace aidl::android::hardware::security::sharedsecret
diff --git a/ng/include/KeyMintUtils.h b/ng/include/KeyMintUtils.h
new file mode 100644
index 0000000..6e232e1
--- /dev/null
+++ b/ng/include/KeyMintUtils.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/security/keymint/Certificate.h>
+#include <aidl/android/hardware/security/keymint/HardwareAuthToken.h>
+#include <aidl/android/hardware/security/keymint/HardwareAuthenticatorType.h>
+#include <aidl/android/hardware/security/keymint/KeyFormat.h>
+#include <aidl/android/hardware/security/keymint/KeyParameter.h>
+#include <aidl/android/hardware/security/keymint/KeyPurpose.h>
+#include <aidl/android/hardware/security/keymint/SecurityLevel.h>
+#include <aidl/android/hardware/security/keymint/Tag.h>
+
+#include <keymaster/keymaster_enforcement.h>
+
+namespace aidl::android::hardware::security::keymint::km_utils {
+
+using ::ndk::ScopedAStatus;
+using std::vector;
+
+inline keymaster_tag_t legacy_enum_conversion(const Tag value) {
+    return static_cast<keymaster_tag_t>(value);
+}
+
+inline Tag legacy_enum_conversion(const keymaster_tag_t value) {
+    return static_cast<Tag>(value);
+}
+
+inline keymaster_purpose_t legacy_enum_conversion(const KeyPurpose value) {
+    return static_cast<keymaster_purpose_t>(value);
+}
+
+inline keymaster_key_format_t legacy_enum_conversion(const KeyFormat value) {
+    return static_cast<keymaster_key_format_t>(value);
+}
+
+inline SecurityLevel legacy_enum_conversion(const keymaster_security_level_t value) {
+    return static_cast<SecurityLevel>(value);
+}
+
+inline hw_authenticator_type_t legacy_enum_conversion(const HardwareAuthenticatorType value) {
+    return static_cast<hw_authenticator_type_t>(value);
+}
+
+inline ScopedAStatus kmError2ScopedAStatus(const keymaster_error_t value) {
+    return (value == KM_ERROR_OK
+                ? ScopedAStatus::ok()
+                : ScopedAStatus(AStatus_fromServiceSpecificError(static_cast<int32_t>(value))));
+}
+
+inline keymaster_tag_type_t typeFromTag(const keymaster_tag_t tag) {
+    return keymaster_tag_get_type(tag);
+}
+
+KeyParameter kmParam2Aidl(const keymaster_key_param_t& param);
+vector<KeyParameter> kmParamSet2Aidl(const keymaster_key_param_set_t& set);
+keymaster_key_param_set_t aidlKeyParams2Km(const vector<KeyParameter>& keyParams);
+
+class KmParamSet : public keymaster_key_param_set_t {
+  public:
+    explicit KmParamSet(const vector<KeyParameter>& keyParams)
+        : keymaster_key_param_set_t(aidlKeyParams2Km(keyParams)) {}
+
+    KmParamSet(KmParamSet&& other) : keymaster_key_param_set_t{other.params, other.length} {
+        other.length = 0;
+        other.params = nullptr;
+    }
+
+    KmParamSet(const KmParamSet&) = delete;
+    ~KmParamSet() { keymaster_free_param_set(this); }
+};
+
+inline vector<uint8_t> kmBlob2vector(const keymaster_key_blob_t& blob) {
+    vector<uint8_t> result(blob.key_material, blob.key_material + blob.key_material_size);
+    return result;
+}
+
+inline vector<uint8_t> kmBlob2vector(const keymaster_blob_t& blob) {
+    vector<uint8_t> result(blob.data, blob.data + blob.data_length);
+    return result;
+}
+
+inline vector<uint8_t> kmBuffer2vector(const ::keymaster::Buffer& buf) {
+    vector<uint8_t> result(buf.peek_read(), buf.peek_read() + buf.available_read());
+    return result;
+}
+
+inline vector<Certificate> kmCertChain2Aidl(const keymaster_cert_chain_t& cert_chain) {
+    vector<Certificate> result;
+    if (!cert_chain.entry_count || !cert_chain.entries) return result;
+
+    result.resize(cert_chain.entry_count);
+    for (size_t i = 0; i < cert_chain.entry_count; ++i) {
+        result[i].encodedCertificate = kmBlob2vector(cert_chain.entries[i]);
+    }
+
+    return result;
+}
+
+template <typename T, typename OutIter>
+inline OutIter copy_bytes_to_iterator(const T& value, OutIter dest) {
+    const uint8_t* value_ptr = reinterpret_cast<const uint8_t*>(&value);
+    return std::copy(value_ptr, value_ptr + sizeof(value), dest);
+}
+
+vector<uint8_t> authToken2AidlVec(const std::optional<HardwareAuthToken>& token);
+
+inline void addClientAndAppData(const vector<uint8_t>& clientId, const vector<uint8_t>& appData,
+                                ::keymaster::AuthorizationSet* params) {
+    params->Clear();
+    if (clientId.size()) {
+        params->push_back(::keymaster::TAG_APPLICATION_ID, clientId.data(), clientId.size());
+    }
+    if (appData.size()) {
+        params->push_back(::keymaster::TAG_APPLICATION_DATA, appData.data(), appData.size());
+    }
+}
+
+}  // namespace aidl::android::hardware::security::keymint::km_utils
diff --git a/ng/include/authorization_set.h b/ng/include/authorization_set.h
index 5367696..895f6cc 100644
--- a/ng/include/authorization_set.h
+++ b/ng/include/authorization_set.h
@@ -14,14 +14,12 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_SECURITY_KEYSTORE_AUTHORIZATION_SET_H_
-#define SYSTEM_SECURITY_KEYSTORE_AUTHORIZATION_SET_H_
+#pragma once
 
 #include "keymaster_tags.h"
 #include <vector>
 
-namespace keymaster {
-namespace ng {
+namespace keymaster::ng {
 
 class AuthorizationSetBuilder;
 
@@ -35,7 +33,7 @@
     /**
      * Construct an empty, dynamically-allocated, growable AuthorizationSet.
      */
-    AuthorizationSet() {};
+    AuthorizationSet(){};
 
     // Copy constructor.
     AuthorizationSet(const AuthorizationSet& other) : data_(other.data_) {}
@@ -48,6 +46,7 @@
 
     // Copy assignment.
     AuthorizationSet& operator=(const AuthorizationSet& other) {
+        if (this == &other) return *this;
         data_ = other.data_;
         return *this;
     }
@@ -153,13 +152,11 @@
     /**
      * Returns true if the set contains at least one instance of \p tag
      */
-    bool Contains(Tag tag) const {
-        return find(tag) != -1;
-    }
+    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_) {
+        for (const auto& param : data_) {
             auto entry = authorizationValue(ttag, param);
             if (entry.isOk() && entry.value() == value) return true;
         }
@@ -177,25 +174,19 @@
         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 KeyParameter& param) { data_.push_back(param); }
+    void push_back(KeyParameter&& param) { data_.push_back(std::move(param)); }
 
     /**
      * 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) {
+    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) {
+    template <typename Iterator> void append(Iterator begin, Iterator end) {
         while (begin != end) {
             push_back(*begin);
             ++begin;
@@ -217,7 +208,7 @@
     std::vector<KeyParameter> data_;
 };
 
-class AuthorizationSetBuilder: public AuthorizationSet {
+class AuthorizationSetBuilder : public AuthorizationSet {
   public:
     template <typename TagType, typename... ValueType>
     AuthorizationSetBuilder& Authorization(TagType ttag, ValueType&&... value) {
@@ -255,9 +246,7 @@
     AuthorizationSetBuilder& NoDigestOrPadding();
     AuthorizationSetBuilder& EcbMode();
 
-    AuthorizationSetBuilder& Digest(Digest digest) {
-        return Authorization(TAG_DIGEST, digest);
-    }
+    AuthorizationSetBuilder& Digest(Digest digest) { return Authorization(TAG_DIGEST, digest); }
 
     AuthorizationSetBuilder& Padding(PaddingMode padding) {
         return Authorization(TAG_PADDING, padding);
@@ -330,7 +319,4 @@
     return Authorization(TAG_BLOCK_MODE, BlockMode::ECB);
 }
 
-}  // namespace ng
-}  // namespace keymaster
-
-#endif  // SYSTEM_SECURITY_KEYSTORE_AUTHORIZATION_SET_H_
+}  // namespace keymaster::ng
diff --git a/ng/include/keymaster_tags.h b/ng/include/keymaster_tags.h
index be6c11c..57e7cc1 100644
--- a/ng/include/keymaster_tags.h
+++ b/ng/include/keymaster_tags.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_SECURITY_KEYSTORE_KEYMASTER_TAGS_H_
-#define SYSTEM_SECURITY_KEYSTORE_KEYMASTER_TAGS_H_
+#pragma once
 
 /**
  * This header contains various definitions that make working with keymaster tags safer and easier.
@@ -63,16 +62,15 @@
 #include <hardware/hw_auth_token.h>
 #include <type_traits>
 
-namespace keymaster {
-namespace ng {
+namespace keymaster::ng {
 
 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::ErrorCode;
-using ::android::hardware::keymaster::V3_0::HardwareAuthToken;
 using ::android::hardware::keymaster::V3_0::HardwareAuthenticatorType;
+using ::android::hardware::keymaster::V3_0::HardwareAuthToken;
 using ::android::hardware::keymaster::V3_0::IKeymasterDevice;
 using ::android::hardware::keymaster::V3_0::KeyBlobUsageRequirements;
 using ::android::hardware::keymaster::V3_0::KeyCharacteristics;
@@ -314,7 +312,7 @@
 
     bool isOk() const { return !null_; }
 
-    const ValueT& value() const & { return value_; }
+    const ValueT& value() const& { return value_; }
     ValueT& value() & { return value_; }
     ValueT&& value() && { return std::move(value_); }
 
@@ -350,7 +348,4 @@
     return accessTagValue(ttag, param);
 }
 
-}  // namespace ng
-}  // namespace keymaster
-
-#endif  // SYSTEM_SECURITY_KEYSTORE_KEYMASTER_TAGS_H_
+}  // namespace keymaster::ng
diff --git a/ng/include/keystore_hidl_support.h b/ng/include/keystore_hidl_support.h
index cfb3c2d..b7d7221 100644
--- a/ng/include/keystore_hidl_support.h
+++ b/ng/include/keystore_hidl_support.h
@@ -15,20 +15,18 @@
  ** limitations under the License.
  */
 
-#ifndef KEYSTORE_KEYSTORE_HIDL_SUPPORT_H_
-#define KEYSTORE_KEYSTORE_HIDL_SUPPORT_H_
+#pragma once
 
+#include "keymaster_tags.h"
 #include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
 #include <hidl/Status.h>
-#include "keymaster_tags.h"
 #include <ostream>
 #include <sstream>
 #include <string>
 
 #include <android-base/logging.h>
 
-namespace keymaster {
-namespace ng {
+namespace keymaster::ng {
 
 inline static std::ostream& formatArgs(std::ostream& out) {
     return out;
@@ -50,7 +48,7 @@
 inline static ErrorCode ksHandleHidlError(const Return<ErrorCode>& error, Msgs&&... msgs) {
     if (!error.isOk()) {
         LOG(ERROR) << "HIDL call failed with " << error.description() << " @ "
-              << argsToString(msgs...);
+                   << argsToString(msgs...);
         return ErrorCode::UNKNOWN_ERROR;
     }
     return ErrorCode(error);
@@ -59,7 +57,7 @@
 inline static ErrorCode ksHandleHidlError(const Return<void>& error, Msgs&&... msgs) {
     if (!error.isOk()) {
         LOG(ERROR) << "HIDL call failed with " << error.description() << " @ "
-              << argsToString(msgs...);
+                   << argsToString(msgs...);
         return ErrorCode::UNKNOWN_ERROR;
     }
     return ErrorCode::OK;
@@ -128,7 +126,4 @@
     return std::string(reinterpret_cast<const std::string::value_type*>(&value[0]), value.size());
 }
 
-}
-}  // namespace keystore
-
-#endif  // KEYSTORE_KEYSTORE_HIDL_SUPPORT_H_
+}  // namespace keymaster::ng
diff --git a/rsa_privkey_pk8.der b/rsa_privkey_pk8.der
deleted file mode 100644
index 0336f80..0000000
--- a/rsa_privkey_pk8.der
+++ /dev/null
Binary files differ
diff --git a/tests/Android.bp b/tests/Android.bp
new file mode 100644
index 0000000..3ee650e
--- /dev/null
+++ b/tests/Android.bp
@@ -0,0 +1,62 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "system_keymaster_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["system_keymaster_license"],
+}
+
+shared_test_libs = [
+    "libbase",
+    "libcppbor_external",
+    "libcrypto",
+    "libcutils",
+    "libhidlbase",
+    "libkeymaster_messages",
+    "libkeymaster_portable",
+    "liblog",
+    "libsoft_attestation_cert",
+    "libutils",
+]
+
+static_test_libs = [
+    "libsoftkeymasterdevice",
+    "libcppcose_rkp",
+]
+
+test_cflags = [
+    "-DKEYMASTER_NAME_TAGS",
+    "-Wall",
+    "-Werror",
+    "-Wextra",
+    "-Wunused-variable",
+]
+
+cc_test {
+    name: "keymaster_tests",
+    cflags: test_cflags,
+    srcs: [
+        "gtest_main.cpp",
+        "keymaster_configuration_test.cpp",
+        "hmac_test.cpp",
+        "android_keymaster_test_utils.cpp",
+        "ckdf_test.cpp",
+        "hkdf_test.cpp",
+        "kdf_test.cpp",
+        "kdf1_test.cpp",
+        "kdf2_test.cpp",
+        "ecies_kem_test.cpp",
+        "nist_curve_key_exchange_test.cpp",
+        "authorization_set_test.cpp",
+        "key_blob_test.cpp",
+        "android_keymaster_messages_test.cpp",
+        "android_keymaster_test.cpp",
+        "keymaster_enforcement_test.cpp",
+        "attestation_record_test.cpp",
+        "wrapped_key_test.cpp",
+    ],
+    shared_libs: shared_test_libs,
+    static_libs: static_test_libs,
+    test_suites: ["general-tests"],
+}
diff --git a/tests/TEST_MAPPING b/tests/TEST_MAPPING
new file mode 100644
index 0000000..5ec0f38
--- /dev/null
+++ b/tests/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+      {
+        "name": "keymaster_tests"
+      }
+  ]
+}
diff --git a/tests/android_keymaster_messages_test.cpp b/tests/android_keymaster_messages_test.cpp
index 7dcffbe..7b523a8 100644
--- a/tests/android_keymaster_messages_test.cpp
+++ b/tests/android_keymaster_messages_test.cpp
@@ -34,8 +34,7 @@
 Message* round_trip(int32_t ver, const Message& message, size_t expected_size) {
     size_t size = message.SerializedSize();
     EXPECT_EQ(expected_size, size);
-    if (size == 0)
-        return nullptr;
+    if (size == 0) return nullptr;
 
     UniquePtr<uint8_t[]> buf(new uint8_t[size]);
     EXPECT_EQ(buf.get() + size, message.Serialize(buf.get(), buf.get() + size));
@@ -47,72 +46,21 @@
     return deserialized;
 }
 
-struct EmptyKeymasterResponse : public KeymasterResponse {
-    explicit EmptyKeymasterResponse(int32_t ver) : KeymasterResponse(ver) {}
-    size_t NonErrorSerializedSize() const { return 1; }
-    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* /* end */) const {
-        *buf++ = 0;
-        return buf;
-    }
-    bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
-        if (*buf_ptr >= end)
-            return false;
-        EXPECT_EQ(0, **buf_ptr);
-        (*buf_ptr)++;
-        return true;
-    }
-};
-
 TEST(RoundTrip, EmptyKeymasterResponse) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         EmptyKeymasterResponse msg(ver);
         msg.error = KM_ERROR_OK;
 
-        UniquePtr<EmptyKeymasterResponse> deserialized(round_trip(ver, msg, 5));
-    }
-}
-
-TEST(RoundTrip, EmptyKeymasterResponseError) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
-        EmptyKeymasterResponse msg(ver);
-        msg.error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
         UniquePtr<EmptyKeymasterResponse> deserialized(round_trip(ver, msg, 4));
     }
 }
 
-TEST(RoundTrip, SupportedByAlgorithmRequest) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
-        SupportedByAlgorithmRequest req(ver);
-        req.algorithm = KM_ALGORITHM_EC;
+TEST(RoundTrip, EmptyKeymasterResponseError) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
+        EmptyKeymasterResponse msg(ver);
+        msg.error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
-        UniquePtr<SupportedByAlgorithmRequest> deserialized(round_trip(ver, req, 4));
-        EXPECT_EQ(KM_ALGORITHM_EC, deserialized->algorithm);
-    }
-}
-
-TEST(RoundTrip, SupportedByAlgorithmAndPurposeRequest) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
-        SupportedByAlgorithmAndPurposeRequest req(ver);
-        req.algorithm = KM_ALGORITHM_EC;
-        req.purpose = KM_PURPOSE_DECRYPT;
-
-        UniquePtr<SupportedByAlgorithmAndPurposeRequest> deserialized(round_trip(ver, req, 8));
-        EXPECT_EQ(KM_ALGORITHM_EC, deserialized->algorithm);
-        EXPECT_EQ(KM_PURPOSE_DECRYPT, deserialized->purpose);
-    }
-}
-
-TEST(RoundTrip, SupportedResponse) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
-        SupportedResponse<keymaster_digest_t> rsp(ver);
-        keymaster_digest_t digests[] = {KM_DIGEST_NONE, KM_DIGEST_MD5, KM_DIGEST_SHA1};
-        rsp.error = KM_ERROR_OK;
-        rsp.SetResults(digests);
-
-        UniquePtr<SupportedResponse<keymaster_digest_t>> deserialized(round_trip(ver, rsp, 20));
-        EXPECT_EQ(array_length(digests), deserialized->results_length);
-        EXPECT_EQ(0, memcmp(deserialized->results, digests, array_size(digests)));
+        UniquePtr<EmptyKeymasterResponse> deserialized(round_trip(ver, msg, 4));
     }
 }
 
@@ -128,31 +76,72 @@
 uint8_t TEST_DATA[] = "a key blob";
 
 TEST(RoundTrip, GenerateKeyRequest) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         GenerateKeyRequest req(ver);
         req.key_description.Reinitialize(params, array_length(params));
-        UniquePtr<GenerateKeyRequest> deserialized(round_trip(ver, req, 78));
+        req.attestation_signing_key_blob =
+            KeymasterKeyBlob(reinterpret_cast<const uint8_t*>("foo"), 3);
+        req.attest_key_params.Reinitialize(params, array_length(params));
+        req.issuer_subject = KeymasterBlob(reinterpret_cast<const uint8_t*>("bar"), 3);
+
+        UniquePtr<GenerateKeyRequest> deserialized(round_trip(ver, req, ver < 4 ? 78 : 170));
         EXPECT_EQ(deserialized->key_description, req.key_description);
+        if (ver < 4) {
+            EXPECT_EQ(0U, deserialized->attestation_signing_key_blob.key_material_size);
+        } else {
+            EXPECT_EQ(3U, deserialized->attestation_signing_key_blob.key_material_size);
+            EXPECT_EQ(0, memcmp(req.attestation_signing_key_blob.key_material,
+                                deserialized->attestation_signing_key_blob.key_material,
+                                deserialized->attestation_signing_key_blob.key_material_size));
+            EXPECT_EQ(deserialized->attest_key_params, req.attest_key_params);
+            EXPECT_EQ(0, memcmp(req.issuer_subject.data, deserialized->issuer_subject.data,
+                                deserialized->issuer_subject.data_length));
+        }
     }
 }
 
 TEST(RoundTrip, GenerateKeyResponse) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         GenerateKeyResponse rsp(ver);
         rsp.error = KM_ERROR_OK;
         rsp.key_blob.key_material = dup_array(TEST_DATA);
         rsp.key_blob.key_material_size = array_length(TEST_DATA);
         rsp.enforced.Reinitialize(params, array_length(params));
 
-        UniquePtr<GenerateKeyResponse> deserialized(round_trip(ver, rsp, 109));
+        rsp.certificate_chain = CertificateChain(3);
+        rsp.certificate_chain.entries[0] = {dup_buffer("foo", 3), 3};
+        rsp.certificate_chain.entries[1] = {dup_buffer("bar", 3), 3};
+        rsp.certificate_chain.entries[2] = {dup_buffer("baz", 3), 3};
+
+        UniquePtr<GenerateKeyResponse> deserialized;
+        if (ver < 4) {
+            deserialized.reset(round_trip(ver, rsp, 109));
+        } else {
+            deserialized.reset(round_trip(ver, rsp, 134));
+        }
+
         EXPECT_EQ(KM_ERROR_OK, deserialized->error);
         EXPECT_EQ(deserialized->enforced, rsp.enforced);
         EXPECT_EQ(deserialized->unenforced, rsp.unenforced);
+
+        keymaster_cert_chain_t* chain = &deserialized->certificate_chain;
+        if (ver < 4) {
+            EXPECT_EQ(nullptr, chain->entries);
+        } else {
+            EXPECT_NE(nullptr, chain->entries);
+            EXPECT_EQ(3U, chain->entry_count);
+            EXPECT_EQ(3U, chain->entries[0].data_length);
+            EXPECT_EQ(0, memcmp("foo", chain->entries[0].data, 3));
+            EXPECT_EQ(3U, chain->entries[1].data_length);
+            EXPECT_EQ(0, memcmp("bar", chain->entries[1].data, 3));
+            EXPECT_EQ(3U, chain->entries[2].data_length);
+            EXPECT_EQ(0, memcmp("baz", chain->entries[2].data, 3));
+        }
     }
 }
 
 TEST(RoundTrip, GenerateKeyResponseTestError) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         GenerateKeyResponse rsp(ver);
         rsp.error = KM_ERROR_UNSUPPORTED_ALGORITHM;
         rsp.key_blob.key_material = dup_array(TEST_DATA);
@@ -167,8 +156,101 @@
     }
 }
 
+TEST(RoundTrip, GenerateRkpKeyRequest) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
+        GenerateRkpKeyRequest req(ver);
+        req.test_mode = true;
+
+        UniquePtr<GenerateRkpKeyRequest> deserialized(round_trip(ver, req, 1));
+        EXPECT_EQ(deserialized->test_mode, req.test_mode);
+    }
+}
+
+TEST(RoundTrip, GenerateRkpKeyResponse) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
+        GenerateRkpKeyResponse rsp(ver);
+        rsp.error = KM_ERROR_OK;
+        rsp.key_blob.key_material = dup_array(TEST_DATA);
+        rsp.key_blob.key_material_size = array_length(TEST_DATA);
+        rsp.maced_public_key.data = dup_array(TEST_DATA);
+        rsp.maced_public_key.data_length = array_length(TEST_DATA);
+
+        UniquePtr<GenerateRkpKeyResponse> deserialized;
+        deserialized.reset(round_trip(ver, rsp, 34));
+
+        EXPECT_EQ(KM_ERROR_OK, deserialized->error);
+        EXPECT_EQ(deserialized->key_blob.key_material_size, rsp.key_blob.key_material_size);
+        EXPECT_EQ(0, std::memcmp(deserialized->key_blob.key_material, rsp.key_blob.key_material,
+                                 deserialized->key_blob.key_material_size));
+        EXPECT_EQ(deserialized->maced_public_key.data_length, rsp.maced_public_key.data_length);
+        EXPECT_EQ(0, std::memcmp(deserialized->maced_public_key.data, rsp.maced_public_key.data,
+                                 deserialized->maced_public_key.data_length));
+    }
+}
+
+TEST(RoundTrip, GenerateCsrRequest) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
+        GenerateCsrRequest req(ver);
+        req.test_mode = true;
+        req.num_keys = 2;
+        req.keys_to_sign_array = new KeymasterBlob[req.num_keys];
+        for (size_t i = 0; i < req.num_keys; i++) {
+            req.SetKeyToSign(i, dup_array(TEST_DATA), array_length(TEST_DATA));
+        }
+        req.SetEndpointEncCertChain(dup_array(TEST_DATA), array_length(TEST_DATA));
+        req.SetChallenge(dup_array(TEST_DATA), array_length(TEST_DATA));
+        UniquePtr<GenerateCsrRequest> deserialized(round_trip(ver, req, 65));
+        EXPECT_EQ(deserialized->test_mode, req.test_mode);
+        EXPECT_EQ(deserialized->num_keys, req.num_keys);
+        for (int i = 0; i < (int)req.num_keys; i++) {
+            EXPECT_EQ(deserialized->keys_to_sign_array[i].data_length,
+                      req.keys_to_sign_array[i].data_length);
+            EXPECT_EQ(0, std::memcmp(deserialized->keys_to_sign_array[i].data,
+                                     req.keys_to_sign_array[i].data,
+                                     req.keys_to_sign_array[i].data_length));
+        }
+        EXPECT_EQ(deserialized->endpoint_enc_cert_chain.data_length,
+                  req.endpoint_enc_cert_chain.data_length);
+        EXPECT_EQ(0, std::memcmp(deserialized->endpoint_enc_cert_chain.data,
+                                 req.endpoint_enc_cert_chain.data,
+                                 req.endpoint_enc_cert_chain.data_length));
+        EXPECT_EQ(deserialized->challenge.data_length, req.challenge.data_length);
+        EXPECT_EQ(0, std::memcmp(deserialized->challenge.data, req.challenge.data,
+                                 req.challenge.data_length));
+    }
+}
+
+TEST(RoundTrip, GenerateCsrResponse) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
+        GenerateCsrResponse rsp(ver);
+        rsp.error = KM_ERROR_OK;
+        rsp.keys_to_sign_mac.data = dup_array(TEST_DATA);
+        rsp.keys_to_sign_mac.data_length = array_length(TEST_DATA);
+        rsp.device_info_blob.data = dup_array(TEST_DATA);
+        rsp.device_info_blob.data_length = array_length(TEST_DATA);
+        rsp.protected_data_blob.data = dup_array(TEST_DATA);
+        rsp.protected_data_blob.data_length = array_length(TEST_DATA);
+
+        UniquePtr<GenerateCsrResponse> deserialized;
+        deserialized.reset(round_trip(ver, rsp, 49));
+
+        EXPECT_EQ(KM_ERROR_OK, deserialized->error);
+        EXPECT_EQ(deserialized->keys_to_sign_mac.data_length, rsp.keys_to_sign_mac.data_length);
+        EXPECT_EQ(0, std::memcmp(deserialized->keys_to_sign_mac.data, rsp.keys_to_sign_mac.data,
+                                 deserialized->keys_to_sign_mac.data_length));
+        EXPECT_EQ(deserialized->device_info_blob.data_length, rsp.device_info_blob.data_length);
+        EXPECT_EQ(0, std::memcmp(deserialized->device_info_blob.data, rsp.device_info_blob.data,
+                                 deserialized->device_info_blob.data_length));
+        EXPECT_EQ(deserialized->protected_data_blob.data_length,
+                  rsp.protected_data_blob.data_length);
+        EXPECT_EQ(0,
+                  std::memcmp(deserialized->protected_data_blob.data, rsp.protected_data_blob.data,
+                              deserialized->protected_data_blob.data_length));
+    }
+}
+
 TEST(RoundTrip, GetKeyCharacteristicsRequest) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         GetKeyCharacteristicsRequest req(ver);
         req.additional_params.Reinitialize(params, array_length(params));
         req.SetKeyMaterial("foo", 3);
@@ -181,7 +263,7 @@
 }
 
 TEST(RoundTrip, GetKeyCharacteristicsResponse) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         GetKeyCharacteristicsResponse msg(ver);
         msg.error = KM_ERROR_OK;
         msg.enforced.Reinitialize(params, array_length(params));
@@ -194,7 +276,7 @@
 }
 
 TEST(RoundTrip, BeginOperationRequest) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         BeginOperationRequest msg(ver);
         msg.purpose = KM_PURPOSE_SIGN;
         msg.SetKeyMaterial("foo", 3);
@@ -209,7 +291,7 @@
 }
 
 TEST(RoundTrip, BeginOperationResponse) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         BeginOperationResponse msg(ver);
         msg.error = KM_ERROR_OK;
         msg.op_handle = 0xDEADBEEF;
@@ -223,6 +305,7 @@
         case 1:
         case 2:
         case 3:
+        case 4:
             deserialized.reset(round_trip(ver, msg, 39));
             break;
         default:
@@ -239,6 +322,7 @@
         case 1:
         case 2:
         case 3:
+        case 4:
             EXPECT_EQ(msg.output_params, deserialized->output_params);
             break;
         default:
@@ -248,7 +332,7 @@
 }
 
 TEST(RoundTrip, BeginOperationResponseError) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         BeginOperationResponse msg(ver);
         msg.error = KM_ERROR_INVALID_OPERATION_HANDLE;
         msg.op_handle = 0xDEADBEEF;
@@ -259,7 +343,7 @@
 }
 
 TEST(RoundTrip, UpdateOperationRequest) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         UpdateOperationRequest msg(ver);
         msg.op_handle = 0xDEADBEEF;
         msg.input.Reinitialize("foo", 3);
@@ -272,6 +356,7 @@
         case 1:
         case 2:
         case 3:
+        case 4:
             deserialized.reset(round_trip(ver, msg, 27));
             break;
         default:
@@ -283,7 +368,7 @@
 }
 
 TEST(RoundTrip, UpdateOperationResponse) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         UpdateOperationResponse msg(ver);
         msg.error = KM_ERROR_OK;
         msg.output.Reinitialize("foo", 3);
@@ -300,6 +385,7 @@
             break;
         case 2:
         case 3:
+        case 4:
             deserialized.reset(round_trip(ver, msg, 42));
             break;
         default:
@@ -318,6 +404,7 @@
             break;
         case 2:
         case 3:
+        case 4:
             EXPECT_EQ(99U, deserialized->input_consumed);
             EXPECT_EQ(1U, deserialized->output_params.size());
             break;
@@ -328,7 +415,7 @@
 }
 
 TEST(RoundTrip, FinishOperationRequest) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         FinishOperationRequest msg(ver);
         msg.op_handle = 0xDEADBEEF;
         msg.signature.Reinitialize("bar", 3);
@@ -344,6 +431,7 @@
             deserialized.reset(round_trip(ver, msg, 27));
             break;
         case 3:
+        case 4:
             deserialized.reset(round_trip(ver, msg, 34));
             break;
         default:
@@ -356,7 +444,7 @@
 }
 
 TEST(Round_Trip, FinishOperationResponse) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         FinishOperationResponse msg(ver);
         msg.error = KM_ERROR_OK;
         msg.output.Reinitialize("foo", 3);
@@ -369,6 +457,7 @@
             break;
         case 2:
         case 3:
+        case 4:
             deserialized.reset(round_trip(ver, msg, 23));
             break;
         default:
@@ -382,40 +471,81 @@
 }
 
 TEST(RoundTrip, ImportKeyRequest) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         ImportKeyRequest msg(ver);
         msg.key_description.Reinitialize(params, array_length(params));
         msg.key_format = KM_KEY_FORMAT_X509;
-        msg.SetKeyMaterial("foo", 3);
+        msg.key_data = KeymasterKeyBlob(reinterpret_cast<const uint8_t*>("foo"), 3);
+        msg.attestation_signing_key_blob =
+            KeymasterKeyBlob(reinterpret_cast<const uint8_t*>("bar"), 3);
+        msg.attest_key_params.Reinitialize(params, array_length(params));
+        msg.issuer_subject = KeymasterBlob(reinterpret_cast<const uint8_t*>("bar"), 3);
 
-        UniquePtr<ImportKeyRequest> deserialized(round_trip(ver, msg, 89));
+        UniquePtr<ImportKeyRequest> deserialized(round_trip(ver, msg, ver < 4 ? 89 : 181));
         EXPECT_EQ(msg.key_description, deserialized->key_description);
         EXPECT_EQ(msg.key_format, deserialized->key_format);
-        EXPECT_EQ(msg.key_data_length, deserialized->key_data_length);
-        EXPECT_EQ(0, memcmp(msg.key_data, deserialized->key_data, msg.key_data_length));
+        EXPECT_EQ(msg.key_data.key_material_size, deserialized->key_data.key_material_size);
+        EXPECT_EQ(0, memcmp(msg.key_data.key_material, deserialized->key_data.key_material,
+                            msg.key_data.key_material_size));
+        if (ver < 4) {
+            EXPECT_EQ(0U, deserialized->attestation_signing_key_blob.key_material_size);
+        } else {
+            EXPECT_EQ(3U, deserialized->attestation_signing_key_blob.key_material_size);
+            EXPECT_EQ(0, memcmp(msg.attestation_signing_key_blob.key_material,
+                                deserialized->attestation_signing_key_blob.key_material,
+                                msg.attestation_signing_key_blob.key_material_size));
+            EXPECT_EQ(deserialized->attest_key_params, msg.attest_key_params);
+            EXPECT_EQ(0, memcmp(msg.issuer_subject.data, deserialized->issuer_subject.data,
+                                deserialized->issuer_subject.data_length));
+        }
     }
 }
 
 TEST(RoundTrip, ImportKeyResponse) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         ImportKeyResponse msg(ver);
         msg.error = KM_ERROR_OK;
         msg.SetKeyMaterial("foo", 3);
         msg.enforced.Reinitialize(params, array_length(params));
         msg.unenforced.Reinitialize(params, array_length(params));
 
-        UniquePtr<ImportKeyResponse> deserialized(round_trip(ver, msg, 167));
+        msg.certificate_chain = CertificateChain(3);
+        msg.certificate_chain.entries[0] = {dup_buffer("foo", 3), 3};
+        msg.certificate_chain.entries[1] = {dup_buffer("bar", 3), 3};
+        msg.certificate_chain.entries[2] = {dup_buffer("baz", 3), 3};
+
+        UniquePtr<ImportKeyResponse> deserialized;
+        if (ver < 4) {
+            deserialized.reset(round_trip(ver, msg, 167));
+        } else {
+            deserialized.reset(round_trip(ver, msg, 192));
+        }
+
         EXPECT_EQ(msg.error, deserialized->error);
         EXPECT_EQ(msg.key_blob.key_material_size, deserialized->key_blob.key_material_size);
         EXPECT_EQ(0, memcmp(msg.key_blob.key_material, deserialized->key_blob.key_material,
                             msg.key_blob.key_material_size));
         EXPECT_EQ(msg.enforced, deserialized->enforced);
         EXPECT_EQ(msg.unenforced, deserialized->unenforced);
+
+        keymaster_cert_chain_t* chain = &deserialized->certificate_chain;
+        if (ver < 4) {
+            EXPECT_EQ(nullptr, chain->entries);
+        } else {
+            EXPECT_NE(nullptr, chain->entries);
+            EXPECT_EQ(3U, chain->entry_count);
+            EXPECT_EQ(3U, chain->entries[0].data_length);
+            EXPECT_EQ(0, memcmp("foo", chain->entries[0].data, 3));
+            EXPECT_EQ(3U, chain->entries[1].data_length);
+            EXPECT_EQ(0, memcmp("bar", chain->entries[1].data, 3));
+            EXPECT_EQ(3U, chain->entries[2].data_length);
+            EXPECT_EQ(0, memcmp("baz", chain->entries[2].data, 3));
+        }
     }
 }
 
 TEST(RoundTrip, ExportKeyRequest) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         ExportKeyRequest msg(ver);
         msg.additional_params.Reinitialize(params, array_length(params));
         msg.key_format = KM_KEY_FORMAT_X509;
@@ -430,7 +560,7 @@
 }
 
 TEST(RoundTrip, ExportKeyResponse) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         ExportKeyResponse msg(ver);
         msg.error = KM_ERROR_OK;
         msg.SetKeyMaterial("foo", 3);
@@ -442,7 +572,7 @@
 }
 
 TEST(RoundTrip, DeleteKeyRequest) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         DeleteKeyRequest msg(ver);
         msg.SetKeyMaterial("foo", 3);
 
@@ -452,29 +582,15 @@
     }
 }
 
-TEST(RoundTrip, DeleteKeyResponse) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
-        DeleteKeyResponse msg(ver);
-        UniquePtr<DeleteKeyResponse> deserialized(round_trip(ver, msg, 4));
-    }
-}
-
 TEST(RoundTrip, DeleteAllKeysRequest) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         DeleteAllKeysRequest msg(ver);
         UniquePtr<DeleteAllKeysRequest> deserialized(round_trip(ver, msg, 0));
     }
 }
 
-TEST(RoundTrip, DeleteAllKeysResponse) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
-        DeleteAllKeysResponse msg(ver);
-        UniquePtr<DeleteAllKeysResponse> deserialized(round_trip(ver, msg, 4));
-    }
-}
-
 TEST(RoundTrip, GetVersionRequest) {
-    GetVersionRequest msg;
+    GetVersionRequest msg(0);
 
     size_t size = msg.SerializedSize();
     ASSERT_EQ(0U, size);
@@ -489,7 +605,7 @@
 }
 
 TEST(RoundTrip, GetVersionResponse) {
-    GetVersionResponse msg;
+    GetVersionResponse msg(0);
     msg.error = KM_ERROR_OK;
     msg.major_ver = 9;
     msg.minor_ver = 98;
@@ -510,8 +626,45 @@
     EXPECT_EQ(38U, msg.subminor_ver);
 }
 
+TEST(RoundTrip, GetVersion2Request) {
+    GetVersion2Request msg;
+
+    msg.max_message_version = 0xDEADBEEF;
+    size_t size = msg.SerializedSize();
+    ASSERT_EQ(4U, size);
+
+    UniquePtr<uint8_t[]> buf(new uint8_t[size]);
+    EXPECT_EQ(buf.get() + size, msg.Serialize(buf.get(), buf.get() + size));
+
+    GetVersion2Request deserialized;
+    const uint8_t* p = buf.get();
+    EXPECT_TRUE(deserialized.Deserialize(&p, p + size));
+    EXPECT_EQ((ptrdiff_t)size, p - buf.get());
+    EXPECT_EQ(0xDEADBEEF, msg.max_message_version);
+}
+
+TEST(RoundTrip, GetVersion2Response) {
+    GetVersion2Response msg;
+    msg.error = KM_ERROR_OK;
+    msg.km_version = KmVersion::KEYMINT_1;
+    msg.km_date = 20121900;
+
+    size_t size = msg.SerializedSize();
+    ASSERT_EQ(16U, size);
+
+    UniquePtr<uint8_t[]> buf(new uint8_t[size]);
+    EXPECT_EQ(buf.get() + size, msg.Serialize(buf.get(), buf.get() + size));
+
+    GetVersion2Response deserialized;
+    const uint8_t* p = buf.get();
+    EXPECT_TRUE(deserialized.Deserialize(&p, p + size));
+    EXPECT_EQ((ptrdiff_t)size, p - buf.get());
+    EXPECT_EQ(KmVersion::KEYMINT_1, msg.km_version);
+    EXPECT_EQ(20121900U, msg.km_date);
+}
+
 TEST(RoundTrip, ConfigureRequest) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         ConfigureRequest req(ver);
         req.os_version = 1;
         req.os_patchlevel = 1;
@@ -523,14 +676,48 @@
 }
 
 TEST(RoundTrip, ConfigureResponse) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         ConfigureResponse rsp(ver);
         UniquePtr<ConfigureResponse> deserialized(round_trip(ver, rsp, 4));
     }
 }
 
+TEST(RoundTrip, ConfigureVendorPatchlevelRequest) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
+        ConfigureVendorPatchlevelRequest req(ver);
+        req.vendor_patchlevel = 2;
+
+        UniquePtr<ConfigureVendorPatchlevelRequest> deserialized(round_trip(ver, req, 4));
+        EXPECT_EQ(deserialized->vendor_patchlevel, req.vendor_patchlevel);
+    }
+}
+
+TEST(RoundTrip, ConfigureVendorPatchlevelResponse) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
+        ConfigureVendorPatchlevelResponse rsp(ver);
+        UniquePtr<ConfigureVendorPatchlevelResponse> deserialized(round_trip(ver, rsp, 4));
+    }
+}
+
+TEST(RoundTrip, ConfigureBootPatchlevelRequest) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
+        ConfigureBootPatchlevelRequest req(ver);
+        req.boot_patchlevel = 2;
+
+        UniquePtr<ConfigureBootPatchlevelRequest> deserialized(round_trip(ver, req, 4));
+        EXPECT_EQ(deserialized->boot_patchlevel, req.boot_patchlevel);
+    }
+}
+
+TEST(RoundTrip, ConfigureBootPatchlevelResponse) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
+        ConfigureBootPatchlevelResponse rsp(ver);
+        UniquePtr<ConfigureBootPatchlevelResponse> deserialized(round_trip(ver, rsp, 4));
+    }
+}
+
 TEST(RoundTrip, AddEntropyRequest) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         AddEntropyRequest msg(ver);
         msg.random_data.Reinitialize("foo", 3);
 
@@ -540,29 +727,15 @@
     }
 }
 
-TEST(RoundTrip, AddEntropyResponse) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
-        AddEntropyResponse msg(ver);
-        UniquePtr<AddEntropyResponse> deserialized(round_trip(ver, msg, 4));
-    }
-}
-
 TEST(RoundTrip, AbortOperationRequest) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         AbortOperationRequest msg(ver);
         UniquePtr<AbortOperationRequest> deserialized(round_trip(ver, msg, 8));
     }
 }
 
-TEST(RoundTrip, AbortOperationResponse) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
-        AbortOperationResponse msg(ver);
-        UniquePtr<AbortOperationResponse> deserialized(round_trip(ver, msg, 4));
-    }
-}
-
 TEST(RoundTrip, AttestKeyRequest) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         AttestKeyRequest msg(ver);
         msg.SetKeyMaterial("foo", 3);
         msg.attest_params.Reinitialize(params, array_length(params));
@@ -575,10 +748,11 @@
 }
 
 TEST(RoundTrip, AttestKeyResponse) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         AttestKeyResponse msg(ver);
         msg.error = KM_ERROR_OK;
-        EXPECT_TRUE(msg.AllocateChain(3));
+        msg.certificate_chain = CertificateChain(3);
+        EXPECT_TRUE(!!msg.certificate_chain.entries);
         msg.certificate_chain.entries[0] = {dup_buffer("foo", 3), 3};
         msg.certificate_chain.entries[1] = {dup_buffer("bar", 3), 3};
         msg.certificate_chain.entries[2] = {dup_buffer("baz", 3), 3};
@@ -598,7 +772,7 @@
 }
 
 TEST(RoundTrip, UpgradeKeyRequest) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         UpgradeKeyRequest msg(ver);
         msg.SetKeyMaterial("foo", 3);
         msg.upgrade_params.Reinitialize(params, array_length(params));
@@ -611,7 +785,7 @@
 }
 
 TEST(RoundTrip, UpgradeKeyResponse) {
-    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
         UpgradeKeyResponse req(ver);
         req.error = KM_ERROR_OK;
         req.upgraded_key.key_material = dup_array(TEST_DATA);
@@ -625,6 +799,67 @@
     }
 }
 
+TEST(RoundTrip, GenerateTimestampTokenRequest) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
+        GenerateTimestampTokenRequest msg(ver);
+        msg.challenge = 1;
+        UniquePtr<GenerateTimestampTokenRequest> deserialized(round_trip(ver, msg, 8));
+        EXPECT_EQ(1U, deserialized->challenge);
+    }
+}
+
+TEST(RoundTrip, GenerateTimestampTokenResponse) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
+        GenerateTimestampTokenResponse msg(ver);
+        msg.error = KM_ERROR_OK;
+        msg.token.challenge = 1;
+        msg.token.timestamp = 2;
+        msg.token.security_level = KM_SECURITY_LEVEL_SOFTWARE;
+        msg.token.mac.data = dup_array(TEST_DATA);
+        msg.token.mac.data_length = array_length(TEST_DATA);
+        UniquePtr<GenerateTimestampTokenResponse> deserialized(round_trip(ver, msg, 39));
+        EXPECT_EQ(1U, deserialized->token.challenge);
+        EXPECT_EQ(2U, deserialized->token.timestamp);
+        EXPECT_EQ(KM_SECURITY_LEVEL_SOFTWARE, deserialized->token.security_level);
+        EXPECT_EQ(msg.token.mac.data_length, deserialized->token.mac.data_length);
+        EXPECT_EQ(
+            0, memcmp(msg.token.mac.data, deserialized->token.mac.data, msg.token.mac.data_length));
+    }
+}
+
+#define SET_ATTESTATION_ID(x) msg.x.Reinitialize(#x, strlen(#x))
+
+void check_id(const Buffer& id, const char* value) {
+    auto len = strlen(value);
+    EXPECT_EQ(id.available_read(), len) << "On " << value;
+    EXPECT_TRUE(memcmp(id.peek_read(), value, len) == 0) << "On " << value;
+}
+
+#define CHECK_ID(x) check_id(deserialized->x, #x);
+
+TEST(RoundTrip, SetAttestationIdsRequest) {
+    for (int ver = 0; ver <= kMaxMessageVersion; ++ver) {
+        SetAttestationIdsRequest msg(ver);
+        SET_ATTESTATION_ID(brand);
+        SET_ATTESTATION_ID(device);
+        SET_ATTESTATION_ID(product);
+        SET_ATTESTATION_ID(serial);
+        SET_ATTESTATION_ID(imei);
+        SET_ATTESTATION_ID(meid);
+        SET_ATTESTATION_ID(manufacturer);
+        SET_ATTESTATION_ID(model);
+
+        UniquePtr<SetAttestationIdsRequest> deserialized(round_trip(ver, msg, 81));
+        ASSERT_TRUE(deserialized);
+        CHECK_ID(brand);
+        CHECK_ID(device);
+        CHECK_ID(product);
+        CHECK_ID(serial);
+        CHECK_ID(imei);
+        CHECK_ID(model);
+    }
+}
+
 uint8_t msgbuf[] = {
     220, 88,  183, 255, 71,  1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
     0,   173, 0,   0,   0,   228, 174, 98,  187, 191, 135, 253, 200, 51,  230, 114, 247, 151, 109,
@@ -659,7 +894,7 @@
  */
 
 template <typename Message> void parse_garbage() {
-    for (int32_t ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+    for (int32_t ver = 0; ver <= kMaxMessageVersion; ++ver) {
         Message msg(ver);
         const uint8_t* end = msgbuf + array_length(msgbuf);
         for (size_t i = 0; i < array_length(msgbuf); ++i) {
@@ -679,7 +914,7 @@
     for (size_t i = 0; i < kBufSize; ++i)
         buf[i] = static_cast<uint8_t>(rand());
 
-    for (uint32_t ver = 0; ver < MAX_MESSAGE_VERSION; ++ver) {
+    for (uint32_t ver = 0; ver < kMaxMessageVersion; ++ver) {
         Message msg(ver);
         const uint8_t* end = buf.get() + kBufSize;
         for (size_t i = 0; i < kBufSize; ++i) {
@@ -694,15 +929,12 @@
     TEST(GarbageTest, Message) { parse_garbage<Message>(); }
 
 GARBAGE_TEST(AbortOperationRequest);
-GARBAGE_TEST(AbortOperationResponse);
+GARBAGE_TEST(EmptyKeymasterResponse);
 GARBAGE_TEST(AddEntropyRequest);
-GARBAGE_TEST(AddEntropyResponse);
 GARBAGE_TEST(BeginOperationRequest);
 GARBAGE_TEST(BeginOperationResponse);
 GARBAGE_TEST(DeleteAllKeysRequest);
-GARBAGE_TEST(DeleteAllKeysResponse);
 GARBAGE_TEST(DeleteKeyRequest);
-GARBAGE_TEST(DeleteKeyResponse);
 GARBAGE_TEST(ExportKeyRequest);
 GARBAGE_TEST(ExportKeyResponse);
 GARBAGE_TEST(FinishOperationRequest);
@@ -713,19 +945,15 @@
 GARBAGE_TEST(GetKeyCharacteristicsResponse);
 GARBAGE_TEST(ImportKeyRequest);
 GARBAGE_TEST(ImportKeyResponse);
-GARBAGE_TEST(SupportedByAlgorithmAndPurposeRequest)
-GARBAGE_TEST(SupportedByAlgorithmRequest)
 GARBAGE_TEST(UpdateOperationRequest);
 GARBAGE_TEST(UpdateOperationResponse);
 GARBAGE_TEST(AttestKeyRequest);
 GARBAGE_TEST(AttestKeyResponse);
 GARBAGE_TEST(UpgradeKeyRequest);
 GARBAGE_TEST(UpgradeKeyResponse);
-
-// The macro doesn't work on this one.
-TEST(GarbageTest, SupportedResponse) {
-    parse_garbage<SupportedResponse<keymaster_digest_t>>();
-}
+GARBAGE_TEST(GenerateTimestampTokenRequest);
+GARBAGE_TEST(GenerateTimestampTokenResponse);
+GARBAGE_TEST(SetAttestationIdsRequest);
 
 }  // namespace test
 
diff --git a/tests/android_keymaster_test.cpp b/tests/android_keymaster_test.cpp
index 253ee92..7c06ce3 100644
--- a/tests/android_keymaster_test.cpp
+++ b/tests/android_keymaster_test.cpp
@@ -22,20 +22,18 @@
 #include <openssl/evp.h>
 #include <openssl/x509.h>
 
-#include <hardware/keymaster0.h>
-
 #include <keymaster/android_keymaster.h>
-#include <keymaster/attestation_record.h>
 #include <keymaster/contexts/pure_soft_keymaster_context.h>
 #include <keymaster/contexts/soft_keymaster_context.h>
 #include <keymaster/key_factory.h>
+#include <keymaster/km_openssl/attestation_record.h>
 #include <keymaster/km_openssl/hmac_key.h>
 #include <keymaster/km_openssl/openssl_utils.h>
 #include <keymaster/km_openssl/soft_keymaster_enforcement.h>
-#include <keymaster/legacy_support/keymaster0_engine.h>
 #include <keymaster/soft_keymaster_device.h>
 
 #include "android_keymaster_test_utils.h"
+#include "test_keys.h"
 
 using std::ifstream;
 using std::istreambuf_iterator;
@@ -97,9 +95,12 @@
  */
 class TestKeymasterContext : public SoftKeymasterContext {
   public:
-    TestKeymasterContext() {}
+    TestKeymasterContext() : SoftKeymasterContext(kCurrentKmVersion) {}
+    TestKeymasterContext(KmVersion version) : SoftKeymasterContext(version) {}
     explicit TestKeymasterContext(const string& root_of_trust)
-        : SoftKeymasterContext(root_of_trust) {}
+        : SoftKeymasterContext(kCurrentKmVersion, root_of_trust) {}
+    explicit TestKeymasterContext(KmVersion version, const string& root_of_trust)
+        : SoftKeymasterContext(version, root_of_trust) {}
 
     KeymasterEnforcement* enforcement_policy() override { return &test_policy_; }
 
@@ -114,7 +115,7 @@
   public:
     keymaster2_device_t* CreateDevice() const override {
         std::cerr << "Creating software-only device" << std::endl;
-        context_ = new TestKeymasterContext;
+        context_ = new TestKeymasterContext(KmVersion::KEYMASTER_4_1);
         SoftKeymasterDevice* device = new SoftKeymasterDevice(context_);
         AuthorizationSet version_info(AuthorizationSetBuilder()
                                           .Authorization(TAG_OS_VERSION, kOsVersion)
@@ -123,11 +124,10 @@
         return device->keymaster2_device();
     }
 
-    bool algorithm_in_km0_hardware(keymaster_algorithm_t) const override { return false; }
-    int keymaster0_calls() const override { return 0; }
     bool is_keymaster1_hw() const override { return false; }
     KeymasterContext* keymaster_context() const override { return context_; }
     string name() const override { return "Soft Keymaster2"; }
+    KmVersion km_version() const override { return KmVersion::KEYMASTER_4_1; }
 
   private:
     mutable TestKeymasterContext* context_;
@@ -142,11 +142,13 @@
         std::cerr << "Creating keymaster1-backed device that supports only SHA256";
 
         // fake_device doesn't leak because device (below) takes ownership of it.
-        keymaster1_device_t* fake_device = make_device_sha256_only(
-            (new SoftKeymasterDevice(new TestKeymasterContext("PseudoHW")))->keymaster_device());
+        keymaster1_device_t* fake_device =
+            make_device_sha256_only((new SoftKeymasterDevice(new TestKeymasterContext(
+                                         KmVersion::KEYMASTER_4_1, "PseudoHW")))
+                                        ->keymaster_device());
 
         // device doesn't leak; it's cleaned up by device->keymaster_device()->common.close().
-        context_ = new TestKeymasterContext;
+        context_ = new TestKeymasterContext(KmVersion::KEYMASTER_4_1);
         SoftKeymasterDevice* device = new SoftKeymasterDevice(context_);
         device->SetHardwareDevice(fake_device);
 
@@ -157,12 +159,11 @@
         return device->keymaster2_device();
     }
 
-    bool algorithm_in_km0_hardware(keymaster_algorithm_t) const override { return false; }
-    int keymaster0_calls() const override { return 0; }
     int minimal_digest_set() const override { return true; }
     bool is_keymaster1_hw() const override { return true; }
     KeymasterContext* keymaster_context() const override { return context_; }
     string name() const override { return "Wrapped fake keymaster1 w/minimal digests"; }
+    KmVersion km_version() const override { return KmVersion::KEYMASTER_4_1; }
 
   private:
     mutable TestKeymasterContext* context_;
@@ -177,11 +178,12 @@
         std::cerr << "Creating keymaster1-backed device";
 
         // fake_device doesn't leak because device (below) takes ownership of it.
-        keymaster1_device_t* fake_device =
-            (new SoftKeymasterDevice(new TestKeymasterContext("PseudoHW")))->keymaster_device();
+        keymaster1_device_t* fake_device = (new SoftKeymasterDevice(new TestKeymasterContext(
+                                                KmVersion::KEYMASTER_4_1, "PseudoHW")))
+                                               ->keymaster_device();
 
         // device doesn't leak; it's cleaned up by device->keymaster_device()->common.close().
-        context_ = new TestKeymasterContext;
+        context_ = new TestKeymasterContext(KmVersion::KEYMASTER_4_1);
         SoftKeymasterDevice* device = new SoftKeymasterDevice(context_);
         device->SetHardwareDevice(fake_device);
 
@@ -192,21 +194,20 @@
         return device->keymaster2_device();
     }
 
-    bool algorithm_in_km0_hardware(keymaster_algorithm_t) const override { return false; }
-    int keymaster0_calls() const override { return 0; }
     int minimal_digest_set() const override { return false; }
     bool is_keymaster1_hw() const override { return true; }
     KeymasterContext* keymaster_context() const override { return context_; }
     string name() const override { return "Wrapped fake keymaster1 w/full digests"; }
+    KmVersion km_version() const override { return KmVersion::KEYMASTER_4_1; }
 
   private:
     mutable TestKeymasterContext* context_;
 };
 
-static auto test_params = testing::Values(
-    InstanceCreatorPtr(new SoftKeymasterTestInstanceCreator),
-    InstanceCreatorPtr(new Keymaster1TestInstanceCreator),
-    InstanceCreatorPtr(new Sha256OnlyKeymaster1TestInstanceCreator));
+static auto test_params =
+    testing::Values(InstanceCreatorPtr(new SoftKeymasterTestInstanceCreator),
+                    InstanceCreatorPtr(new Keymaster1TestInstanceCreator),
+                    InstanceCreatorPtr(new Sha256OnlyKeymaster1TestInstanceCreator));
 
 class NewKeyGeneration : public Keymaster2Test {
   protected:
@@ -256,16 +257,9 @@
     // Check specified tags are all present, and in the right set.
     AuthorizationSet crypto_params;
     AuthorizationSet non_crypto_params;
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) {
-        EXPECT_NE(0U, hw_enforced().size());
-        EXPECT_NE(0U, sw_enforced().size());
-        crypto_params.push_back(hw_enforced());
-        non_crypto_params.push_back(sw_enforced());
-    } else {
-        EXPECT_EQ(0U, hw_enforced().size());
-        EXPECT_NE(0U, sw_enforced().size());
-        crypto_params.push_back(sw_enforced());
-    }
+    EXPECT_EQ(0U, hw_enforced().size());
+    EXPECT_NE(0U, sw_enforced().size());
+    crypto_params.push_back(sw_enforced());
 
     EXPECT_TRUE(contains(crypto_params, TAG_ALGORITHM, KM_ALGORITHM_RSA));
     EXPECT_FALSE(contains(non_crypto_params, TAG_ALGORITHM, KM_ALGORITHM_RSA));
@@ -275,9 +269,6 @@
     EXPECT_FALSE(contains(non_crypto_params, TAG_RSA_PUBLIC_EXPONENT, 3));
 
     EXPECT_EQ(KM_ERROR_OK, DeleteKey());
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(2, GetParam()->keymaster0_calls());
 }
 
 TEST_P(NewKeyGeneration, RsaDefaultSize) {
@@ -286,8 +277,6 @@
                               .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
                               .Authorization(TAG_RSA_PUBLIC_EXPONENT, 3)
                               .SigningKey()));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(NewKeyGeneration, Ecdsa) {
@@ -298,24 +287,14 @@
     // Check specified tags are all present, and in the right set.
     AuthorizationSet crypto_params;
     AuthorizationSet non_crypto_params;
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) {
-        EXPECT_NE(0U, hw_enforced().size());
-        EXPECT_NE(0U, sw_enforced().size());
-        crypto_params.push_back(hw_enforced());
-        non_crypto_params.push_back(sw_enforced());
-    } else {
-        EXPECT_EQ(0U, hw_enforced().size());
-        EXPECT_NE(0U, sw_enforced().size());
-        crypto_params.push_back(sw_enforced());
-    }
+    EXPECT_EQ(0U, hw_enforced().size());
+    EXPECT_NE(0U, sw_enforced().size());
+    crypto_params.push_back(sw_enforced());
 
     EXPECT_TRUE(contains(crypto_params, TAG_ALGORITHM, KM_ALGORITHM_EC));
     EXPECT_FALSE(contains(non_crypto_params, TAG_ALGORITHM, KM_ALGORITHM_EC));
     EXPECT_TRUE(contains(crypto_params, TAG_KEY_SIZE, 224));
     EXPECT_FALSE(contains(non_crypto_params, TAG_KEY_SIZE, 224));
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
-        EXPECT_EQ(1, GetParam()->keymaster0_calls());
 }
 
 TEST_P(NewKeyGeneration, EcdsaDefaultSize) {
@@ -324,14 +303,11 @@
                               .Authorization(TAG_ALGORITHM, KM_ALGORITHM_EC)
                               .SigningKey()
                               .Digest(KM_DIGEST_NONE)));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(NewKeyGeneration, EcdsaInvalidSize) {
     ASSERT_EQ(KM_ERROR_UNSUPPORTED_KEY_SIZE,
               GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(190).Digest(KM_DIGEST_NONE)));
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(NewKeyGeneration, EcdsaMismatchKeySize) {
@@ -349,9 +325,6 @@
                                    KM_DIGEST_NONE)))
             << "Failed to generate size: " << size;
     }
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
-        EXPECT_EQ(4, GetParam()->keymaster0_calls());
 }
 
 TEST_P(NewKeyGeneration, HmacSha256) {
@@ -359,8 +332,6 @@
                                            .HmacKey(128)
                                            .Digest(KM_DIGEST_SHA_2_256)
                                            .Authorization(TAG_MIN_MAC_LENGTH, 256)));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(NewKeyGeneration, CheckKeySizes) {
@@ -380,7 +351,6 @@
                                                    .Authorization(TAG_MIN_MAC_LENGTH, 256)));
         }
     }
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(NewKeyGeneration, HmacMultipleDigests) {
@@ -390,8 +360,6 @@
                               .Digest(KM_DIGEST_SHA1)
                               .Digest(KM_DIGEST_SHA_2_256)
                               .Authorization(TAG_MIN_MAC_LENGTH, 128)));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(NewKeyGeneration, HmacDigestNone) {
@@ -400,8 +368,6 @@
                               .HmacKey(128)
                               .Digest(KM_DIGEST_NONE)
                               .Authorization(TAG_MIN_MAC_LENGTH, 128)));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(NewKeyGeneration, HmacSha256TooShortMacLength) {
@@ -410,8 +376,6 @@
                               .HmacKey(128)
                               .Digest(KM_DIGEST_SHA_2_256)
                               .Authorization(TAG_MIN_MAC_LENGTH, 48)));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(NewKeyGeneration, HmacSha256NonIntegralOctetMacLength) {
@@ -420,8 +384,6 @@
                               .HmacKey(128)
                               .Digest(KM_DIGEST_SHA_2_256)
                               .Authorization(TAG_MIN_MAC_LENGTH, 130)));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(NewKeyGeneration, HmacSha256TooLongMacLength) {
@@ -430,8 +392,6 @@
                               .HmacKey(128)
                               .Digest(KM_DIGEST_SHA_2_256)
                               .Authorization(TAG_MIN_MAC_LENGTH, 384)));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 typedef Keymaster2Test GetKeyCharacteristics;
@@ -446,9 +406,6 @@
 
     ASSERT_EQ(KM_ERROR_OK, GetCharacteristics());
     EXPECT_EQ(original, sw_enforced());
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(1, GetParam()->keymaster0_calls());
 }
 
 typedef Keymaster2Test SigningOperationsTest;
@@ -462,9 +419,6 @@
     string message = "12345678901234567890123456789012";
     string signature;
     SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(3, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, RsaPssSha256Success) {
@@ -476,9 +430,6 @@
     string message(1024, 'a');
     string signature;
     SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PSS);
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(3, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, RsaPaddingNoneDoesNotAllowOther) {
@@ -493,9 +444,6 @@
     begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
     begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN);
     EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PADDING_MODE, BeginOperation(KM_PURPOSE_SIGN, begin_params));
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(2, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, RsaPkcs1Sha256Success) {
@@ -506,9 +454,6 @@
     string message(1024, 'a');
     string signature;
     SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PKCS1_1_5_SIGN);
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(3, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, RsaPkcs1NoDigestSuccess) {
@@ -519,9 +464,6 @@
     string message(53, 'a');
     string signature;
     SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_RSA_PKCS1_1_5_SIGN);
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(3, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, RsaPkcs1NoDigestTooLarge) {
@@ -538,9 +480,6 @@
     string result;
     string signature;
     EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(message, "", &signature));
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(2, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, RsaPssSha256TooSmallKey) {
@@ -573,9 +512,6 @@
     string result;
     size_t input_consumed;
     EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, UpdateOperation(message, &result, &input_consumed));
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(2, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, RsaAbort) {
@@ -590,9 +526,6 @@
     EXPECT_EQ(KM_ERROR_OK, AbortOperation());
     // Another abort should fail
     EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, AbortOperation());
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(2, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, RsaUnsupportedPadding) {
@@ -603,9 +536,6 @@
     AuthorizationSet begin_params(client_params());
     begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
     ASSERT_EQ(KM_ERROR_UNSUPPORTED_PADDING_MODE, BeginOperation(KM_PURPOSE_SIGN, begin_params));
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(2, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, RsaNoDigest) {
@@ -618,9 +548,6 @@
     begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
     begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PSS);
     ASSERT_EQ(KM_ERROR_INCOMPATIBLE_DIGEST, BeginOperation(KM_PURPOSE_SIGN, begin_params));
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(2, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, RsaNoPadding) {
@@ -630,9 +557,6 @@
     AuthorizationSet begin_params(client_params());
     begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
     ASSERT_EQ(KM_ERROR_UNSUPPORTED_PADDING_MODE, BeginOperation(KM_PURPOSE_SIGN, begin_params));
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(2, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, RsaTooShortMessage) {
@@ -643,9 +567,6 @@
     string message = "1234567890123456789012345678901";
     string signature;
     SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(3, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, RsaSignWithEncryptionKey) {
@@ -657,9 +578,6 @@
     begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
     begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
     ASSERT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE, BeginOperation(KM_PURPOSE_SIGN, begin_params));
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(2, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, RsaSignTooLargeMessage) {
@@ -679,9 +597,6 @@
     ASSERT_EQ(message.size(), input_consumed);
     string output;
     ASSERT_EQ(KM_ERROR_INVALID_ARGUMENT, FinishOperation(&output));
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(3, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, EcdsaSuccess) {
@@ -690,9 +605,6 @@
     string message(224 / 8, 'a');
     string signature;
     SignMessage(message, &signature, KM_DIGEST_NONE);
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
-        EXPECT_EQ(3, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, EcdsaSha256Success) {
@@ -701,9 +613,6 @@
     string message(1024, 'a');
     string signature;
     SignMessage(message, &signature, KM_DIGEST_SHA_2_256);
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
-        EXPECT_EQ(3, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, EcdsaSha384Success) {
@@ -712,9 +621,6 @@
     string message(1024, 'a');
     string signature;
     SignMessage(message, &signature, KM_DIGEST_SHA_2_384);
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
-        EXPECT_EQ(3, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, EcdsaNoPaddingHugeData) {
@@ -728,9 +634,6 @@
     string result;
     size_t input_consumed;
     EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
-        EXPECT_EQ(2, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, EcdsaAllSizesAndHashes) {
@@ -748,15 +651,10 @@
 
             string message(1024, 'a');
             string signature;
-            if (digest == KM_DIGEST_NONE)
-                message.resize(key_size / 8);
+            if (digest == KM_DIGEST_NONE) message.resize(key_size / 8);
             SignMessage(message, &signature, digest);
         }
     }
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
-        EXPECT_EQ(digests.size() * key_sizes.size() * 3,
-                  static_cast<size_t>(GetParam()->keymaster0_calls()));
 }
 
 TEST_P(SigningOperationsTest, AesEcbSign) {
@@ -765,8 +663,6 @@
                   TAG_BLOCK_MODE, KM_MODE_ECB)));
     ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, BeginOperation(KM_PURPOSE_SIGN));
     ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, BeginOperation(KM_PURPOSE_VERIFY));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, HmacSha1Success) {
@@ -778,8 +674,6 @@
     string signature;
     MacMessage(message, &signature, 160);
     ASSERT_EQ(20U, signature.size());
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, HmacSha224Success) {
@@ -791,8 +685,6 @@
     string signature;
     MacMessage(message, &signature, 224);
     ASSERT_EQ(28U, signature.size());
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, HmacSha256Success) {
@@ -804,8 +696,6 @@
     string signature;
     MacMessage(message, &signature, 256);
     ASSERT_EQ(32U, signature.size());
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, HmacSha384Success) {
@@ -818,8 +708,6 @@
     string signature;
     MacMessage(message, &signature, 384);
     ASSERT_EQ(48U, signature.size());
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, HmacSha512Success) {
@@ -831,8 +719,6 @@
     string signature;
     MacMessage(message, &signature, 512);
     ASSERT_EQ(64U, signature.size());
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, HmacLengthInKey) {
@@ -845,8 +731,6 @@
     string signature;
     MacMessage(message, &signature, 160);
     ASSERT_EQ(20U, signature.size());
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, HmacRfc4231TestCase3) {
@@ -879,8 +763,6 @@
     CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
     CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_384, make_string(sha_384_expected));
     CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_512, make_string(sha_512_expected));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, HmacRfc4231TestCase4) {
@@ -917,8 +799,6 @@
     CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
     CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_384, make_string(sha_384_expected));
     CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_512, make_string(sha_512_expected));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, HmacRfc4231TestCase5) {
@@ -946,8 +826,6 @@
     CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
     CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_384, make_string(sha_384_expected));
     CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_512, make_string(sha_512_expected));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, HmacRfc4231TestCase6) {
@@ -981,8 +859,6 @@
     CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
     CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_384, make_string(sha_384_expected));
     CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_512, make_string(sha_512_expected));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, HmacRfc4231TestCase7) {
@@ -1018,8 +894,6 @@
     CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
     CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_384, make_string(sha_384_expected));
     CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_512, make_string(sha_512_expected));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, HmacSha256TooLargeMacLength) {
@@ -1032,8 +906,6 @@
     begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
     ASSERT_EQ(KM_ERROR_UNSUPPORTED_MAC_LENGTH,
               BeginOperation(KM_PURPOSE_SIGN, begin_params, nullptr /* output_params */));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(SigningOperationsTest, HmacSha256TooSmallMacLength) {
@@ -1046,8 +918,6 @@
     begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
     ASSERT_EQ(KM_ERROR_INVALID_MAC_LENGTH,
               BeginOperation(KM_PURPOSE_SIGN, begin_params, nullptr /* output_params */));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 // TODO(swillden): Add more verification failure tests.
@@ -1064,9 +934,6 @@
     string signature;
     SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
     VerifyMessage(message, signature, KM_DIGEST_NONE, KM_PAD_NONE);
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(4, GetParam()->keymaster0_calls());
 }
 
 TEST_P(VerificationOperationsTest, RsaPssSha256Success) {
@@ -1079,9 +946,6 @@
     string signature;
     SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PSS);
     VerifyMessage(message, signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PSS);
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(4, GetParam()->keymaster0_calls());
 }
 
 TEST_P(VerificationOperationsTest, RsaPssSha224Success) {
@@ -1095,9 +959,6 @@
     SignMessage(message, &signature, KM_DIGEST_SHA_2_224, KM_PAD_RSA_PSS);
     VerifyMessage(message, signature, KM_DIGEST_SHA_2_224, KM_PAD_RSA_PSS);
 
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(4, GetParam()->keymaster0_calls());
-
     // Verify with OpenSSL.
     string pubkey;
     EXPECT_EQ(KM_ERROR_OK, ExportKey(KM_KEY_FORMAT_X509, &pubkey));
@@ -1137,9 +998,6 @@
 
     string result;
     EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(message, signature, &result));
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(4, GetParam()->keymaster0_calls());
 }
 
 TEST_P(VerificationOperationsTest, RsaPssSha256CorruptInput) {
@@ -1160,9 +1018,6 @@
 
     string result;
     EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(message, signature, &result));
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(4, GetParam()->keymaster0_calls());
 }
 
 TEST_P(VerificationOperationsTest, RsaPkcs1Sha256Success) {
@@ -1174,9 +1029,6 @@
     string signature;
     SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PKCS1_1_5_SIGN);
     VerifyMessage(message, signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PKCS1_1_5_SIGN);
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(4, GetParam()->keymaster0_calls());
 }
 
 TEST_P(VerificationOperationsTest, RsaPks1Sha224Success) {
@@ -1190,9 +1042,6 @@
     SignMessage(message, &signature, KM_DIGEST_SHA_2_224, KM_PAD_RSA_PKCS1_1_5_SIGN);
     VerifyMessage(message, signature, KM_DIGEST_SHA_2_224, KM_PAD_RSA_PKCS1_1_5_SIGN);
 
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(4, GetParam()->keymaster0_calls());
-
     // Verify with OpenSSL.
     string pubkey;
     EXPECT_EQ(KM_ERROR_OK, ExportKey(KM_KEY_FORMAT_X509, &pubkey));
@@ -1231,9 +1080,6 @@
 
     string result;
     EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(message, signature, &result));
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(4, GetParam()->keymaster0_calls());
 }
 
 TEST_P(VerificationOperationsTest, RsaPkcs1Sha256CorruptInput) {
@@ -1254,9 +1100,6 @@
 
     string result;
     EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(message, signature, &result));
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(4, GetParam()->keymaster0_calls());
 }
 
 TEST_P(VerificationOperationsTest, RsaAllDigestAndPadCombinations) {
@@ -1266,7 +1109,9 @@
     };
 
     vector<keymaster_padding_t> padding_modes{
-        KM_PAD_NONE, KM_PAD_RSA_PKCS1_1_5_SIGN, KM_PAD_RSA_PSS,
+        KM_PAD_NONE,
+        KM_PAD_RSA_PKCS1_1_5_SIGN,
+        KM_PAD_RSA_PSS,
     };
 
     int trial_count = 0;
@@ -1349,9 +1194,6 @@
             ++trial_count;
         }
     }
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(trial_count * 4, GetParam()->keymaster0_calls());
 }
 
 TEST_P(VerificationOperationsTest, EcdsaSuccess) {
@@ -1361,9 +1203,6 @@
     string signature;
     SignMessage(message, &signature, KM_DIGEST_NONE);
     VerifyMessage(message, signature, KM_DIGEST_NONE);
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
-        EXPECT_EQ(4, GetParam()->keymaster0_calls());
 }
 
 TEST_P(VerificationOperationsTest, EcdsaTooShort) {
@@ -1373,9 +1212,6 @@
     string signature;
     SignMessage(message, &signature, KM_DIGEST_NONE);
     VerifyMessage(message, signature, KM_DIGEST_NONE);
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
-        EXPECT_EQ(4, GetParam()->keymaster0_calls());
 }
 
 TEST_P(VerificationOperationsTest, EcdsaSlightlyTooLong) {
@@ -1390,9 +1226,6 @@
     // Modifying low-order bits doesn't matter, because they didn't get signed.  Ugh.
     message[65] ^= 7;
     VerifyMessage(message, signature, KM_DIGEST_NONE);
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
-        EXPECT_EQ(5, GetParam()->keymaster0_calls());
 }
 
 TEST_P(VerificationOperationsTest, EcdsaSha256Success) {
@@ -1405,9 +1238,6 @@
     SignMessage(message, &signature, KM_DIGEST_SHA_2_256);
     VerifyMessage(message, signature, KM_DIGEST_SHA_2_256);
 
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
-        EXPECT_EQ(4, GetParam()->keymaster0_calls());
-
     // Just for giggles, try verifying with the wrong digest.
     AuthorizationSet begin_params(client_params());
     begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
@@ -1426,9 +1256,6 @@
     SignMessage(message, &signature, KM_DIGEST_SHA_2_224);
     VerifyMessage(message, signature, KM_DIGEST_SHA_2_224);
 
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
-        EXPECT_EQ(4, GetParam()->keymaster0_calls());
-
     // Just for giggles, try verifying with the wrong digest.
     AuthorizationSet begin_params(client_params());
     begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
@@ -1462,10 +1289,6 @@
             VerifyMessage(message, signature, digest);
         }
     }
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
-        EXPECT_EQ(static_cast<int>(array_length(key_sizes) * (1 + 3 * array_length(digests))),
-                  GetParam()->keymaster0_calls());
 }
 
 TEST_P(VerificationOperationsTest, HmacSha1Success) {
@@ -1477,8 +1300,6 @@
     string signature;
     MacMessage(message, &signature, 160);
     VerifyMac(message, signature);
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(VerificationOperationsTest, HmacSha224Success) {
@@ -1490,8 +1311,6 @@
     string signature;
     MacMessage(message, &signature, 224);
     VerifyMac(message, signature);
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(VerificationOperationsTest, HmacSha256Success) {
@@ -1503,8 +1322,6 @@
     string signature;
     MacMessage(message, &signature, 256);
     VerifyMac(message, signature);
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(VerificationOperationsTest, HmacSha256TooShortMac) {
@@ -1527,8 +1344,6 @@
     EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params));
     string result;
     EXPECT_EQ(KM_ERROR_INVALID_MAC_LENGTH, FinishOperation(message, signature, &result));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(VerificationOperationsTest, HmacSha384Success) {
@@ -1540,8 +1355,6 @@
     string signature;
     MacMessage(message, &signature, 384);
     VerifyMac(message, signature);
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(VerificationOperationsTest, HmacSha512Success) {
@@ -1553,8 +1366,6 @@
     string signature;
     MacMessage(message, &signature, 512);
     VerifyMac(message, signature);
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 typedef Keymaster2Test ExportKeyTest;
@@ -1570,9 +1381,6 @@
     EXPECT_GT(export_data.length(), 0U);
 
     // TODO(swillden): Verify that the exported key is actually usable to verify signatures.
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(2, GetParam()->keymaster0_calls());
 }
 
 TEST_P(ExportKeyTest, EcdsaSuccess) {
@@ -1583,9 +1391,6 @@
     EXPECT_GT(export_data.length(), 0U);
 
     // TODO(swillden): Verify that the exported key is actually usable to verify signatures.
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
-        EXPECT_EQ(2, GetParam()->keymaster0_calls());
 }
 
 TEST_P(ExportKeyTest, RsaUnsupportedKeyFormat) {
@@ -1595,9 +1400,6 @@
                                            .Padding(KM_PAD_NONE)));
     string export_data;
     ASSERT_EQ(KM_ERROR_UNSUPPORTED_KEY_FORMAT, ExportKey(KM_KEY_FORMAT_PKCS8, &export_data));
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(2, GetParam()->keymaster0_calls());
 }
 
 TEST_P(ExportKeyTest, RsaCorruptedKeyBlob) {
@@ -1608,9 +1410,6 @@
     corrupt_key_blob();
     string export_data;
     ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, ExportKey(KM_KEY_FORMAT_X509, &export_data));
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(2, GetParam()->keymaster0_calls());
 }
 
 TEST_P(ExportKeyTest, AesKeyExportFails) {
@@ -1620,22 +1419,13 @@
     EXPECT_EQ(KM_ERROR_UNSUPPORTED_KEY_FORMAT, ExportKey(KM_KEY_FORMAT_X509, &export_data));
     EXPECT_EQ(KM_ERROR_UNSUPPORTED_KEY_FORMAT, ExportKey(KM_KEY_FORMAT_PKCS8, &export_data));
     EXPECT_EQ(KM_ERROR_UNSUPPORTED_KEY_FORMAT, ExportKey(KM_KEY_FORMAT_RAW, &export_data));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
-}
-
-static string read_file(const string& file_name) {
-    ifstream file_stream(file_name, std::ios::binary);
-    istreambuf_iterator<char> file_begin(file_stream);
-    istreambuf_iterator<char> file_end;
-    return string(file_begin, file_end);
 }
 
 typedef Keymaster2Test ImportKeyTest;
 INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, ImportKeyTest, test_params);
 
 TEST_P(ImportKeyTest, RsaSuccess) {
-    string pk8_key = read_file("rsa_privkey_pk8.der");
+    string pk8_key(reinterpret_cast<char*>(&rsa_privkey_pk8_der[0]), rsa_privkey_pk8_der_len);
     ASSERT_EQ(633U, pk8_key.size());
 
     ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder()
@@ -1645,34 +1435,22 @@
                                      KM_KEY_FORMAT_PKCS8, pk8_key));
 
     // Check values derived from the key.
-    EXPECT_TRUE(contains(GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA) ? hw_enforced()
-                                                                                 : sw_enforced(),
-                         TAG_ALGORITHM, KM_ALGORITHM_RSA));
-    EXPECT_TRUE(contains(GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA) ? hw_enforced()
-                                                                                 : sw_enforced(),
-                         TAG_KEY_SIZE, 1024));
-    EXPECT_TRUE(contains(GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA) ? hw_enforced()
-                                                                                 : sw_enforced(),
-                         TAG_RSA_PUBLIC_EXPONENT, 65537U));
+    EXPECT_TRUE(contains(sw_enforced(), TAG_ALGORITHM, KM_ALGORITHM_RSA));
+    EXPECT_TRUE(contains(sw_enforced(), TAG_KEY_SIZE, 1024));
+    EXPECT_TRUE(contains(sw_enforced(), TAG_RSA_PUBLIC_EXPONENT, 65537U));
 
     // And values provided by AndroidKeymaster
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_TRUE(contains(hw_enforced(), TAG_ORIGIN, KM_ORIGIN_UNKNOWN));
-    else
-        EXPECT_TRUE(contains(sw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED));
+    EXPECT_TRUE(contains(sw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED));
     EXPECT_TRUE(contains(sw_enforced(), KM_TAG_CREATION_DATETIME));
 
     string message(1024 / 8, 'a');
     string signature;
     SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
     VerifyMessage(message, signature, KM_DIGEST_NONE, KM_PAD_NONE);
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(4, GetParam()->keymaster0_calls());
 }
 
 TEST_P(ImportKeyTest, RsaKeySizeMismatch) {
-    string pk8_key = read_file("rsa_privkey_pk8.der");
+    string pk8_key(reinterpret_cast<char*>(&rsa_privkey_pk8_der[0]), rsa_privkey_pk8_der_len);
     ASSERT_EQ(633U, pk8_key.size());
     ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH,
               ImportKey(AuthorizationSetBuilder()
@@ -1680,12 +1458,10 @@
                             .Digest(KM_DIGEST_NONE)
                             .Padding(KM_PAD_NONE),
                         KM_KEY_FORMAT_PKCS8, pk8_key));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(ImportKeyTest, RsaPublicExponenMismatch) {
-    string pk8_key = read_file("rsa_privkey_pk8.der");
+    string pk8_key(reinterpret_cast<char*>(&rsa_privkey_pk8_der[0]), rsa_privkey_pk8_der_len);
     ASSERT_EQ(633U, pk8_key.size());
     ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH,
               ImportKey(AuthorizationSetBuilder()
@@ -1693,12 +1469,10 @@
                             .Digest(KM_DIGEST_NONE)
                             .Padding(KM_PAD_NONE),
                         KM_KEY_FORMAT_PKCS8, pk8_key));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(ImportKeyTest, EcdsaSuccess) {
-    string pk8_key = read_file("ec_privkey_pk8.der");
+    string pk8_key(reinterpret_cast<char*>(&ec_privkey_pk8_der[0]), ec_privkey_pk8_der_len);
     ASSERT_EQ(138U, pk8_key.size());
 
     ASSERT_EQ(KM_ERROR_OK,
@@ -1706,31 +1480,21 @@
                         KM_KEY_FORMAT_PKCS8, pk8_key));
 
     // Check values derived from the key.
-    EXPECT_TRUE(contains(GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC) ? hw_enforced()
-                                                                                : sw_enforced(),
-                         TAG_ALGORITHM, KM_ALGORITHM_EC));
-    EXPECT_TRUE(contains(GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC) ? hw_enforced()
-                                                                                : sw_enforced(),
-                         TAG_KEY_SIZE, 256));
+    EXPECT_TRUE(contains(sw_enforced(), TAG_ALGORITHM, KM_ALGORITHM_EC));
+    EXPECT_TRUE(contains(sw_enforced(), TAG_KEY_SIZE, 256));
 
     // And values provided by AndroidKeymaster
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
-        EXPECT_TRUE(contains(hw_enforced(), TAG_ORIGIN, KM_ORIGIN_UNKNOWN));
-    else
-        EXPECT_TRUE(contains(sw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED));
+    EXPECT_TRUE(contains(sw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED));
     EXPECT_TRUE(contains(sw_enforced(), KM_TAG_CREATION_DATETIME));
 
     string message(32, 'a');
     string signature;
     SignMessage(message, &signature, KM_DIGEST_NONE);
     VerifyMessage(message, signature, KM_DIGEST_NONE);
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
-        EXPECT_EQ(4, GetParam()->keymaster0_calls());
 }
 
 TEST_P(ImportKeyTest, EcdsaSizeSpecified) {
-    string pk8_key = read_file("ec_privkey_pk8.der");
+    string pk8_key(reinterpret_cast<char*>(&ec_privkey_pk8_der[0]), ec_privkey_pk8_der_len);
     ASSERT_EQ(138U, pk8_key.size());
 
     ASSERT_EQ(KM_ERROR_OK,
@@ -1738,39 +1502,27 @@
                         KM_KEY_FORMAT_PKCS8, pk8_key));
 
     // Check values derived from the key.
-    EXPECT_TRUE(contains(GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC) ? hw_enforced()
-                                                                                : sw_enforced(),
-                         TAG_ALGORITHM, KM_ALGORITHM_EC));
-    EXPECT_TRUE(contains(GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC) ? hw_enforced()
-                                                                                : sw_enforced(),
-                         TAG_KEY_SIZE, 256));
+    EXPECT_TRUE(contains(sw_enforced(), TAG_ALGORITHM, KM_ALGORITHM_EC));
+    EXPECT_TRUE(contains(sw_enforced(), TAG_KEY_SIZE, 256));
 
     // And values provided by AndroidKeymaster
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
-        EXPECT_TRUE(contains(hw_enforced(), TAG_ORIGIN, KM_ORIGIN_UNKNOWN));
-    else
-        EXPECT_TRUE(contains(sw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED));
+    EXPECT_TRUE(contains(sw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED));
     EXPECT_TRUE(contains(sw_enforced(), KM_TAG_CREATION_DATETIME));
 
     string message(32, 'a');
     string signature;
     SignMessage(message, &signature, KM_DIGEST_NONE);
     VerifyMessage(message, signature, KM_DIGEST_NONE);
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
-        EXPECT_EQ(4, GetParam()->keymaster0_calls());
 }
 
 TEST_P(ImportKeyTest, EcdsaSizeMismatch) {
-    string pk8_key = read_file("ec_privkey_pk8.der");
+    string pk8_key(reinterpret_cast<char*>(&ec_privkey_pk8_der[0]), ec_privkey_pk8_der_len);
     ASSERT_EQ(138U, pk8_key.size());
     ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH,
               ImportKey(AuthorizationSetBuilder()
                             .EcdsaSigningKey(224 /* Doesn't match key */)
                             .Digest(KM_DIGEST_NONE),
                         KM_KEY_FORMAT_PKCS8, pk8_key));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(ImportKeyTest, AesKeySuccess) {
@@ -1788,8 +1540,6 @@
     string ciphertext = EncryptMessage(message, KM_MODE_ECB, KM_PAD_PKCS7);
     string plaintext = DecryptMessage(ciphertext, KM_MODE_ECB, KM_PAD_PKCS7);
     EXPECT_EQ(message, plaintext);
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(ImportKeyTest, HmacSha256KeySuccess) {
@@ -1808,31 +1558,31 @@
     string signature;
     MacMessage(message, &signature, 256);
     VerifyMac(message, signature);
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
-string wrapped_key = hex2str(
-    "3082017302010004820100A2B7988012A043CE83E762A4E4D3C86D578B2E1EA5E04138353114A816951308E3222AFA"
-    "D86CA141C581198E65BC56D9EEDC5B555713BE2C20948DD076AB4980305871317F89DD3A7A67FBBB7AACF6941C06B2"
-    "65396D894A6DCC7B9FB152FFA8CBF44FF8063748795F3FB506DF8718535289E759075A13A5DDC83EF8470549AA7794"
-    "3AFBACF6CF82DCE3751E05BFE05F30B998D73E23611E6EAEFC2A497E097A895C4242607B472AE8F19DA77A9A5A4786"
-    "75541FC813C9213B5CE8C2E598BFBBCD1B369E3D7AEC0274F9B79118D8AA5FBB7634EBD3C4C2AF3B5DA483DF2CFDF1"
-    "E68A3BFC7B6C0D503AF88E82C9EE841A278B144FF8D39F2DB2ACE9415C120190040CD796B02C370F1FA4CC0124F130"
-    "280201033023A1083106020100020101A203020120A30402020100A4053103020101A60531030201400420CCD54085"
-    "5F833A5E1480BFD2D36FAF3AEEE15DF5BEABE2691BC82DDE2A7AA91004107CB81BDDCD09E8F4DF575726279F3229");
+auto wrapped_key = hex2str(
+    "3082017902010004820100934bf94e2aa28a3f83c9f79297250262fbe3276b5a1c91159bbfa3ef8957aac84b59b30b"
+    "455a79c2973480823d8b3863c3deef4a8e243590268d80e18751a0e130f67ce6a1ace9f79b95e097474febc981195b"
+    "1d13a69086c0863f66a7b7fdb48792227b1ac5e2489febdf087ab5486483033a6f001ca5d1ec1e27f5c30f4cec2642"
+    "074a39ae68aee552e196627a8e3d867e67a8c01b11e75f13cca0a97ab668b50cda07a8ecb7cd8e3dd7009c9636534f"
+    "6f239cffe1fc8daa466f78b676c7119efb96bce4e69ca2a25d0b34ed9c3ff999b801597d5220e307eaa5bee507fb94"
+    "d1fa69f9e519b2de315bac92c36f2ea1fa1df4478c0ddedeae8c70e0233cd098040cd796b02c370f1fa4cc0124f130"
+    "2e0201033029a1083106020100020101a203020120a30402020100a4053103020101a6053103020140bf8377020500"
+    "0420ccd540855f833a5e1480bfd2d36faf3aeee15df5beabe2691bc82dde2a7aa910041064c9f689c60ff6223ab6e6"
+    "999e0eb6e5");
 
-string wrapped_key_masked = hex2str(
-    "30820173020100048201008CBEE0DC600215FFC85FC26B57DD2331DDF5D3E106C0A68BFEF167AFD428041D9B7C3316"
-    "110BBB914A86FC24D4EF5C6A4673C9B3CC914C7806453650753B5130C4FE72264A52C1A270286032513F24EB3E033A"
-    "BCC26A9D6AEFD0D0AD3E922E4E737ECDAD3C4DF2ABDB416378E67381BE0391175EC8F05FDFBC3794B7D0D88298010F"
-    "E9B6F788BC049D874575D2D4C33DB582B113694738A9151BBC7603D3556B26FEC0279EE1C1CA44D6F7F91F4C424912"
-    "7F9CC3232DE8B0AEFFD5AFAD4C3D5B846FD26873315606F6457BC19447FD7C6431550D6E6592A0555E61C7A021D149"
-    "BCEE7A858DD6D4A8E230C6015EEDF0A58F4CAA8A6D0E3A1E3794CAEE7854CE92040C6D9721D08589581AB49204A330"
-    "280201033023A1083106020100020101A203020120A30402020100A4053103020101A60531030201400420A61C6E24"
-    "7E25B3E6E69AA78EB03C2D4AC20D1F99A9A024A76F35C8E2CAB9B68D04101FF7A0E793B9EE4AECEBB9AC4C545254");
+auto wrapped_key_masked = hex2str(
+    "3082017902010004820100aad93ed5924f283b4bb5526fbe7a1412f9d9749ec30db9062b29e574a8546f33c8873245"
+    "2f5b8e6a391ee76c39ed1712c61d8df6213dec1cffbc17a8c6d04c7b30893d8daa9b2015213e21946821553207f8f9"
+    "931c4caba23ed3bee28b36947e47f10e0a5c3dc51c988a628daad3e5e1f4005e79c2d5a96c284b4b8d7e4948f331e5"
+    "b85dd5a236f85579f3ea1d1b848487470bdb0ab4f81a12bee42c99fe0df4bee3759453e69ad1d68a809ce06b949f76"
+    "94a990429b2fe81e066ff43e56a21602db70757922a4bcc23ab89f1e35da77586775f423e519c2ea394caf48a28d0c"
+    "8020f1dcf6b3a68ec246f615ae96dae9a079b1f6eb959033c1af5c125fd94168040c6d9721d08589581ab49204a330"
+    "2e0201033029a1083106020100020101a203020120a30402020100a4053103020101a6053103020140bf8377020500"
+    "0420a61c6e247e25b3e6e69aa78eb03c2d4ac20d1f99a9a024a76f35c8e2cab9b68d04102560c70109ae67c030f00b"
+    "98b512a670");
 
-string wrapping_key = hex2str(
+auto wrapping_key = hex2str(
     "308204be020100300d06092a864886f70d0101010500048204a8308204a40201000282010100aec367931d8900ce56"
     "b0067f7d70e1fc653f3f34d194c1fed50018fb43db937b06e673a837313d56b1c725150a3fef86acbddc41bb759c28"
     "54eae32d35841efb5c18d82bc90a1cb5c1d55adf245b02911f0b7cda88c421ff0ebafe7c0d23be312d7bd5921ffaea"
@@ -1866,26 +1616,26 @@
 
 class ImportWrappedKeyTest : public testing::Test {
   public:
-    ImportWrappedKeyTest() : keymaster_(new PureSoftKeymasterContext(), 16) {}
+    ImportWrappedKeyTest() : keymaster_(new PureSoftKeymasterContext(kCurrentKmVersion), 16) {}
 
   protected:
     void SetUp() override {
-        ConfigureRequest configReq;
+        ConfigureRequest configReq(kMaxMessageVersion);
         configReq.os_version = kOsVersion;
         configReq.os_patchlevel = kOsPatchLevel;
-        ConfigureResponse configRsp;
+        ConfigureResponse configRsp(kMaxMessageVersion);
         keymaster_.Configure(configReq, &configRsp);
         EXPECT_EQ(KM_ERROR_OK, configRsp.error);
     }
 
     keymaster_error_t BeginOperation(keymaster_purpose_t purpose,
                                      const AuthorizationSet& input_set) {
-        BeginOperationRequest req;
+        BeginOperationRequest req(kMaxMessageVersion);
         req.purpose = purpose;
         req.SetKeyMaterial(blob_);
         req.additional_params = input_set;
 
-        BeginOperationResponse rsp;
+        BeginOperationResponse rsp(kMaxMessageVersion);
         keymaster_.BeginOperation(req, &rsp);
         op_handle_ = rsp.op_handle;
 
@@ -1893,11 +1643,11 @@
     }
 
     keymaster_error_t FinishOperation(const string& input, string* output) {
-        FinishOperationRequest req;
+        FinishOperationRequest req(kMaxMessageVersion);
         req.op_handle = op_handle_;
         req.input.Reinitialize(input.data(), input.size());
 
-        FinishOperationResponse rsp;
+        FinishOperationResponse rsp(kMaxMessageVersion);
         keymaster_.FinishOperation(req, &rsp);
 
         if (output) {
@@ -1923,29 +1673,29 @@
 };
 
 TEST_F(ImportWrappedKeyTest, GoldenKeySuccess) {
-    ImportKeyRequest import_request;
+    ImportKeyRequest import_request(kMaxMessageVersion);
 
     auto import_params = AuthorizationSetBuilder()
                              .RsaEncryptionKey(2048, 65537)
-                             .Digest(KM_DIGEST_SHA1)
+                             .Digest(KM_DIGEST_SHA_2_256)
                              .Padding(KM_PAD_RSA_OAEP)
                              .Authorization(TAG_PURPOSE, KM_PURPOSE_WRAP)
                              .build();
     import_request.key_description.Reinitialize(import_params);
-    import_request.SetKeyMaterial(reinterpret_cast<const uint8_t*>(wrapping_key.c_str()),
-                                  wrapping_key.size());
+    import_request.key_data = KeymasterKeyBlob(
+        reinterpret_cast<const uint8_t*>(wrapping_key.c_str()), wrapping_key.size());
     import_request.key_format = KM_KEY_FORMAT_PKCS8;
-    ImportKeyResponse import_response;
+    ImportKeyResponse import_response(kMaxMessageVersion);
     keymaster_.ImportKey(import_request, &import_response);
     ASSERT_EQ(import_response.error, KM_ERROR_OK);
 
-    ImportWrappedKeyRequest request;
+    ImportWrappedKeyRequest request(kMaxMessageVersion);
     KeymasterKeyBlob wrapped_key_blob(reinterpret_cast<const uint8_t*>(wrapped_key.c_str()),
                                       wrapped_key.size());
     request.SetKeyMaterial(wrapped_key_blob, import_response.key_blob);
     request.SetMaskingKeyMaterial(reinterpret_cast<const uint8_t*>(zero_masking_key.c_str()),
                                   zero_masking_key.size());
-    ImportWrappedKeyResponse response;
+    ImportWrappedKeyResponse response(kMaxMessageVersion);
 
     keymaster_.ImportWrappedKey(request, &response);
 
@@ -1968,71 +1718,71 @@
 }
 
 TEST_F(ImportWrappedKeyTest, SuccessMaskingKey) {
-    ImportKeyRequest import_request;
+    ImportKeyRequest import_request(kMaxMessageVersion);
 
     auto import_params = AuthorizationSetBuilder()
                              .RsaEncryptionKey(2048, 65537)
-                             .Digest(KM_DIGEST_SHA1)
+                             .Digest(KM_DIGEST_SHA_2_256)
                              .Padding(KM_PAD_RSA_OAEP)
                              .Authorization(TAG_PURPOSE, KM_PURPOSE_WRAP)
                              .build();
     import_request.key_description.Reinitialize(import_params);
-    import_request.SetKeyMaterial(reinterpret_cast<const uint8_t*>(wrapping_key.c_str()),
-                                  wrapping_key.size());
+    import_request.key_data = KeymasterKeyBlob(
+        reinterpret_cast<const uint8_t*>(wrapping_key.c_str()), wrapping_key.size());
 
     import_request.key_format = KM_KEY_FORMAT_PKCS8;
-    ImportKeyResponse import_response;
+    ImportKeyResponse import_response(kMaxMessageVersion);
     keymaster_.ImportKey(import_request, &import_response);
     EXPECT_EQ(import_response.error, KM_ERROR_OK);
 
     if (import_response.error != KM_ERROR_OK) return;
 
-    ImportWrappedKeyRequest request;
+    ImportWrappedKeyRequest request(kMaxMessageVersion);
     KeymasterKeyBlob wrapped_key_blob(reinterpret_cast<const uint8_t*>(wrapped_key_masked.c_str()),
                                       wrapped_key_masked.size());
     request.SetKeyMaterial(wrapped_key_blob, import_response.key_blob);
     request.SetMaskingKeyMaterial(reinterpret_cast<const uint8_t*>(masking_key.c_str()),
                                   masking_key.size());
-    ImportWrappedKeyResponse response;
+    ImportWrappedKeyResponse response(kMaxMessageVersion);
 
     keymaster_.ImportWrappedKey(request, &response);
     EXPECT_EQ(response.error, KM_ERROR_OK);
 }
 
 TEST_F(ImportWrappedKeyTest, WrongMaskingKey) {
-    ImportKeyRequest import_request;
+    ImportKeyRequest import_request(kMaxMessageVersion);
 
     auto import_params = AuthorizationSetBuilder()
                              .RsaEncryptionKey(2048, 65537)
-                             .Digest(KM_DIGEST_SHA1)
+                             .Digest(KM_DIGEST_SHA_2_256)
                              .Padding(KM_PAD_RSA_OAEP)
                              .Authorization(TAG_PURPOSE, KM_PURPOSE_WRAP)
                              .build();
     import_request.key_description.Reinitialize(import_params);
-    import_request.SetKeyMaterial(reinterpret_cast<const uint8_t*>(wrapping_key.c_str()),
-                                  wrapping_key.size());
+    import_request.key_data = KeymasterKeyBlob(
+        reinterpret_cast<const uint8_t*>(wrapping_key.c_str()), wrapping_key.size());
 
     import_request.key_format = KM_KEY_FORMAT_PKCS8;
-    ImportKeyResponse import_response;
+    ImportKeyResponse import_response(kMaxMessageVersion);
     keymaster_.ImportKey(import_request, &import_response);
     EXPECT_EQ(import_response.error, KM_ERROR_OK);
 
     if (import_response.error != KM_ERROR_OK) return;
 
-    ImportWrappedKeyRequest request;
+    ImportWrappedKeyRequest request(kMaxMessageVersion);
     KeymasterKeyBlob wrapped_key_blob(reinterpret_cast<const uint8_t*>(wrapped_key_masked.c_str()),
                                       wrapped_key_masked.size());
     request.SetKeyMaterial(wrapped_key_blob, import_response.key_blob);
     request.SetMaskingKeyMaterial(reinterpret_cast<const uint8_t*>(zero_masking_key.c_str()),
                                   zero_masking_key.size());
-    ImportWrappedKeyResponse response;
+    ImportWrappedKeyResponse response(kMaxMessageVersion);
 
     keymaster_.ImportWrappedKey(request, &response);
     EXPECT_EQ(response.error, KM_ERROR_VERIFICATION_FAILED);
 }
 
 TEST_F(ImportWrappedKeyTest, WrongPurpose) {
-    ImportKeyRequest import_request;
+    ImportKeyRequest import_request(kMaxMessageVersion);
 
     auto import_params = AuthorizationSetBuilder()
                              .RsaEncryptionKey(2048, 65537)
@@ -2040,20 +1790,20 @@
                              .Padding(KM_PAD_RSA_OAEP)
                              .build();
     import_request.key_description.Reinitialize(import_params);
-    import_request.SetKeyMaterial(reinterpret_cast<const uint8_t*>(wrapping_key.c_str()),
-                                  wrapping_key.size());
+    import_request.key_data = KeymasterKeyBlob(
+        reinterpret_cast<const uint8_t*>(wrapping_key.c_str()), wrapping_key.size());
     import_request.key_format = KM_KEY_FORMAT_PKCS8;
-    ImportKeyResponse import_response;
+    ImportKeyResponse import_response(kMaxMessageVersion);
     keymaster_.ImportKey(import_request, &import_response);
     EXPECT_EQ(import_response.error, KM_ERROR_OK);
 
     if (import_response.error != KM_ERROR_OK) return;
 
-    ImportWrappedKeyRequest request;
+    ImportWrappedKeyRequest request(kMaxMessageVersion);
     KeymasterKeyBlob wrapped_key_blob(reinterpret_cast<const uint8_t*>(wrapped_key.c_str()),
                                       wrapped_key.size());
     request.SetKeyMaterial(wrapped_key_blob, import_response.key_blob);
-    ImportWrappedKeyResponse response;
+    ImportWrappedKeyResponse response(kMaxMessageVersion);
 
     keymaster_.ImportWrappedKey(request, &response);
     EXPECT_EQ(response.error, KM_ERROR_INCOMPATIBLE_PURPOSE);
@@ -2075,9 +1825,6 @@
 
     // Unpadded RSA is deterministic
     EXPECT_EQ(ciphertext1, ciphertext2);
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(3, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, RsaNoPaddingTooShort) {
@@ -2093,9 +1840,6 @@
     string plaintext = DecryptMessage(ciphertext, KM_PAD_NONE);
 
     EXPECT_EQ(expected_plaintext, plaintext);
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(4, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, RsaNoPaddingTooLong) {
@@ -2111,9 +1855,6 @@
     string result;
     size_t input_consumed;
     EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, UpdateOperation(message, &result, &input_consumed));
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(2, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, RsaNoPaddingLargerThanModulus) {
@@ -2153,9 +1894,6 @@
     message = string(reinterpret_cast<const char*>(modulus_buf.get()), modulus_len);
     EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
     EXPECT_EQ(KM_ERROR_OK, FinishOperation(message, "", &result));
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(4, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, RsaOaepSuccess) {
@@ -2174,9 +1912,48 @@
 
     // OAEP randomizes padding so every result should be different.
     EXPECT_NE(ciphertext1, ciphertext2);
+}
 
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(3, GetParam()->keymaster0_calls());
+TEST_P(EncryptionOperationsTest, RsaOaepWithMgf224Success) {
+    size_t key_size = 768;
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaEncryptionKey(key_size, 3)
+                                           .Padding(KM_PAD_RSA_OAEP)
+                                           .Digest(KM_DIGEST_SHA_2_256)
+                                           .OaepMgfDigest(KM_DIGEST_SHA_2_224)));
+
+    string message = "Hello";
+    string ciphertext1 =
+        EncryptMessage(string(message), KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_224, KM_PAD_RSA_OAEP);
+    EXPECT_EQ(key_size / 8, ciphertext1.size());
+
+    string ciphertext2 =
+        EncryptMessage(string(message), KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_224, KM_PAD_RSA_OAEP);
+    EXPECT_EQ(key_size / 8, ciphertext2.size());
+
+    // OAEP randomizes padding so every result should be different.
+    EXPECT_NE(ciphertext1, ciphertext2);
+}
+
+TEST_P(EncryptionOperationsTest, RsaOaepWithMgfMD5Success) {
+    size_t key_size = 768;
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaEncryptionKey(key_size, 3)
+                                           .Padding(KM_PAD_RSA_OAEP)
+                                           .Digest(KM_DIGEST_SHA_2_256)
+                                           .OaepMgfDigest(KM_DIGEST_MD5)));
+
+    string message = "Hello";
+    string ciphertext1 =
+        EncryptMessage(string(message), KM_DIGEST_SHA_2_256, KM_DIGEST_MD5, KM_PAD_RSA_OAEP);
+    EXPECT_EQ(key_size / 8, ciphertext1.size());
+
+    string ciphertext2 =
+        EncryptMessage(string(message), KM_DIGEST_SHA_2_256, KM_DIGEST_MD5, KM_PAD_RSA_OAEP);
+    EXPECT_EQ(key_size / 8, ciphertext2.size());
+
+    // OAEP randomizes padding so every result should be different.
+    EXPECT_NE(ciphertext1, ciphertext2);
 }
 
 TEST_P(EncryptionOperationsTest, RsaOaepSha224Success) {
@@ -2195,9 +1972,6 @@
 
     // OAEP randomizes padding so every result should be different.
     EXPECT_NE(ciphertext1, ciphertext2);
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(3, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, RsaOaepRoundTrip) {
@@ -2212,9 +1986,23 @@
 
     string plaintext = DecryptMessage(ciphertext, KM_DIGEST_SHA_2_256, KM_PAD_RSA_OAEP);
     EXPECT_EQ(message, plaintext);
+}
 
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(4, GetParam()->keymaster0_calls());
+TEST_P(EncryptionOperationsTest, RsaOaepWithMgfSha256RoundTrip) {
+    size_t key_size = 768;
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaEncryptionKey(key_size, 3)
+                                           .Padding(KM_PAD_RSA_OAEP)
+                                           .Digest(KM_DIGEST_SHA_2_256)
+                                           .OaepMgfDigest(KM_DIGEST_SHA_2_256)));
+    string message = "Hello World!";
+    string ciphertext =
+        EncryptMessage(string(message), KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_256, KM_PAD_RSA_OAEP);
+    EXPECT_EQ(key_size / 8, ciphertext.size());
+
+    string plaintext =
+        DecryptMessage(ciphertext, KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_256, KM_PAD_RSA_OAEP);
+    EXPECT_EQ(message, plaintext);
 }
 
 TEST_P(EncryptionOperationsTest, RsaOaepSha224RoundTrip) {
@@ -2229,9 +2017,6 @@
 
     string plaintext = DecryptMessage(ciphertext, KM_DIGEST_SHA_2_224, KM_PAD_RSA_OAEP);
     EXPECT_EQ(message, plaintext);
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(4, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, RsaOaepInvalidDigest) {
@@ -2245,9 +2030,21 @@
     begin_params.push_back(TAG_PADDING, KM_PAD_RSA_OAEP);
     begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
     EXPECT_EQ(KM_ERROR_INCOMPATIBLE_DIGEST, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+}
 
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(2, GetParam()->keymaster0_calls());
+TEST_P(EncryptionOperationsTest, RsaOaepWithMgfInvalidDigest) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .RsaEncryptionKey(512, 3)
+                                           .Padding(KM_PAD_RSA_OAEP)
+                                           .Digest(KM_DIGEST_SHA_2_256)
+                                           .OaepMgfDigest(KM_DIGEST_SHA_2_256)));
+    string message = "Hello World!";
+
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_PADDING, KM_PAD_RSA_OAEP);
+    begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
+    begin_params.push_back(TAG_RSA_OAEP_MGF_DIGEST, KM_DIGEST_SHA_2_224);
+    EXPECT_EQ(KM_ERROR_INCOMPATIBLE_MGF_DIGEST, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
 }
 
 TEST_P(EncryptionOperationsTest, RsaOaepUnauthorizedDigest) {
@@ -2267,9 +2064,6 @@
     begin_params.push_back(TAG_PADDING, KM_PAD_RSA_OAEP);
     begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA1);
     EXPECT_EQ(KM_ERROR_INCOMPATIBLE_DIGEST, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(3, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, RsaOaepDecryptWithWrongDigest) {
@@ -2295,9 +2089,6 @@
     EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext, &result, &input_consumed));
     EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, FinishOperation(&result));
     EXPECT_EQ(0U, result.size());
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(4, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, RsaOaepTooLarge) {
@@ -2316,9 +2107,6 @@
     EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
     EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(&result));
     EXPECT_EQ(0U, result.size());
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(2, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, RsaOaepCorruptedDecrypt) {
@@ -2343,9 +2131,6 @@
     EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext, &result, &input_consumed));
     EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, FinishOperation(&result));
     EXPECT_EQ(0U, result.size());
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(4, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, RsaPkcs1Success) {
@@ -2360,9 +2145,6 @@
 
     // PKCS1 v1.5 randomizes padding so every result should be different.
     EXPECT_NE(ciphertext1, ciphertext2);
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(3, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, RsaPkcs1RoundTrip) {
@@ -2374,9 +2156,6 @@
 
     string plaintext = DecryptMessage(ciphertext, KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
     EXPECT_EQ(message, plaintext);
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(4, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, RsaRoundTripAllCombinations) {
@@ -2413,9 +2192,6 @@
             string plaintext = DecryptMessage(ciphertext, digest, padding);
             EXPECT_EQ(message, plaintext);
         }
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(40, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, RsaPkcs1TooLarge) {
@@ -2431,9 +2207,6 @@
     EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
     EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(&result));
     EXPECT_EQ(0U, result.size());
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(2, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, RsaPkcs1CorruptedDecrypt) {
@@ -2454,9 +2227,6 @@
     EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext, &result, &input_consumed));
     EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, FinishOperation(&result));
     EXPECT_EQ(0U, result.size());
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(4, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, RsaEncryptWithSigningKey) {
@@ -2466,9 +2236,6 @@
     AuthorizationSet begin_params(client_params());
     begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
     ASSERT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(2, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, EcdsaEncrypt) {
@@ -2476,9 +2243,6 @@
               GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest(KM_DIGEST_NONE)));
     ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, BeginOperation(KM_PURPOSE_ENCRYPT));
     ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, BeginOperation(KM_PURPOSE_DECRYPT));
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
-        EXPECT_EQ(3, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, HmacEncrypt) {
@@ -2489,8 +2253,6 @@
                                            .Authorization(TAG_MIN_MAC_LENGTH, 128)));
     ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, BeginOperation(KM_PURPOSE_ENCRYPT));
     ASSERT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE, BeginOperation(KM_PURPOSE_DECRYPT));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, AesEcbRoundTripSuccess) {
@@ -2511,8 +2273,6 @@
 
     string plaintext = DecryptMessage(ciphertext1, KM_MODE_ECB, KM_PAD_NONE);
     EXPECT_EQ(message, plaintext);
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, AesEcbNotAuthorized) {
@@ -2526,8 +2286,6 @@
     begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB);
     begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
     EXPECT_EQ(KM_ERROR_INCOMPATIBLE_BLOCK_MODE, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, AesEcbNoPaddingWrongInputSize) {
@@ -2544,8 +2302,6 @@
     EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
     string ciphertext;
     EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(message, "", &ciphertext));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, AesEcbPkcs7Padding) {
@@ -2562,8 +2318,6 @@
         string plaintext = DecryptMessage(ciphertext, KM_MODE_ECB, KM_PAD_PKCS7);
         EXPECT_EQ(message, plaintext);
     }
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, AesEcbNoPaddingKeyWithPkcs7Padding) {
@@ -2580,8 +2334,6 @@
         EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PADDING_MODE,
                   BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
     }
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, AesEcbPkcs7PaddingCorrupted) {
@@ -2605,8 +2357,6 @@
     EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext, &plaintext, &input_consumed));
     EXPECT_EQ(ciphertext.size(), input_consumed);
     EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, FinishOperation(&plaintext));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, AesCtrRoundTripSuccess) {
@@ -2631,8 +2381,6 @@
 
     string plaintext = DecryptMessage(ciphertext1, KM_MODE_CTR, KM_PAD_NONE, iv1);
     EXPECT_EQ(message, plaintext);
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, AesCtrIncremental) {
@@ -2672,8 +2420,6 @@
     EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext));
     EXPECT_EQ(ciphertext.size(), plaintext.size());
     EXPECT_EQ(message, plaintext);
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 struct AesCtrSp80038aTestVector {
@@ -2688,7 +2434,8 @@
 static const AesCtrSp80038aTestVector kAesCtrSp80038aTestVectors[] = {
     // AES-128
     {
-        "2b7e151628aed2a6abf7158809cf4f3c", "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+        "2b7e151628aed2a6abf7158809cf4f3c",
+        "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
         "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
         "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
         "874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff"
@@ -2696,7 +2443,8 @@
     },
     // AES-192
     {
-        "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b", "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+        "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
+        "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
         "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
         "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
         "1abc932417521ca24f2b0459fe7e6e0b090339ec0aa6faefd5ccc2c6f4ce8e94"
@@ -2722,8 +2470,6 @@
         const string ciphertext = hex2str(test.ciphertext);
         CheckAesCtrTestVector(key, nonce, plaintext, ciphertext);
     }
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, AesCtrInvalidPaddingMode) {
@@ -2735,8 +2481,6 @@
     begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_CTR);
     begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
     EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PADDING_MODE, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, AesCtrInvalidCallerNonce) {
@@ -2751,8 +2495,6 @@
     input_params.push_back(TAG_PADDING, KM_PAD_NONE);
     input_params.push_back(TAG_NONCE, "123", 3);
     EXPECT_EQ(KM_ERROR_INVALID_NONCE, BeginOperation(KM_PURPOSE_ENCRYPT, input_params));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, AesCbcRoundTripSuccess) {
@@ -2776,8 +2518,6 @@
 
     string plaintext = DecryptMessage(ciphertext1, KM_MODE_CBC, KM_PAD_NONE, iv1);
     EXPECT_EQ(message, plaintext);
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, AesCallerNonce) {
@@ -2819,8 +2559,6 @@
     plaintext = ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext2, input_params, update_params,
                                &output_params);
     EXPECT_NE(message, plaintext);
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, AesCallerNonceProhibited) {
@@ -2849,8 +2587,6 @@
 
     EXPECT_EQ(KM_ERROR_CALLER_NONCE_PROHIBITED,
               BeginOperation(KM_PURPOSE_ENCRYPT, input_params, &output_params));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, AesCbcIncrementalNoPadding) {
@@ -2890,8 +2626,6 @@
     EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext));
     EXPECT_EQ(ciphertext.size(), plaintext.size());
     EXPECT_EQ(message, plaintext);
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, AesCbcPkcs7Padding) {
@@ -2909,8 +2643,6 @@
         string plaintext = DecryptMessage(ciphertext, KM_MODE_CBC, KM_PAD_PKCS7, iv);
         EXPECT_EQ(message, plaintext);
     }
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, AesGcmRoundTripSuccess) {
@@ -2953,7 +2685,6 @@
     EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext));
 
     EXPECT_EQ(message, plaintext);
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, AesGcmTooShortTag) {
@@ -2975,8 +2706,6 @@
     AuthorizationSet begin_out_params;
     EXPECT_EQ(KM_ERROR_INVALID_MAC_LENGTH,
               BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, AesGcmTooShortTagOnDecrypt) {
@@ -3016,8 +2745,6 @@
 
     // Decrypt.
     EXPECT_EQ(KM_ERROR_INVALID_MAC_LENGTH, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, AesGcmCorruptKey) {
@@ -3074,8 +2801,6 @@
     EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
     EXPECT_EQ(KM_ERROR_OK, UpdateOperation(ciphertext_str, &plaintext, &input_consumed));
     EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(&plaintext));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, AesGcmAadNoData) {
@@ -3118,7 +2843,6 @@
     EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext));
 
     EXPECT_EQ(empty_message, plaintext);
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, AesGcmIncremental) {
@@ -3187,8 +2911,6 @@
     }
     EXPECT_EQ(1000U, plaintext.size());
     EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, AesGcmMultiPartAad) {
@@ -3239,7 +2961,6 @@
     EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext));
 
     EXPECT_EQ(message, plaintext);
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, AesGcmBadAad) {
@@ -3285,8 +3006,6 @@
                                            &plaintext, &input_consumed));
     EXPECT_EQ(ciphertext.size(), input_consumed);
     EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(&plaintext));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, AesGcmWrongNonce) {
@@ -3327,7 +3046,6 @@
 
     // With wrong nonce, should have gotten garbage plaintext.
     EXPECT_NE(message, plaintext);
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, AesGcmCorruptTag) {
@@ -3373,7 +3091,6 @@
     EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(&plaintext));
 
     EXPECT_EQ(message, plaintext);
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, TripleDesEcbRoundTripSuccess) {
@@ -3668,8 +3385,6 @@
 
     string plaintext = DecryptMessage(ciphertext1, KM_MODE_CBC, KM_PAD_NONE, iv1);
     EXPECT_EQ(message, plaintext);
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(EncryptionOperationsTest, TripleDesCallerIv) {
@@ -3866,8 +3581,6 @@
     EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext));
     EXPECT_EQ(ciphertext.size(), plaintext.size());
     EXPECT_EQ(message, plaintext);
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 typedef Keymaster2Test MaxOperationsTest;
@@ -3890,8 +3603,6 @@
     begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB);
     begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
     EXPECT_EQ(KM_ERROR_KEY_MAX_OPS_EXCEEDED, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(MaxOperationsTest, TestAbort) {
@@ -3911,8 +3622,6 @@
     begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB);
     begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
     EXPECT_EQ(KM_ERROR_KEY_MAX_OPS_EXCEEDED, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 typedef Keymaster2Test AddEntropyTest;
@@ -3923,8 +3632,6 @@
     // doesn't blow up or return an error.
     EXPECT_EQ(KM_ERROR_OK,
               device()->add_rng_entropy(device(), reinterpret_cast<const uint8_t*>("foo"), 3));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 typedef Keymaster2Test AttestationTest;
@@ -3943,13 +3650,11 @@
         X509_Ptr key_cert(parse_cert_blob(key_cert_blob));
         X509_Ptr signing_cert(parse_cert_blob(signing_cert_blob));
         EXPECT_TRUE(!!key_cert.get() && !!signing_cert.get());
-        if (!key_cert.get() || !signing_cert.get())
-            return false;
+        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;
+        if (!signing_pubkey.get()) return false;
 
         EXPECT_EQ(1, X509_verify(key_cert.get(), signing_pubkey.get()))
             << "Verification of certificate " << i << " failed";
@@ -3960,21 +3665,18 @@
 
 // Extract attestation record from cert. Returned object is still part of cert; don't free it
 // separately.
-static ASN1_OCTET_STRING* get_attestation_record(X509* certificate) {
-    ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
+static ASN1_OCTET_STRING* get_attestation_record(X509* certificate, const char* oid_string) {
+    ASN1_OBJECT_Ptr oid(OBJ_txt2obj(oid_string, 1 /* dotted string format */));
     EXPECT_TRUE(!!oid.get());
-    if (!oid.get())
-        return nullptr;
+    if (!oid.get()) return nullptr;
 
     int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
     EXPECT_NE(-1, location);
-    if (location == -1)
-        return nullptr;
+    if (location == -1) return nullptr;
 
     X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
     EXPECT_TRUE(!!attest_rec_ext);
-    if (!attest_rec_ext)
-        return nullptr;
+    if (!attest_rec_ext) return nullptr;
 
     ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
     EXPECT_TRUE(!!attest_rec);
@@ -3990,13 +3692,15 @@
 
     X509_Ptr cert(parse_cert_blob(attestation_cert));
     EXPECT_TRUE(!!cert.get());
-    if (!cert.get())
-        return false;
+    if (!cert.get()) return false;
 
-    ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get());
+    const char* oid =
+        expected_keymaster_version >= (uint32_t)KmVersion::KEYMINT_1 ? kEatTokenOid : kAsn1TokenOid;
+    uint32_t expected_attestation_version =
+        expected_keymaster_version >= (uint32_t)KmVersion::KEYMINT_1 ? 5u : 4u;
+    ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get(), oid);
     EXPECT_TRUE(!!attest_rec);
-    if (!attest_rec)
-        return false;
+    if (!attest_rec) return false;
 
     AuthorizationSet att_sw_enforced;
     AuthorizationSet att_tee_enforced;
@@ -4006,13 +3710,27 @@
     keymaster_security_level_t att_keymaster_security_level;
     keymaster_blob_t att_challenge = {};
     keymaster_blob_t att_unique_id = {};
-    EXPECT_EQ(KM_ERROR_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));
+    keymaster_blob_t att_boot_key = {};
+    keymaster_verified_boot_t att_boot_state;
+    bool att_dev_locked;
+    std::vector<int64_t> unexpected_eat_claims;
+    if (expected_keymaster_version >= (uint32_t)KmVersion::KEYMINT_1) {
+        EXPECT_EQ(KM_ERROR_OK,
+                  parse_eat_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, &att_boot_key,
+                                   &att_boot_state, &att_dev_locked, &unexpected_eat_claims));
+    } else {
+        EXPECT_EQ(KM_ERROR_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_EQ(2U, att_attestation_version);
+    EXPECT_EQ(std::vector<int64_t>(), unexpected_eat_claims);
+    EXPECT_EQ(expected_attestation_version, att_attestation_version);
     EXPECT_EQ(KM_SECURITY_LEVEL_SOFTWARE, att_attestation_security_level);
     EXPECT_EQ(expected_keymaster_version, att_keymaster_version);
     EXPECT_EQ(expected_keymaster_security_level, att_keymaster_security_level);
@@ -4053,7 +3771,14 @@
     return true;
 }
 
-TEST_P(AttestationTest, RsaAttestation) {
+TEST_P(AttestationTest, RsaAttestationKeymaster) {
+    // We can't test KeyMint attestation here because these tests are architected to use the
+    // Keymaster2 API (an old-style C-struct HAL, pre-HIDL), which doesn't have a way to return the
+    // certificates.  For now, we'll have to rely on the KeyMint VTS tests to validate KeyMint
+    // attestation.
+    //
+    // TODO: Refactor this test suite to use the HIDL/AIDL interfaces.
+    if (GetParam()->is_keymint()) return;
     ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
                                            .RsaSigningKey(256, 3)
                                            .Digest(KM_DIGEST_NONE)
@@ -4068,13 +3793,8 @@
     uint32_t expected_keymaster_version;
     keymaster_security_level_t expected_keymaster_security_level;
     // TODO(swillden): Add a test KM1 that claims to be hardware.
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) {
-        expected_keymaster_version = 0;
-        expected_keymaster_security_level = KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
-    } else {
-        expected_keymaster_version = 3;
-        expected_keymaster_security_level = KM_SECURITY_LEVEL_SOFTWARE;
-    }
+    expected_keymaster_version = (uint32_t)GetParam()->km_version();
+    expected_keymaster_security_level = KM_SECURITY_LEVEL_SOFTWARE;
 
     EXPECT_TRUE(verify_attestation_record(
         "challenge", "attest_app_id", sw_enforced(), hw_enforced(), expected_keymaster_version,
@@ -4084,19 +3804,21 @@
 }
 
 TEST_P(AttestationTest, EcAttestation) {
+    // We can't test KeyMint attestation here because these tests are architected to use the
+    // Keymaster2 API (an old-style C-struct HAL, pre-HIDL), which doesn't have a way to return the
+    // certificates.  For now, we'll have to rely on the KeyMint VTS tests to validate KeyMint
+    // attestation.
+    //
+    // TODO: Refactor this test suite to use the HIDL/AIDL interfaces.
+    if (GetParam()->is_keymint()) return;
     ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(
                                KM_DIGEST_SHA_2_256)));
 
     uint32_t expected_keymaster_version;
     keymaster_security_level_t expected_keymaster_security_level;
     // TODO(swillden): Add a test KM1 that claims to be hardware.
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) {
-        expected_keymaster_version = 0;
-        expected_keymaster_security_level = KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
-    } else {
-        expected_keymaster_version = 3;
-        expected_keymaster_security_level = KM_SECURITY_LEVEL_SOFTWARE;
-    }
+    expected_keymaster_version = (uint32_t)GetParam()->km_version();
+    expected_keymaster_security_level = KM_SECURITY_LEVEL_SOFTWARE;
 
     keymaster_cert_chain_t cert_chain;
     EXPECT_EQ(KM_ERROR_OK, AttestKey("challenge", "attest_app_id", &cert_chain));
@@ -4156,8 +3878,6 @@
 
     // Upgrade should fail
     EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, UpgradeKey(client_params()));
-
-    EXPECT_EQ(0, GetParam()->keymaster0_calls());
 }
 
 TEST_P(KeyUpgradeTest, RsaVersionUpgrade) {
@@ -4201,9 +3921,6 @@
 
     // Upgrade should fail
     EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, UpgradeKey(client_params()));
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
-        EXPECT_EQ(7, GetParam()->keymaster0_calls());
 }
 
 TEST_P(KeyUpgradeTest, EcVersionUpgrade) {
@@ -4248,17 +3965,16 @@
 
     // Upgrade should fail
     EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, UpgradeKey(client_params()));
-
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
-        EXPECT_EQ(7, GetParam()->keymaster0_calls());
 }
 
 TEST(SoftKeymasterWrapperTest, CheckKeymaster2Device) {
     // Make a good fake device, and wrap it.
-    SoftKeymasterDevice* good_fake(new SoftKeymasterDevice(new TestKeymasterContext));
+    SoftKeymasterDevice* good_fake(
+        new SoftKeymasterDevice(new TestKeymasterContext(KmVersion::KEYMASTER_4_1)));
 
     // Wrap it and check it.
-    SoftKeymasterDevice* good_fake_wrapper(new SoftKeymasterDevice(new TestKeymasterContext));
+    SoftKeymasterDevice* good_fake_wrapper(
+        new SoftKeymasterDevice(new TestKeymasterContext(KmVersion::KEYMASTER_4_1)));
     good_fake_wrapper->SetHardwareDevice(good_fake->keymaster_device());
     EXPECT_TRUE(good_fake_wrapper->Keymaster1DeviceIsGood());
 
@@ -4267,11 +3983,12 @@
 
     // Make a "bad" (doesn't support all digests) device;
     keymaster1_device_t* sha256_only_fake = make_device_sha256_only(
-        (new SoftKeymasterDevice(new TestKeymasterContext("256")))->keymaster_device());
+        (new SoftKeymasterDevice(new TestKeymasterContext(KmVersion::KEYMASTER_4_1, "256")))
+            ->keymaster_device());
 
     // Wrap it and check it.
     SoftKeymasterDevice* sha256_only_fake_wrapper(
-        (new SoftKeymasterDevice(new TestKeymasterContext)));
+        (new SoftKeymasterDevice(new TestKeymasterContext(KmVersion::KEYMASTER_4_1))));
     sha256_only_fake_wrapper->SetHardwareDevice(sha256_only_fake);
     EXPECT_FALSE(sha256_only_fake_wrapper->Keymaster1DeviceIsGood());
 
@@ -4319,7 +4036,7 @@
     }
 
     ResponseVec ComputeSharedHmac(const KeymasterVec& keymasters, const ParamsVec& paramsVec) {
-        ComputeSharedHmacRequest req;
+        ComputeSharedHmacRequest req(kMaxMessageVersion);
         req.params_array.params_array = const_cast<HmacSharingParameters*>(paramsVec.data());
         auto prevent_deletion_of_paramsVec_data =
             finally([&]() { req.params_array.params_array = nullptr; });
@@ -4462,7 +4179,7 @@
     ASSERT_TRUE(VerifyResponses(sharing_check_value, responses));
 
     // Pick a random param and modify the seed.
-    auto param_to_tweak = rand() & params.size();
+    auto param_to_tweak = rand() % params.size();
     constexpr uint8_t wrong_seed_value[] = {0xF, 0x0, 0x0};
     params[param_to_tweak].SetSeed({wrong_seed_value, sizeof(wrong_seed_value)});
     auto prevent_deletion_of_wrong_seed =
diff --git a/tests/android_keymaster_test_utils.cpp b/tests/android_keymaster_test_utils.cpp
index b031d26..7b70601 100644
--- a/tests/android_keymaster_test_utils.cpp
+++ b/tests/android_keymaster_test_utils.cpp
@@ -42,19 +42,22 @@
         break;
     case KM_UINT_REP:
         os << " (Rep)";
-    /* Falls through */
+        /* Falls through */
+        [[fallthrough]];
     case KM_UINT:
         os << " Int: " << param.integer;
         break;
     case KM_ENUM_REP:
         os << " (Rep)";
-    /* Falls through */
+        /* Falls through */
+        [[fallthrough]];
     case KM_ENUM:
         os << " Enum: " << param.enumerated;
         break;
     case KM_ULONG_REP:
         os << " (Rep)";
-    /* Falls through */
+        /* Falls through */
+        [[fallthrough]];
     case KM_ULONG:
         os << " Long: " << param.long_integer;
         break;
@@ -143,12 +146,10 @@
 namespace keymaster {
 
 bool operator==(const AuthorizationSet& a, const AuthorizationSet& b) {
-    if (a.size() != b.size())
-        return false;
+    if (a.size() != b.size()) return false;
 
     for (size_t i = 0; i < a.size(); ++i)
-        if (!(a[i] == b[i]))
-            return false;
+        if (!(a[i] == b[i])) return false;
     return true;
 }
 
@@ -288,8 +289,7 @@
     if (error == KM_ERROR_OK && out_tmp.data)
         output->append(reinterpret_cast<const char*>(out_tmp.data), out_tmp.data_length);
     free((void*)out_tmp.data);
-    if (output_params)
-        output_params->Reinitialize(out_params);
+    if (output_params) output_params->Reinitialize(out_params);
     keymaster_free_param_set(&out_params);
     return error;
 }
@@ -324,8 +324,7 @@
     if (out_tmp.data)
         output->append(reinterpret_cast<const char*>(out_tmp.data), out_tmp.data_length);
     free((void*)out_tmp.data);
-    if (output_params)
-        output_params->Reinitialize(out_params);
+    if (output_params) output_params->Reinitialize(out_params);
     keymaster_free_param_set(&out_params);
     return error;
 }
@@ -485,6 +484,13 @@
     return EncryptMessage(update_params, message, digest, padding, generated_nonce);
 }
 
+string Keymaster2Test::EncryptMessage(const string& message, keymaster_digest_t digest,
+                                      keymaster_digest_t mgf_digest, keymaster_padding_t padding,
+                                      string* generated_nonce) {
+    AuthorizationSet update_params;
+    return EncryptMessage(update_params, message, digest, mgf_digest, padding, generated_nonce);
+}
+
 string Keymaster2Test::EncryptMessage(const string& message, keymaster_block_mode_t block_mode,
                                       keymaster_padding_t padding, string* generated_nonce) {
     AuthorizationSet update_params;
@@ -492,6 +498,26 @@
 }
 
 string Keymaster2Test::EncryptMessage(const AuthorizationSet& update_params, const string& message,
+                                      keymaster_digest_t digest, keymaster_digest_t mgf_digest,
+                                      keymaster_padding_t padding, string* generated_nonce) {
+    SCOPED_TRACE("EncryptMessage");
+    AuthorizationSet begin_params(client_params()), output_params;
+    begin_params.push_back(TAG_PADDING, padding);
+    begin_params.push_back(TAG_DIGEST, digest);
+    begin_params.push_back(TAG_RSA_OAEP_MGF_DIGEST, mgf_digest);
+    string ciphertext =
+        ProcessMessage(KM_PURPOSE_ENCRYPT, message, begin_params, update_params, &output_params);
+    if (generated_nonce) {
+        keymaster_blob_t nonce_blob;
+        EXPECT_TRUE(output_params.GetTagValue(TAG_NONCE, &nonce_blob));
+        *generated_nonce = make_string(nonce_blob.data, nonce_blob.data_length);
+    } else {
+        EXPECT_EQ(-1, output_params.find(TAG_NONCE));
+    }
+    return ciphertext;
+}
+
+string Keymaster2Test::EncryptMessage(const AuthorizationSet& update_params, const string& message,
                                       keymaster_digest_t digest, keymaster_padding_t padding,
                                       string* generated_nonce) {
     SCOPED_TRACE("EncryptMessage");
@@ -587,6 +613,17 @@
     return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext, begin_params, update_params);
 }
 
+string Keymaster2Test::DecryptMessage(const string& ciphertext, keymaster_digest_t digest,
+                                      keymaster_digest_t mgf_digest, keymaster_padding_t padding) {
+    SCOPED_TRACE("DecryptMessage");
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_PADDING, padding);
+    begin_params.push_back(TAG_DIGEST, digest);
+    begin_params.push_back(TAG_RSA_OAEP_MGF_DIGEST, mgf_digest);
+    AuthorizationSet update_params;
+    return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext, begin_params, update_params);
+}
+
 string Keymaster2Test::DecryptMessage(const AuthorizationSet& update_params,
                                       const string& ciphertext, keymaster_digest_t digest,
                                       keymaster_padding_t padding, const string& nonce) {
@@ -617,8 +654,7 @@
     keymaster_error_t error = device()->export_key(device(), format, &blob_, &client_id_,
                                                    nullptr /* app_data */, &export_tmp);
 
-    if (error != KM_ERROR_OK)
-        return error;
+    if (error != KM_ERROR_OK) return error;
 
     *export_data = string(reinterpret_cast<const char*>(export_tmp.data), export_tmp.data_length);
     free((void*)export_tmp.data);
@@ -750,8 +786,7 @@
         auto alg_ptr = std::find_if(params->params, end, [](keymaster_key_param_t& p) {
             return p.tag == KM_TAG_ALGORITHM;
         });
-        if (alg_ptr == end)
-            return nullptr;
+        if (alg_ptr == end) return nullptr;
         return alg_ptr;
     }
 
@@ -795,8 +830,7 @@
                                                    size_t* digests_length) {
         keymaster_error_t error = unwrap(dev)->get_supported_digests(
             unwrap(dev), algorithm, purpose, digests, digests_length);
-        if (error != KM_ERROR_OK)
-            return error;
+        if (error != KM_ERROR_OK) return error;
 
         std::vector<keymaster_digest_t> filtered_digests;
         std::copy_if(*digests, *digests + *digests_length, std::back_inserter(filtered_digests),
@@ -835,8 +869,7 @@
                                           keymaster_key_blob_t* key_blob,
                                           keymaster_key_characteristics_t** characteristics) {
         auto alg_ptr = get_algorithm_param(params);
-        if (!alg_ptr)
-            return KM_ERROR_UNSUPPORTED_ALGORITHM;
+        if (!alg_ptr) return KM_ERROR_UNSUPPORTED_ALGORITHM;
         if (alg_ptr->enumerated == KM_ALGORITHM_HMAC && !all_digests_supported(params))
             return KM_ERROR_UNSUPPORTED_DIGEST;
 
@@ -857,8 +890,7 @@
                keymaster_key_format_t key_format, const keymaster_blob_t* key_data,
                keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t** characteristics) {
         auto alg_ptr = get_algorithm_param(params);
-        if (!alg_ptr)
-            return KM_ERROR_UNSUPPORTED_ALGORITHM;
+        if (!alg_ptr) return KM_ERROR_UNSUPPORTED_ALGORITHM;
         if (alg_ptr->enumerated == KM_ALGORITHM_HMAC && !all_digests_supported(params))
             return KM_ERROR_UNSUPPORTED_DIGEST;
 
@@ -881,8 +913,7 @@
                                    const keymaster_key_param_set_t* in_params,
                                    keymaster_key_param_set_t* out_params,
                                    keymaster_operation_handle_t* operation_handle) {
-        if (!all_digests_supported(in_params))
-            return KM_ERROR_UNSUPPORTED_DIGEST;
+        if (!all_digests_supported(in_params)) return KM_ERROR_UNSUPPORTED_DIGEST;
         return unwrap(dev)->begin(unwrap(dev), purpose, key, in_params, out_params,
                                   operation_handle);
     }
diff --git a/tests/android_keymaster_test_utils.h b/tests/android_keymaster_test_utils.h
index a1965be..06eefab 100644
--- a/tests/android_keymaster_test_utils.h
+++ b/tests/android_keymaster_test_utils.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef SYSTEM_KEYMASTER_ANDROID_KEYMASTER_TEST_UTILS_H_
-#define SYSTEM_KEYMASTER_ANDROID_KEYMASTER_TEST_UTILS_H_
+#pragma once
 
 /*
  * Utilities used to help with testing.  Not used in production code.
@@ -31,7 +30,6 @@
 
 #include <gtest/gtest.h>
 
-#include <hardware/keymaster0.h>
 #include <hardware/keymaster1.h>
 #include <hardware/keymaster2.h>
 #include <hardware/keymaster_defs.h>
@@ -39,6 +37,7 @@
 #include <keymaster/android_keymaster_utils.h>
 #include <keymaster/authorization_set.h>
 #include <keymaster/keymaster_context.h>
+#include <keymaster/km_version.h>
 #include <keymaster/logger.h>
 
 std::ostream& operator<<(std::ostream& os, const keymaster_key_param_t& param);
@@ -66,8 +65,7 @@
               KeymasterEnum val) {
     int pos = -1;
     while ((pos = set.find(tag, pos)) != -1)
-        if (static_cast<KeymasterEnum>(set[pos].enumerated) == val)
-            return true;
+        if (static_cast<KeymasterEnum>(set[pos].enumerated) == val) return true;
     return false;
 }
 
@@ -81,8 +79,7 @@
 bool contains(const AuthorizationSet& set, TypedTag<KM_UINT_REP, Tag> tag, uint32_t val) {
     int pos = -1;
     while ((pos = set.find(tag, pos)) != -1)
-        if (set[pos].integer == val)
-            return true;
+        if (set[pos].integer == val) return true;
     return false;
 }
 
@@ -95,17 +92,15 @@
 template <keymaster_tag_t Tag>
 bool contains(const AuthorizationSet& set, TypedTag<KM_BYTES, Tag> tag, const std::string& val) {
     int pos = set.find(tag);
-    return pos != -1 &&
-           std::string(reinterpret_cast<const char*>(set[pos].blob.data),
-                       set[pos].blob.data_length) == val;
+    return pos != -1 && std::string(reinterpret_cast<const char*>(set[pos].blob.data),
+                                    set[pos].blob.data_length) == val;
 }
 
 template <keymaster_tag_t Tag>
 bool contains(const AuthorizationSet& set, TypedTag<KM_BIGNUM, Tag> tag, const std::string& val) {
     int pos = set.find(tag);
-    return pos != -1 &&
-           std::string(reinterpret_cast<const char*>(set[pos].blob.data),
-                       set[pos].blob.data_length) == val;
+    return pos != -1 && std::string(reinterpret_cast<const char*>(set[pos].blob.data),
+                                    set[pos].blob.data_length) == val;
 }
 
 inline bool contains(const AuthorizationSet& set, keymaster_tag_t tag) {
@@ -161,11 +156,11 @@
     virtual ~Keymaster2TestInstanceCreator(){};
     virtual keymaster2_device_t* CreateDevice() const = 0;
 
-    virtual bool algorithm_in_km0_hardware(keymaster_algorithm_t algorithm) const = 0;
-    virtual int keymaster0_calls() const = 0;
     virtual int minimal_digest_set() const { return false; }
     virtual bool is_keymaster1_hw() const = 0;
+    virtual bool is_keymint() const { return false; }
     virtual KeymasterContext* keymaster_context() const = 0;
+    virtual KmVersion km_version() const = 0;
 
     virtual std::string name() const = 0;
 };
@@ -251,10 +246,16 @@
     std::string EncryptMessage(const std::string& message, keymaster_padding_t padding,
                                std::string* generated_nonce = nullptr);
     std::string EncryptMessage(const std::string& message, keymaster_digest_t digest,
+                               keymaster_digest_t mgf_digest, keymaster_padding_t padding,
+                               std::string* generated_nonce = nullptr);
+    std::string EncryptMessage(const std::string& message, keymaster_digest_t digest,
                                keymaster_padding_t padding, std::string* generated_nonce = nullptr);
     std::string EncryptMessage(const std::string& message, keymaster_block_mode_t block_mode,
                                keymaster_padding_t padding, std::string* generated_nonce = nullptr);
     std::string EncryptMessage(const AuthorizationSet& update_params, const std::string& message,
+                               keymaster_digest_t digest, keymaster_digest_t mgf_digest,
+                               keymaster_padding_t padding, std::string* generated_nonce = nullptr);
+    std::string EncryptMessage(const AuthorizationSet& update_params, const std::string& message,
                                keymaster_digest_t digest, keymaster_padding_t padding,
                                std::string* generated_nonce = nullptr);
     std::string EncryptMessage(const AuthorizationSet& update_params, const std::string& message,
@@ -272,6 +273,8 @@
                                keymaster_padding_t padding);
     std::string DecryptMessage(const std::string& ciphertext, keymaster_digest_t digest,
                                keymaster_padding_t padding, const std::string& nonce);
+    std::string DecryptMessage(const std::string& ciphertext, keymaster_digest_t digest,
+                               keymaster_digest_t mgf_digest, keymaster_padding_t padding);
     std::string DecryptMessage(const std::string& ciphertext, keymaster_block_mode_t block_mode,
                                keymaster_padding_t padding, const std::string& nonce);
     std::string DecryptMessage(const AuthorizationSet& update_params, const std::string& ciphertext,
@@ -348,139 +351,6 @@
     keymaster_key_characteristics_t characteristics_;
 };
 
-struct Keymaster0CountingWrapper : public keymaster0_device_t {
-    explicit Keymaster0CountingWrapper(keymaster0_device_t* device) : device_(device), counter_(0) {
-        common = device_->common;
-        common.close = counting_close_device;
-        client_version = device_->client_version;
-        flags = device_->flags;
-        context = this;
-
-        generate_keypair = counting_generate_keypair;
-        import_keypair = counting_import_keypair;
-        get_keypair_public = counting_get_keypair_public;
-        delete_keypair = counting_delete_keypair;
-        delete_all = counting_delete_all;
-        sign_data = counting_sign_data;
-        verify_data = counting_verify_data;
-    }
-
-    int count() { return counter_; }
-
-    // The blobs generated by the underlying softkeymaster start with "PK#8".  Tweak the prefix so
-    // they don't get identified as softkeymaster blobs.
-    static void munge_blob(uint8_t* blob, size_t blob_length) {
-        if (blob && blob_length > 0 && *blob == 'P')
-            *blob = 'Q';  // Mind your Ps and Qs!
-    }
-
-    // Copy and un-modfy the blob.  The caller must clean up the return value.
-    static uint8_t* unmunge_blob(const uint8_t* blob, size_t blob_length) {
-        uint8_t* dup_blob = dup_buffer(blob, blob_length);
-        if (dup_blob && blob_length > 0 && *dup_blob == 'Q')
-            *dup_blob = 'P';
-        return dup_blob;
-    }
-
-    static keymaster0_device_t* device(const keymaster0_device_t* dev) {
-        Keymaster0CountingWrapper* wrapper =
-            reinterpret_cast<Keymaster0CountingWrapper*>(dev->context);
-        return wrapper->device_;
-    }
-
-    static void increment(const keymaster0_device_t* dev) {
-        Keymaster0CountingWrapper* wrapper =
-            reinterpret_cast<Keymaster0CountingWrapper*>(dev->context);
-        wrapper->counter_++;
-    }
-
-    static int counting_close_device(hw_device_t* dev) {
-        keymaster0_device_t* k0_dev = reinterpret_cast<keymaster0_device_t*>(dev);
-        increment(k0_dev);
-        Keymaster0CountingWrapper* wrapper =
-            reinterpret_cast<Keymaster0CountingWrapper*>(k0_dev->context);
-        int retval =
-            wrapper->device_->common.close(reinterpret_cast<hw_device_t*>(wrapper->device_));
-        delete wrapper;
-        return retval;
-    }
-
-    static int counting_generate_keypair(const struct keymaster0_device* dev,
-                                         const keymaster_keypair_t key_type, const void* key_params,
-                                         uint8_t** key_blob, size_t* key_blob_length) {
-        increment(dev);
-        int result = device(dev)->generate_keypair(device(dev), key_type, key_params, key_blob,
-                                                   key_blob_length);
-        if (result == 0)
-            munge_blob(*key_blob, *key_blob_length);
-        return result;
-    }
-
-    static int counting_import_keypair(const struct keymaster0_device* dev, const uint8_t* key,
-                                       const size_t key_length, uint8_t** key_blob,
-                                       size_t* key_blob_length) {
-        increment(dev);
-        int result =
-            device(dev)->import_keypair(device(dev), key, key_length, key_blob, key_blob_length);
-        if (result == 0)
-            munge_blob(*key_blob, *key_blob_length);
-        return result;
-    }
-
-    static int counting_get_keypair_public(const struct keymaster0_device* dev,
-                                           const uint8_t* key_blob, const size_t key_blob_length,
-                                           uint8_t** x509_data, size_t* x509_data_length) {
-        increment(dev);
-        std::unique_ptr<uint8_t[]> dup_blob(unmunge_blob(key_blob, key_blob_length));
-        return device(dev)->get_keypair_public(device(dev), dup_blob.get(), key_blob_length,
-                                               x509_data, x509_data_length);
-    }
-
-    static int counting_delete_keypair(const struct keymaster0_device* dev, const uint8_t* key_blob,
-                                       const size_t key_blob_length) {
-        increment(dev);
-        if (key_blob && key_blob_length > 0)
-            EXPECT_EQ('Q', *key_blob);
-        if (device(dev)->delete_keypair) {
-            std::unique_ptr<uint8_t[]> dup_blob(unmunge_blob(key_blob, key_blob_length));
-            return device(dev)->delete_keypair(device(dev), dup_blob.get(), key_blob_length);
-        }
-        return 0;
-    }
-
-    static int counting_delete_all(const struct keymaster0_device* dev) {
-        increment(dev);
-        if (device(dev)->delete_all)
-            return device(dev)->delete_all(device(dev));
-        return 0;
-    }
-
-    static int counting_sign_data(const struct keymaster0_device* dev, const void* signing_params,
-                                  const uint8_t* key_blob, const size_t key_blob_length,
-                                  const uint8_t* data, const size_t data_length,
-                                  uint8_t** signed_data, size_t* signed_data_length) {
-        increment(dev);
-        std::unique_ptr<uint8_t[]> dup_blob(unmunge_blob(key_blob, key_blob_length));
-        return device(dev)->sign_data(device(dev), signing_params, dup_blob.get(), key_blob_length,
-                                      data, data_length, signed_data, signed_data_length);
-    }
-
-    static int counting_verify_data(const struct keymaster0_device* dev, const void* signing_params,
-                                    const uint8_t* key_blob, const size_t key_blob_length,
-                                    const uint8_t* signed_data, const size_t signed_data_length,
-                                    const uint8_t* signature, const size_t signature_length) {
-        increment(dev);
-        std::unique_ptr<uint8_t[]> dup_blob(unmunge_blob(key_blob, key_blob_length));
-        return device(dev)->verify_data(device(dev), signing_params, dup_blob.get(),
-                                        key_blob_length, signed_data, signed_data_length, signature,
-                                        signature_length);
-    }
-
-  private:
-    keymaster0_device_t* device_;
-    int counter_;
-};
-
 /**
  * This function takes a keymaster1_device_t and wraps it in an adapter that supports only
  * KM_DIGEST_SHA_2_256.
@@ -489,5 +359,3 @@
 
 }  // namespace test
 }  // namespace keymaster
-
-#endif  // SYSTEM_KEYMASTER_ANDROID_KEYMASTER_TEST_UTILS_H_
diff --git a/tests/attestation_record_test.cpp b/tests/attestation_record_test.cpp
index 02b99f7..92cd77d 100644
--- a/tests/attestation_record_test.cpp
+++ b/tests/attestation_record_test.cpp
@@ -16,37 +16,46 @@
 
 #include <fstream>
 
+#include <cppbor_parse.h>
 #include <gtest/gtest.h>
 
+#include <keymaster/contexts/soft_attestation_context.h>
 #include <keymaster/keymaster_context.h>
+#include <keymaster/km_openssl/attestation_record.h>
 
 #include "android_keymaster_test_utils.h"
-#include <keymaster/attestation_record.h>
+
+// Use TAG_KDF as an 'unknown tag', as it is not deliberately thrown out
+// in attestation_record.cpp, but still among the keymaster tag types.
+#define UNKNOWN_TAG static_cast<keymaster_tag_t>(KM_ULONG_REP | 50)
+#define UNKNOWN_TAG_VALUE 0
 
 namespace keymaster {
 namespace test {
 
-class TestContext : public AttestationRecordContext {
+TypedTag<KM_ULONG_REP, UNKNOWN_TAG> UNKNOWN_TAG_T;
+
+class TestContext : public SoftAttestationContext {
   public:
+    TestContext(KmVersion version) : SoftAttestationContext(version) {}
+
     keymaster_security_level_t GetSecurityLevel() const override {
         return KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
     }
-    keymaster_error_t GenerateUniqueId(uint64_t /* creation_date_time */,
-                                       const keymaster_blob_t& application_id,
-                                       bool /* reset_since_rotation */,
-                                       Buffer* unique_id) const override {
+    Buffer GenerateUniqueId(uint64_t /* creation_date_time */,
+                            const keymaster_blob_t& application_id, bool /* reset_since_rotation */,
+                            keymaster_error_t* error) const override {
         // Use the application ID directly as the unique ID.
-        unique_id->Reinitialize(application_id.data, application_id.data_length);
-        return KM_ERROR_OK;
+        *error = KM_ERROR_OK;
+        return {application_id.data, application_id.data_length};
     }
-    keymaster_error_t GetVerifiedBootParams(keymaster_blob_t* verified_boot_key,
-                                            keymaster_verified_boot_t* verified_boot_state,
-                                            bool* device_locked) const override {
-        verified_boot_key->data = vboot_key_;
-        verified_boot_key->data_length = sizeof(vboot_key_);
-        *verified_boot_state = KM_VERIFIED_BOOT_VERIFIED;
-        *device_locked = true;
-        return KM_ERROR_OK;
+    const VerifiedBootParams* GetVerifiedBootParams(keymaster_error_t* error) const override {
+        static VerifiedBootParams params{};
+        params.verified_boot_key = {vboot_key_, sizeof(vboot_key_)};
+        params.verified_boot_state = KM_VERIFIED_BOOT_VERIFIED;
+        params.device_locked = true;
+        *error = KM_ERROR_OK;
+        return &params;
     }
 
     void VerifyRootOfTrust(const keymaster_blob_t& verified_boot_key,
@@ -63,8 +72,18 @@
     uint8_t vboot_key_[32]{"test_vboot_key"};
 };
 
-TEST(AttestTest, Simple) {
-    TestContext context;
+class KeymintTestContext : public TestContext {
+  public:
+    KeymintTestContext() : TestContext(KmVersion::KEYMINT_1) {}
+};
+
+class KeymasterTestContext : public TestContext {
+  public:
+    KeymasterTestContext() : TestContext(KmVersion::KEYMASTER_4_1) {}  // Last Keymaster version
+};
+
+TEST(AttestAsn1Test, Simple) {
+    KeymasterTestContext context;
     AuthorizationSet hw_set(AuthorizationSetBuilder()
                                 .RsaSigningKey(512, 3)
                                 .Digest(KM_DIGEST_SHA_2_256)
@@ -75,7 +94,8 @@
     AuthorizationSet sw_set(AuthorizationSetBuilder()
                                 .Authorization(TAG_ACTIVE_DATETIME, 10)
                                 .Authorization(TAG_CREATION_DATETIME, 10)
-                                .Authorization(TAG_APPLICATION_ID, "fake_app_id", 11));
+                                .Authorization(TAG_APPLICATION_ID, "fake_app_id", 19)
+                                .Authorization(TAG_APPLICATION_DATA, "fake_app_data", 12));
 
     UniquePtr<uint8_t[]> asn1;
     size_t asn1_len = 0;
@@ -89,8 +109,7 @@
 
     std::ofstream output("attest.der",
                          std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
-    if (output)
-        output.write(reinterpret_cast<const char*>(asn1.get()), asn1_len);
+    if (output) output.write(reinterpret_cast<const char*>(asn1.get()), asn1_len);
     output.close();
 
     AuthorizationSet parsed_hw_set;
@@ -122,6 +141,10 @@
     // The TAG_INCLUDE_UNIQUE_ID tag is not expected to appear in parsed_hw_set.
     hw_set.erase(hw_set.find(TAG_INCLUDE_UNIQUE_ID));
 
+    // Application data is not expected to appear in parsed_sw_set.
+    sw_set.erase(sw_set.find(TAG_APPLICATION_ID));
+    sw_set.erase(sw_set.find(TAG_APPLICATION_DATA));
+
     // Check that the list of tags is consistent across build and parse.
     hw_set.Sort();
     sw_set.Sort();
@@ -140,5 +163,190 @@
     delete[] verified_boot_key.data;
 }
 
+TEST(EatTest, Simple) {
+    KeymintTestContext context;
+    AuthorizationSet hw_set(AuthorizationSetBuilder()
+                                .RsaSigningKey(512, 3)
+                                .Digest(KM_DIGEST_SHA_2_256)
+                                .Digest(KM_DIGEST_SHA_2_384)
+                                .Authorization(TAG_OS_VERSION, 60000)
+                                .Authorization(TAG_OS_PATCHLEVEL, 201512)
+                                .Authorization(TAG_INCLUDE_UNIQUE_ID)
+                                .Authorization(TAG_ATTESTATION_ID_IMEI, "490154203237518", 15));
+    AuthorizationSet sw_set(AuthorizationSetBuilder()
+                                .Authorization(TAG_ACTIVE_DATETIME, 10)
+                                .Authorization(TAG_CREATION_DATETIME, 10)
+                                .Authorization(TAG_APPLICATION_ID, "fake_app_id", 19)
+                                .Authorization(TAG_APPLICATION_DATA, "fake_app_data", 12));
+
+    std::vector<uint8_t> eat;
+    AuthorizationSet attest_params(
+        AuthorizationSetBuilder()
+            .Authorization(TAG_ATTESTATION_CHALLENGE, "fake_challenge", 14)
+            .Authorization(TAG_ATTESTATION_APPLICATION_ID, "fake_attest_app_id", 18));
+    ASSERT_EQ(KM_ERROR_OK, build_eat_record(attest_params, sw_set, hw_set, context, &eat));
+    EXPECT_GT(eat.size(), 0U);
+
+    std::ofstream output("eat.der",
+                         std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
+    if (output) output.write(reinterpret_cast<const char*>(&eat[0]), eat.size() * sizeof(uint8_t));
+    output.close();
+
+    AuthorizationSet parsed_hw_set;
+    AuthorizationSet parsed_sw_set;
+    uint32_t attestation_version;
+    uint32_t keymaster_version;
+    keymaster_security_level_t attestation_security_level;
+    keymaster_security_level_t keymaster_security_level;
+    keymaster_blob_t attestation_challenge = {};
+    keymaster_blob_t unique_id = {};
+    keymaster_blob_t verified_boot_key = {};
+    keymaster_verified_boot_t verified_boot_state;
+    bool device_locked;
+    std::vector<int64_t> unexpected_claims;
+    EXPECT_EQ(KM_ERROR_OK,
+              parse_eat_record(eat.data(), eat.size(), &attestation_version,
+                               &attestation_security_level, &keymaster_version,
+                               &keymaster_security_level, &attestation_challenge, &parsed_sw_set,
+                               &parsed_hw_set, &unique_id, &verified_boot_key, &verified_boot_state,
+                               &device_locked, &unexpected_claims));
+
+    // Check that there were no unexpected claims when parsing.
+    EXPECT_EQ(std::vector<int64_t>(), unexpected_claims);
+
+    // Check that the challenge is consistent across build and parse.
+    EXPECT_EQ("fake_challenge",
+              std::string(reinterpret_cast<const char*>(attestation_challenge.data), 14));
+    delete[] attestation_challenge.data;
+
+    // Check that the unique id was populated as expected.
+    EXPECT_EQ("fake_app_id", std::string(reinterpret_cast<const char*>(unique_id.data), 11));
+    delete[] unique_id.data;
+
+    // The attestation ID is expected to appear in parsed_sw_set.
+    sw_set.push_back(TAG_ATTESTATION_APPLICATION_ID, "fake_attest_app_id", 18);
+
+    // The TAG_INCLUDE_UNIQUE_ID tag is not expected to appear in parsed_hw_set.
+    hw_set.erase(hw_set.find(TAG_INCLUDE_UNIQUE_ID));
+
+    // Application data is not expected to appear in parsed_sw_set.
+    sw_set.erase(sw_set.find(TAG_APPLICATION_ID));
+    sw_set.erase(sw_set.find(TAG_APPLICATION_DATA));
+
+    // Check that the list of tags is consistent across build and parse.
+    hw_set.Sort();
+    sw_set.Sort();
+    parsed_hw_set.Sort();
+    parsed_sw_set.Sort();
+    EXPECT_EQ(hw_set, parsed_hw_set);
+    EXPECT_EQ(sw_set, parsed_sw_set);
+
+    // Check the root of trust values.
+    context.VerifyRootOfTrust(verified_boot_key, verified_boot_state, device_locked);
+    delete[] verified_boot_key.data;
+}
+
+TEST(BadImeiTest, Simple) {
+    KeymintTestContext context;
+    AuthorizationSet hw_set(
+        AuthorizationSetBuilder().Authorization(TAG_ATTESTATION_ID_IMEI, "1234567890123456", 16));
+    AuthorizationSet attest_params(
+        AuthorizationSetBuilder()
+            .Authorization(TAG_ATTESTATION_CHALLENGE, "fake_challenge", 14)
+            .Authorization(TAG_ATTESTATION_APPLICATION_ID, "fake_attest_app_id", 18));
+    AuthorizationSet sw_set;
+
+    std::vector<uint8_t> eat;
+    ASSERT_EQ(KM_ERROR_INVALID_TAG, build_eat_record(attest_params, sw_set, hw_set, context, &eat));
+}
+
+TEST(MissingAuthChallengeTest, Simple) {
+    KeymintTestContext context;
+    AuthorizationSet hw_set(AuthorizationSetBuilder().Authorization(TAG_OS_PATCHLEVEL, 201512));
+    AuthorizationSet attest_params(AuthorizationSetBuilder().Authorization(
+        TAG_ATTESTATION_APPLICATION_ID, "fake_attest_app_id", 18));
+    AuthorizationSet sw_set;
+
+    std::vector<uint8_t> eat;
+    ASSERT_EQ(KM_ERROR_ATTESTATION_CHALLENGE_MISSING,
+              build_eat_record(attest_params, sw_set, hw_set, context, &eat));
+}
+
+TEST(UnknownTagTest, Simple) {
+    KeymintTestContext context;
+    AuthorizationSet unknown_tag_set(
+        AuthorizationSetBuilder().Authorization(UNKNOWN_TAG_T, UNKNOWN_TAG_VALUE));
+
+    // Test adding an unknown tag to both sets. The tag should be retained only in the software
+    // submod.
+    std::vector<uint8_t> eat;
+    AuthorizationSet attest_params(
+        AuthorizationSetBuilder()
+            .Authorization(TAG_ATTESTATION_CHALLENGE, "fake_challenge", 14)
+            .Authorization(TAG_ATTESTATION_APPLICATION_ID, "fake_attest_app_id", 18));
+    ASSERT_EQ(KM_ERROR_OK,
+              build_eat_record(attest_params, unknown_tag_set, unknown_tag_set, context, &eat));
+    EXPECT_GT(eat.size(), 0U);
+
+    AuthorizationSet parsed_hw_set;
+    AuthorizationSet parsed_sw_set;
+    uint32_t attestation_version;
+    uint32_t keymaster_version;
+    keymaster_security_level_t attestation_security_level;
+    keymaster_security_level_t keymaster_security_level;
+    keymaster_blob_t attestation_challenge = {};
+    keymaster_blob_t unique_id = {};
+    keymaster_blob_t verified_boot_key = {};
+    keymaster_verified_boot_t verified_boot_state;
+    bool device_locked;
+    std::vector<int64_t> unexpected_claims;
+    // Parsing should fail, because the software submod retains the unknown tag.
+    EXPECT_EQ(KM_ERROR_INVALID_TAG,
+              parse_eat_record(eat.data(), eat.size(), &attestation_version,
+                               &attestation_security_level, &keymaster_version,
+                               &keymaster_security_level, &attestation_challenge, &parsed_sw_set,
+                               &parsed_hw_set, &unique_id, &verified_boot_key, &verified_boot_state,
+                               &device_locked, &unexpected_claims));
+
+    // Perform a manual inspection of the EAT token, checking that the tag is retained in the
+    // software submod, but not in the hardware submod.
+    auto [top_level_item, next_pos, error] = cppbor::parse(eat.data(), eat.size());
+    ASSERT_NE(top_level_item, nullptr);
+    const cppbor::Map* eat_map = top_level_item->asMap();
+    ASSERT_NE(eat_map, nullptr);
+    bool found_in_software_submod = false;
+    bool found_in_hardware_submod = false;
+    for (size_t i = 0; i < eat_map->size(); i++) {
+        auto& [eat_key, eat_value] = (*eat_map)[i];
+        const cppbor::Int* root_key = eat_key->asInt();
+        if ((EatClaim)root_key->value() == EatClaim::SUBMODS) {
+            const cppbor::Map* submods_map = eat_value->asMap();
+            // Check for each submod whether it contains the expected value.
+            for (size_t j = 0; j < submods_map->size(); j++) {
+                auto& [submod_key, submod_value] = (*submods_map)[j];
+                const cppbor::Map* submod_map = submod_value->asMap();
+                bool found_in_submod = false;
+                EatSecurityLevel submod_security_level;
+                for (size_t k = 0; k < submod_map->size(); k++) {
+                    auto& [key_item, value_item] = (*submod_map)[k];
+                    const cppbor::Int* key_int = key_item->asInt();
+                    if (key_int->value() == convert_to_eat_claim(UNKNOWN_TAG_T)) {
+                        found_in_submod = true;
+                    } else if ((EatClaim)key_int->value() == EatClaim::SECURITY_LEVEL) {
+                        submod_security_level = (EatSecurityLevel)value_item->asInt()->value();
+                    }
+                }
+                if (submod_security_level == EatSecurityLevel::UNRESTRICTED) {
+                    found_in_software_submod = found_in_submod;
+                } else if (submod_security_level == EatSecurityLevel::SECURE_RESTRICTED) {
+                    found_in_hardware_submod = found_in_submod;
+                }
+            }
+        }
+    }
+    EXPECT_FALSE(found_in_hardware_submod);
+    EXPECT_TRUE(found_in_software_submod);
+}
+
 }  // namespace test
 }  // namespace keymaster
diff --git a/tests/authorization_set_test.cpp b/tests/authorization_set_test.cpp
index 8c908c3..ecbe2c0 100644
--- a/tests/authorization_set_test.cpp
+++ b/tests/authorization_set_test.cpp
@@ -16,8 +16,8 @@
 
 #include <gtest/gtest.h>
 
-#include <keymaster/authorization_set.h>
 #include <keymaster/android_keymaster_utils.h>
+#include <keymaster/authorization_set.h>
 
 #include "android_keymaster_test_utils.h"
 
@@ -27,10 +27,13 @@
 
 TEST(Construction, ListProvided) {
     keymaster_key_param_t params[] = {
-        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
-        Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_USER_ID, 7),
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+        Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+        Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
+        Authorization(TAG_USER_ID, 7),
         Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD),
-        Authorization(TAG_APPLICATION_ID, "my_app", 6), Authorization(TAG_KEY_SIZE, 256),
+        Authorization(TAG_APPLICATION_ID, "my_app", 6),
+        Authorization(TAG_KEY_SIZE, 256),
         Authorization(TAG_AUTH_TIMEOUT, 300),
     };
     AuthorizationSet set(params, array_length(params));
@@ -39,10 +42,13 @@
 
 TEST(Construction, Copy) {
     keymaster_key_param_t params[] = {
-        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
-        Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_USER_ID, 7),
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+        Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+        Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
+        Authorization(TAG_USER_ID, 7),
         Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD),
-        Authorization(TAG_APPLICATION_ID, "my_app", 6), Authorization(TAG_KEY_SIZE, 256),
+        Authorization(TAG_APPLICATION_ID, "my_app", 6),
+        Authorization(TAG_KEY_SIZE, 256),
         Authorization(TAG_AUTH_TIMEOUT, 300),
     };
     AuthorizationSet set(params, array_length(params));
@@ -52,7 +58,8 @@
 
 TEST(Construction, NullProvided) {
     keymaster_key_param_t params[] = {
-        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+        Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
     };
 
     AuthorizationSet set1(params, 0);
@@ -637,22 +644,22 @@
 
 TEST(Union, Disjoint) {
     AuthorizationSet set1(AuthorizationSetBuilder()
-                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
-                             .Authorization(TAG_ACTIVE_DATETIME, 10)
-                             .Authorization(TAG_APPLICATION_DATA, "data", 4));
+                              .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                              .Authorization(TAG_ACTIVE_DATETIME, 10)
+                              .Authorization(TAG_APPLICATION_DATA, "data", 4));
 
     AuthorizationSet set2(AuthorizationSetBuilder()
-                             .Authorization(TAG_USER_ID, 7)
-                             .Authorization(TAG_APPLICATION_DATA, "foo", 3)
-                             .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD));
+                              .Authorization(TAG_USER_ID, 7)
+                              .Authorization(TAG_APPLICATION_DATA, "foo", 3)
+                              .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD));
 
     AuthorizationSet expected(AuthorizationSetBuilder()
-                             .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
-                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
-                             .Authorization(TAG_USER_ID, 7)
-                             .Authorization(TAG_ACTIVE_DATETIME, 10)
-                             .Authorization(TAG_APPLICATION_DATA, "data", 4)
-                             .Authorization(TAG_APPLICATION_DATA, "foo", 3));
+                                  .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
+                                  .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                                  .Authorization(TAG_USER_ID, 7)
+                                  .Authorization(TAG_ACTIVE_DATETIME, 10)
+                                  .Authorization(TAG_APPLICATION_DATA, "data", 4)
+                                  .Authorization(TAG_APPLICATION_DATA, "foo", 3));
 
     set1.Union(set2);
     EXPECT_EQ(expected, set1);
@@ -660,19 +667,19 @@
 
 TEST(Union, Overlap) {
     AuthorizationSet set1(AuthorizationSetBuilder()
-                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
-                             .Authorization(TAG_ACTIVE_DATETIME, 10)
-                             .Authorization(TAG_APPLICATION_DATA, "data", 4));
+                              .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                              .Authorization(TAG_ACTIVE_DATETIME, 10)
+                              .Authorization(TAG_APPLICATION_DATA, "data", 4));
 
     AuthorizationSet set2(AuthorizationSetBuilder()
-                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
-                             .Authorization(TAG_ACTIVE_DATETIME, 10)
-                             .Authorization(TAG_APPLICATION_DATA, "data", 4));
+                              .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                              .Authorization(TAG_ACTIVE_DATETIME, 10)
+                              .Authorization(TAG_APPLICATION_DATA, "data", 4));
 
     AuthorizationSet expected(AuthorizationSetBuilder()
-                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
-                             .Authorization(TAG_ACTIVE_DATETIME, 10)
-                             .Authorization(TAG_APPLICATION_DATA, "data", 4));
+                                  .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                                  .Authorization(TAG_ACTIVE_DATETIME, 10)
+                                  .Authorization(TAG_APPLICATION_DATA, "data", 4));
 
     set1.Union(set2);
     EXPECT_EQ(expected, set1);
@@ -680,16 +687,16 @@
 
 TEST(Union, Empty) {
     AuthorizationSet set1(AuthorizationSetBuilder()
-                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
-                             .Authorization(TAG_ACTIVE_DATETIME, 10)
-                             .Authorization(TAG_APPLICATION_DATA, "data", 4));
+                              .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                              .Authorization(TAG_ACTIVE_DATETIME, 10)
+                              .Authorization(TAG_APPLICATION_DATA, "data", 4));
 
     AuthorizationSet set2;
 
     AuthorizationSet expected(AuthorizationSetBuilder()
-                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
-                             .Authorization(TAG_ACTIVE_DATETIME, 10)
-                             .Authorization(TAG_APPLICATION_DATA, "data", 4));
+                                  .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                                  .Authorization(TAG_ACTIVE_DATETIME, 10)
+                                  .Authorization(TAG_APPLICATION_DATA, "data", 4));
 
     set1.Union(set2);
     EXPECT_EQ(expected, set1);
@@ -697,20 +704,20 @@
 
 TEST(Difference, Disjoint) {
     AuthorizationSet set1(AuthorizationSetBuilder()
-                             .Authorization(TAG_APPLICATION_DATA, "data", 4)
-                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
-                             .Authorization(TAG_ACTIVE_DATETIME, 10));
+                              .Authorization(TAG_APPLICATION_DATA, "data", 4)
+                              .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                              .Authorization(TAG_ACTIVE_DATETIME, 10));
 
     AuthorizationSet set2(AuthorizationSetBuilder()
-                             .Authorization(TAG_USER_ID, 7)
-                             .Authorization(TAG_APPLICATION_DATA, "foo", 3)
-                             .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD));
+                              .Authorization(TAG_USER_ID, 7)
+                              .Authorization(TAG_APPLICATION_DATA, "foo", 3)
+                              .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD));
 
     // Elements are the same as set1, but happen to be in a different order
     AuthorizationSet expected(AuthorizationSetBuilder()
-                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
-                             .Authorization(TAG_ACTIVE_DATETIME, 10)
-                             .Authorization(TAG_APPLICATION_DATA, "data", 4));
+                                  .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                                  .Authorization(TAG_ACTIVE_DATETIME, 10)
+                                  .Authorization(TAG_APPLICATION_DATA, "data", 4));
 
     set1.Difference(set2);
     EXPECT_EQ(expected, set1);
@@ -718,14 +725,14 @@
 
 TEST(Difference, Overlap) {
     AuthorizationSet set1(AuthorizationSetBuilder()
-                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
-                             .Authorization(TAG_ACTIVE_DATETIME, 10)
-                             .Authorization(TAG_APPLICATION_DATA, "data", 4));
+                              .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                              .Authorization(TAG_ACTIVE_DATETIME, 10)
+                              .Authorization(TAG_APPLICATION_DATA, "data", 4));
 
     AuthorizationSet set2(AuthorizationSetBuilder()
-                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
-                             .Authorization(TAG_ACTIVE_DATETIME, 10)
-                             .Authorization(TAG_APPLICATION_DATA, "data", 4));
+                              .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                              .Authorization(TAG_ACTIVE_DATETIME, 10)
+                              .Authorization(TAG_APPLICATION_DATA, "data", 4));
 
     AuthorizationSet empty;
     set1.Difference(set2);
@@ -735,16 +742,16 @@
 
 TEST(Difference, NullSet) {
     AuthorizationSet set1(AuthorizationSetBuilder()
-                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
-                             .Authorization(TAG_ACTIVE_DATETIME, 10)
-                             .Authorization(TAG_APPLICATION_DATA, "data", 4));
+                              .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                              .Authorization(TAG_ACTIVE_DATETIME, 10)
+                              .Authorization(TAG_APPLICATION_DATA, "data", 4));
 
     AuthorizationSet set2;
 
     AuthorizationSet expected(AuthorizationSetBuilder()
-                             .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
-                             .Authorization(TAG_ACTIVE_DATETIME, 10)
-                             .Authorization(TAG_APPLICATION_DATA, "data", 4));
+                                  .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+                                  .Authorization(TAG_ACTIVE_DATETIME, 10)
+                                  .Authorization(TAG_APPLICATION_DATA, "data", 4));
 
     set1.Difference(set2);
     EXPECT_EQ(expected, set1);
diff --git a/tests/ecies_kem_test.cpp b/tests/ecies_kem_test.cpp
index 06e26c3..1910579 100644
--- a/tests/ecies_kem_test.cpp
+++ b/tests/ecies_kem_test.cpp
@@ -31,8 +31,6 @@
 namespace keymaster {
 namespace test {
 
-StdoutLogger logger;
-
 static const keymaster_ec_curve_t kEcCurves[] = {KM_EC_CURVE_P_224, KM_EC_CURVE_P_256,
                                                  KM_EC_CURVE_P_384, KM_EC_CURVE_P_521};
 
diff --git a/tests/fuzzers/buffer_fuzz.cpp b/tests/fuzzers/buffer_fuzz.cpp
new file mode 100644
index 0000000..0b02b3f
--- /dev/null
+++ b/tests/fuzzers/buffer_fuzz.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <functional>
+#include <memory>
+
+#include "fuzzer/FuzzedDataProvider.h"
+#include "keymaster/serializable.h"
+
+static constexpr uint16_t kMinBufferSize = 1;
+static constexpr uint16_t kMaxBufferSize = 2048;
+static constexpr uint16_t kMaxOperations = 1000;
+
+std::vector<std::function<void(keymaster::Buffer*, FuzzedDataProvider*)>> operations = {
+
+    [](keymaster::Buffer* buf, FuzzedDataProvider*) -> void {
+        // Just reading values, but there's some interesting
+        // integer manipulation here.
+        buf->begin();
+        buf->end();
+    },
+    [](keymaster::Buffer* buf, FuzzedDataProvider*) -> void { buf->Clear(); },
+    [](keymaster::Buffer* buf, FuzzedDataProvider* fdp) -> void {
+        buf->reserve(fdp->ConsumeIntegralInRange<int>(kMinBufferSize, kMaxBufferSize));
+    },
+    [](keymaster::Buffer* buf, FuzzedDataProvider* fdp) -> void {
+        buf->advance_read(fdp->ConsumeIntegral<int>());
+    },
+    [](keymaster::Buffer* buf, FuzzedDataProvider* fdp) -> void {
+        buf->advance_write(fdp->ConsumeIntegral<int>());
+    },
+    [](keymaster::Buffer* buf, FuzzedDataProvider* fdp) -> void {
+        buf->Reinitialize(fdp->ConsumeIntegralInRange<size_t>(kMinBufferSize, kMaxBufferSize));
+    },
+    [](keymaster::Buffer* buf, FuzzedDataProvider* fdp) -> void {
+        size_t buf_size = fdp->ConsumeIntegralInRange<size_t>(kMinBufferSize, kMaxBufferSize);
+        std::unique_ptr<uint8_t[]> in_buf = std::unique_ptr<uint8_t[]>(new uint8_t[buf_size]);
+        buf->Reinitialize(in_buf.get(), buf_size);
+    },
+    [](keymaster::Buffer* buf, FuzzedDataProvider* fdp) -> void {
+        uint16_t buf_size = fdp->ConsumeIntegralInRange<uint16_t>(kMinBufferSize, kMaxBufferSize);
+        std::unique_ptr<uint8_t[]> in_buf = std::unique_ptr<uint8_t[]>(new uint8_t[buf_size]);
+        const uint8_t* data_ptr = in_buf.get();
+        int32_t end = fdp->ConsumeIntegralInRange<int32_t>(0, buf_size);
+        buf->Deserialize(&data_ptr, data_ptr + end);
+    },
+    [](keymaster::Buffer* buf, FuzzedDataProvider* fdp) -> void {
+        uint16_t buf_size = buf->SerializedSize();
+        std::unique_ptr<uint8_t[]> out_buf = std::unique_ptr<uint8_t[]>(new uint8_t[buf_size]);
+        int32_t end = fdp->ConsumeIntegralInRange<int32_t>(0, buf_size);
+        buf->Serialize(out_buf.get(), out_buf.get() + end);
+    },
+    [](keymaster::Buffer* buf, FuzzedDataProvider* fdp) -> void {
+        uint16_t buf_size = fdp->ConsumeIntegralInRange<uint16_t>(kMinBufferSize, kMaxBufferSize);
+        std::vector<uint8_t> in_buf = fdp->ConsumeBytes<uint8_t>(buf_size);
+        buf->write(in_buf.data(), fdp->ConsumeIntegralInRange<int16_t>(0, buf_size));
+    },
+    [](keymaster::Buffer* buf, FuzzedDataProvider* fdp) -> void {
+        uint16_t buf_size = fdp->ConsumeIntegralInRange<uint16_t>(kMinBufferSize, kMaxBufferSize);
+        std::unique_ptr<uint8_t[]> out = std::unique_ptr<uint8_t[]>(new uint8_t[buf_size]);
+        buf->read(out.get(), fdp->ConsumeIntegralInRange<int16_t>(0, buf_size));
+    }};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider fdp(data, size);
+    uint16_t buf_size = fdp.ConsumeIntegralInRange<uint16_t>(kMinBufferSize, kMaxBufferSize);
+    keymaster::Buffer fuzzBuffer(buf_size);
+    for (size_t i = 0; i < kMaxOperations && fdp.remaining_bytes() > 0; i++) {
+        uint8_t op = fdp.ConsumeIntegralInRange<uint8_t>(0, operations.size() - 1);
+        operations[op](&fuzzBuffer, &fdp);
+    }
+    return 0;
+}
diff --git a/tests/fuzzers/message_serializable_fuzz.cpp b/tests/fuzzers/message_serializable_fuzz.cpp
new file mode 100644
index 0000000..11c3ff3
--- /dev/null
+++ b/tests/fuzzers/message_serializable_fuzz.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <functional>
+#include <memory>
+
+#include <keymaster/serializable.h>
+
+#include "fuzzer/FuzzedDataProvider.h"
+#include "serializable_types.h"
+
+static constexpr uint16_t kMinBufferSize = 1;
+static constexpr uint16_t kMaxBufferSize = 2048;
+
+void RunDeserialize(keymaster::Serializable* ser, FuzzedDataProvider* fdp) {
+    uint16_t buf_size = fdp->ConsumeIntegralInRange<uint16_t>(kMinBufferSize, kMaxBufferSize);
+    std::unique_ptr<uint8_t[]> in_buf = std::unique_ptr<uint8_t[]>(new uint8_t[buf_size]);
+    const uint8_t* data_ptr = in_buf.get();
+    // memset((void*) data_ptr, 0x41, buf_size);
+    int32_t end = fdp->ConsumeIntegralInRange<int32_t>(0, buf_size);
+    ser->Deserialize(&data_ptr, data_ptr + end);
+}
+
+void RunSerialize(keymaster::Serializable* ser, FuzzedDataProvider* fdp) {
+    uint16_t buf_size = ser->SerializedSize();
+    std::unique_ptr<uint8_t[]> out_buf = std::unique_ptr<uint8_t[]>(new uint8_t[buf_size]);
+    // memset((void*) out_buf.get(), 0x41, buf_size);
+    int32_t end = fdp->ConsumeIntegralInRange<int32_t>(0, buf_size);
+    ser->Serialize(out_buf.get(), out_buf.get() + end);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider fdp(data, size);
+    std::unique_ptr<keymaster::Serializable> serializable =
+        keymaster::getSerializable(fdp.ConsumeEnum<keymaster::SerializableType>());
+    /*if(fdp.remaining_bytes() > 1) {
+            RunDeserialize(serializable.get(), &fdp);
+    }*/
+    for (size_t i = 0; fdp.remaining_bytes() > 0; i++) {
+        if (fdp.ConsumeBool()) {
+            RunSerialize(serializable.get(), &fdp);
+        } else {
+            RunDeserialize(serializable.get(), &fdp);
+        }
+    }
+    return 0;
+}
diff --git a/tests/fuzzers/serializable_types.h b/tests/fuzzers/serializable_types.h
new file mode 100644
index 0000000..96dc4b3
--- /dev/null
+++ b/tests/fuzzers/serializable_types.h
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <keymaster/android_keymaster_messages.h>
+#include <keymaster/serializable.h>
+
+namespace keymaster {
+enum class SerializableType : uint32_t {
+    SUPPORTED_IMPORT_FORMATS_REQUEST,
+    SUPPORTED_EXPORT_FORMATS_REQUEST,
+    SUPPORTED_BLOCK_MODES_REQUEST,
+    SUPPORTED_PADDING_MODES_REQUEST,
+    SUPPORTED_DIGESTS_REQUEST,
+    SUPPORTED_ALGORITHMS_RESPONSE,
+    SUPPORTED_BLOCK_MODES_RESPONSE,
+    SUPPORTED_PADDING_MODES_RESPONSE,
+    SUPPORTED_DIGESTS_RESPONSE,
+    SUPPORTED_IMPORT_FORMATS_RESPONSE,
+    SUPPORTED_EXPORT_FORMATS_RESPONSE,
+    GENERATE_KEY_REQUEST,
+    GENERATE_KEY_RESPONSE,
+    GET_KEY_CHARACTERISTICS_REQUEST,
+    GET_KEY_CHARACTERISTICS_RESPONSE,
+    BEGIN_OPERATION_REQUEST,
+    BEGIN_OPERATION_RESPONSE,
+    UPDATE_OPERATION_REQUEST,
+    UPDATE_OPERATION_RESPONSE,
+    FINISH_OPERATION_REQUEST,
+    FINISH_OPERATION_RESPONSE,
+    ABORT_OPERATION_REQUEST,
+    ABORT_OPERATION_RESPONSE,
+    ADD_ENTROPY_REQUEST,
+    ADD_ENTROPY_RESPONSE,
+    IMPORT_KEY_REQUEST,
+    IMPORT_KEY_RESPONSE,
+    EXPORT_KEY_REQUEST,
+    EXPORT_KEY_RESPONSE,
+    DELETE_KEY_REQUEST,
+    DELETE_KEY_RESPONSE,
+    DELETE_ALL_KEYS_REQUEST,
+    DELETE_ALL_KEYS_RESPONSE,
+    GET_VERSION_REQUEST,
+    GET_VERSION_RESPONSE,
+    GET_VERSION2_REQUEST,
+    GET_VERSION2_RESPONSE,
+    ATTEST_KEY_REQUEST,
+    ATTEST_KEY_RESPONSE,
+    UPGRADE_KEY_REQUEST,
+    UPGRADE_KEY_RESPONSE,
+    CONFIGURE_REQUEST,
+    CONFIGURE_RESPONSE,
+    HMAC_SHARING_PARAMETERS,
+    HMAC_SHARING_PARAMETERS_ARRAY,
+    GET_HMAC_SHARING_PARAMETERS_RESPONSE,
+    COMPUTE_SHARED_HMAC_REQUEST,
+    COMPUTE_SHARED_HMAC_RESPONSE,
+    IMPORT_WRAPPED_KEY_REQUEST,
+    IMPORT_WRAPPED_KEY_RESPONSE,
+    HARDWARE_AUTH_TOKEN,
+    VERIFICATION_TOKEN,
+    VERIFY_AUTHORIZATION_REQUEST,
+    VERIFY_AUTHORIZATION_RESPONSE,
+    DEVICE_LOCKED_REQUEST,
+    BUFFER,
+    // Libfuzzer needs this to always be the last value
+    kMaxValue = BUFFER
+};
+
+std::unique_ptr<Serializable> getSerializable(SerializableType serType) {
+    switch (serType) {
+    case SerializableType::SUPPORTED_IMPORT_FORMATS_REQUEST:
+        return std::make_unique<SupportedImportFormatsRequest>(kMaxMessageVersion);
+    case SerializableType::SUPPORTED_EXPORT_FORMATS_REQUEST:
+        return std::make_unique<SupportedExportFormatsRequest>(kMaxMessageVersion);
+    case SerializableType::SUPPORTED_BLOCK_MODES_REQUEST:
+        return std::make_unique<SupportedBlockModesRequest>(kMaxMessageVersion);
+    case SerializableType::SUPPORTED_PADDING_MODES_REQUEST:
+        return std::make_unique<SupportedPaddingModesRequest>(kMaxMessageVersion);
+    case SerializableType::SUPPORTED_DIGESTS_REQUEST:
+        return std::make_unique<SupportedDigestsRequest>(kMaxMessageVersion);
+    case SerializableType::SUPPORTED_ALGORITHMS_RESPONSE:
+        return std::make_unique<SupportedAlgorithmsResponse>(kMaxMessageVersion);
+    case SerializableType::SUPPORTED_BLOCK_MODES_RESPONSE:
+        return std::make_unique<SupportedBlockModesResponse>(kMaxMessageVersion);
+    case SerializableType::SUPPORTED_PADDING_MODES_RESPONSE:
+        return std::make_unique<SupportedPaddingModesResponse>(kMaxMessageVersion);
+    case SerializableType::SUPPORTED_DIGESTS_RESPONSE:
+        return std::make_unique<SupportedDigestsResponse>(kMaxMessageVersion);
+    case SerializableType::SUPPORTED_IMPORT_FORMATS_RESPONSE:
+        return std::make_unique<SupportedImportFormatsResponse>(kMaxMessageVersion);
+    case SerializableType::SUPPORTED_EXPORT_FORMATS_RESPONSE:
+        return std::make_unique<SupportedExportFormatsResponse>(kMaxMessageVersion);
+    case SerializableType::GENERATE_KEY_REQUEST:
+        return std::make_unique<GenerateKeyRequest>(kMaxMessageVersion);
+    case SerializableType::GENERATE_KEY_RESPONSE:
+        return std::make_unique<GenerateKeyResponse>(kMaxMessageVersion);
+    case SerializableType::GET_KEY_CHARACTERISTICS_REQUEST:
+        return std::make_unique<GetKeyCharacteristicsRequest>(kMaxMessageVersion);
+    case SerializableType::GET_KEY_CHARACTERISTICS_RESPONSE:
+        return std::make_unique<GetKeyCharacteristicsResponse>(kMaxMessageVersion);
+    case SerializableType::BEGIN_OPERATION_REQUEST:
+        return std::make_unique<BeginOperationRequest>(kMaxMessageVersion);
+    case SerializableType::BEGIN_OPERATION_RESPONSE:
+        return std::make_unique<BeginOperationResponse>(kMaxMessageVersion);
+    case SerializableType::UPDATE_OPERATION_REQUEST:
+        return std::make_unique<UpdateOperationRequest>(kMaxMessageVersion);
+    case SerializableType::UPDATE_OPERATION_RESPONSE:
+        return std::make_unique<UpdateOperationResponse>(kMaxMessageVersion);
+    case SerializableType::FINISH_OPERATION_REQUEST:
+        return std::make_unique<FinishOperationRequest>(kMaxMessageVersion);
+    case SerializableType::FINISH_OPERATION_RESPONSE:
+        return std::make_unique<FinishOperationResponse>(kMaxMessageVersion);
+    case SerializableType::ABORT_OPERATION_REQUEST:
+        return std::make_unique<AbortOperationRequest>(kMaxMessageVersion);
+    case SerializableType::ABORT_OPERATION_RESPONSE:
+        return std::make_unique<AbortOperationResponse>(kMaxMessageVersion);
+    case SerializableType::ADD_ENTROPY_REQUEST:
+        return std::make_unique<AddEntropyRequest>(kMaxMessageVersion);
+    case SerializableType::ADD_ENTROPY_RESPONSE:
+        return std::make_unique<AddEntropyResponse>(kMaxMessageVersion);
+    case SerializableType::IMPORT_KEY_REQUEST:
+        return std::make_unique<ImportKeyRequest>(kMaxMessageVersion);
+    case SerializableType::IMPORT_KEY_RESPONSE:
+        return std::make_unique<ImportKeyResponse>(kMaxMessageVersion);
+    case SerializableType::EXPORT_KEY_REQUEST:
+        return std::make_unique<ExportKeyRequest>(kMaxMessageVersion);
+    case SerializableType::EXPORT_KEY_RESPONSE:
+        return std::make_unique<ExportKeyResponse>(kMaxMessageVersion);
+    case SerializableType::DELETE_KEY_REQUEST:
+        return std::make_unique<DeleteKeyRequest>(kMaxMessageVersion);
+    case SerializableType::DELETE_KEY_RESPONSE:
+        return std::make_unique<DeleteKeyResponse>(kMaxMessageVersion);
+    case SerializableType::DELETE_ALL_KEYS_REQUEST:
+        return std::make_unique<DeleteAllKeysRequest>(kMaxMessageVersion);
+    case SerializableType::DELETE_ALL_KEYS_RESPONSE:
+        return std::make_unique<DeleteAllKeysResponse>(kMaxMessageVersion);
+    case SerializableType::GET_VERSION_REQUEST:
+        // Not versionable
+        return std::make_unique<GetVersionRequest>();
+    case SerializableType::GET_VERSION_RESPONSE:
+        // Not versionable
+        return std::make_unique<GetVersionResponse>();
+    case SerializableType::GET_VERSION2_REQUEST:
+        // Not versionable
+        return std::make_unique<GetVersion2Request>();
+    case SerializableType::GET_VERSION2_RESPONSE:
+        // Not versionable
+        return std::make_unique<GetVersion2Response>();
+    case SerializableType::ATTEST_KEY_REQUEST:
+        return std::make_unique<AttestKeyRequest>(kMaxMessageVersion);
+    case SerializableType::ATTEST_KEY_RESPONSE:
+        return std::make_unique<AttestKeyResponse>(kMaxMessageVersion);
+    case SerializableType::UPGRADE_KEY_REQUEST:
+        return std::make_unique<UpgradeKeyRequest>(kMaxMessageVersion);
+    case SerializableType::UPGRADE_KEY_RESPONSE:
+        return std::make_unique<UpgradeKeyResponse>(kMaxMessageVersion);
+    case SerializableType::CONFIGURE_REQUEST:
+        return std::make_unique<ConfigureRequest>(kMaxMessageVersion);
+    case SerializableType::CONFIGURE_RESPONSE:
+        return std::make_unique<ConfigureResponse>(kMaxMessageVersion);
+    case SerializableType::DEVICE_LOCKED_REQUEST:
+        return std::make_unique<DeviceLockedRequest>(kMaxMessageVersion);
+    case SerializableType::GET_HMAC_SHARING_PARAMETERS_RESPONSE:
+        return std::make_unique<GetHmacSharingParametersResponse>(kMaxMessageVersion);
+    case SerializableType::COMPUTE_SHARED_HMAC_REQUEST:
+        return std::make_unique<ComputeSharedHmacRequest>(kMaxMessageVersion);
+    case SerializableType::COMPUTE_SHARED_HMAC_RESPONSE:
+        return std::make_unique<ComputeSharedHmacResponse>(kMaxMessageVersion);
+    case SerializableType::IMPORT_WRAPPED_KEY_REQUEST:
+        return std::make_unique<ImportWrappedKeyRequest>(kMaxMessageVersion);
+    case SerializableType::IMPORT_WRAPPED_KEY_RESPONSE:
+        return std::make_unique<ImportWrappedKeyResponse>(kMaxMessageVersion);
+    case SerializableType::VERIFY_AUTHORIZATION_REQUEST:
+        return std::make_unique<VerifyAuthorizationRequest>(kMaxMessageVersion);
+    case SerializableType::VERIFY_AUTHORIZATION_RESPONSE:
+        return std::make_unique<VerifyAuthorizationResponse>(kMaxMessageVersion);
+
+    // These are not messages, and expect an empty constructor.
+    case SerializableType::HMAC_SHARING_PARAMETERS:
+        return std::make_unique<HmacSharingParameters>();
+    case SerializableType::HMAC_SHARING_PARAMETERS_ARRAY:
+        return std::make_unique<HmacSharingParametersArray>();
+    case SerializableType::HARDWARE_AUTH_TOKEN:
+        return std::make_unique<HardwareAuthToken>();
+    case SerializableType::VERIFICATION_TOKEN:
+        return std::make_unique<VerificationToken>();
+    case SerializableType::BUFFER:
+        return std::make_unique<Buffer>();
+    }
+}
+}  // namespace keymaster
diff --git a/tests/gtest_main.cpp b/tests/gtest_main.cpp
index 6072749..dfa9357 100644
--- a/tests/gtest_main.cpp
+++ b/tests/gtest_main.cpp
@@ -21,7 +21,7 @@
 int main(int argc, char** argv) {
 #if !defined(OPENSSL_IS_BORINGSSL)
     ERR_load_crypto_strings();
-#endif // not OPENSSL_IS_BORINGSSL
+#endif  // not OPENSSL_IS_BORINGSSL
     ::testing::InitGoogleTest(&argc, argv);
     int result = RUN_ALL_TESTS();
 #if !defined(OPENSSL_IS_BORINGSSL)
@@ -29,6 +29,6 @@
     CRYPTO_cleanup_all_ex_data();
     ERR_remove_thread_state(NULL);
     ERR_free_strings();
-#endif // not OPENSSL_IS_BORINGSSL
+#endif  // not OPENSSL_IS_BORINGSSL
     return result;
 }
diff --git a/tests/hkdf_test.cpp b/tests/hkdf_test.cpp
index 69ddd08..fb210eb 100644
--- a/tests/hkdf_test.cpp
+++ b/tests/hkdf_test.cpp
@@ -37,7 +37,8 @@
 // https://tools.ietf.org/html/rfc5869#appendix-A.
 static const HkdfTest kHkdfTests[] = {
     {
-        "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "000102030405060708090a0b0c",
+        "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+        "000102030405060708090a0b0c",
         "f0f1f2f3f4f5f6f7f8f9",
         "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865",
     },
@@ -52,7 +53,9 @@
         "590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87",
     },
     {
-        "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "", "",
+        "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+        "",
+        "",
         "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8",
     },
 };
diff --git a/tests/hmac_test.cpp b/tests/hmac_test.cpp
index 9802e00..2413380 100644
--- a/tests/hmac_test.cpp
+++ b/tests/hmac_test.cpp
@@ -41,9 +41,9 @@
         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
         {
-            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,
+            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,
         },
     },
     {
@@ -51,9 +51,9 @@
         "46697265666f7820616e64205468756e64657242697264206172652061776573"
         "6f6d652100",
         {
-            0x05, 0x75, 0x9a, 0x9e, 0x70, 0x5e, 0xe7, 0x44, 0xe2, 0x46, 0x4b, 0x92, 0x22, 0x14,
-            0x22, 0xe0, 0x1b, 0x92, 0x8a, 0x0c, 0xfe, 0xf5, 0x49, 0xe9, 0xa7, 0x1b, 0x56, 0x7d,
-            0x1d, 0x29, 0x40, 0x48,
+            0x05, 0x75, 0x9a, 0x9e, 0x70, 0x5e, 0xe7, 0x44, 0xe2, 0x46, 0x4b,
+            0x92, 0x22, 0x14, 0x22, 0xe0, 0x1b, 0x92, 0x8a, 0x0c, 0xfe, 0xf5,
+            0x49, 0xe9, 0xa7, 0x1b, 0x56, 0x7d, 0x1d, 0x29, 0x40, 0x48,
         },
     },
 };
diff --git a/tests/kdf1_test.cpp b/tests/kdf1_test.cpp
index b01143d..5881529 100644
--- a/tests/kdf1_test.cpp
+++ b/tests/kdf1_test.cpp
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#include <keymaster/km_openssl/kdf1.h>
 #include <gtest/gtest.h>
+#include <keymaster/km_openssl/kdf1.h>
 #include <string.h>
 
 #include "android_keymaster_test_utils.h"
diff --git a/tests/kdf2_test.cpp b/tests/kdf2_test.cpp
index c300186..d022c10 100644
--- a/tests/kdf2_test.cpp
+++ b/tests/kdf2_test.cpp
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#include <keymaster/km_openssl/kdf2.h>
 #include <gtest/gtest.h>
+#include <keymaster/km_openssl/kdf2.h>
 #include <string.h>
 
 #include "android_keymaster_test_utils.h"
diff --git a/tests/kdf_test.cpp b/tests/kdf_test.cpp
index 19c96ef..2c5a43f 100644
--- a/tests/kdf_test.cpp
+++ b/tests/kdf_test.cpp
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#include <keymaster/km_openssl/kdf.h>
 #include <gtest/gtest.h>
+#include <keymaster/km_openssl/kdf.h>
 
 namespace keymaster {
 
diff --git a/tests/key_blob_test.cpp b/tests/key_blob_test.cpp
index 5c1458b..35d3aa6 100644
--- a/tests/key_blob_test.cpp
+++ b/tests/key_blob_test.cpp
@@ -21,12 +21,12 @@
 #include <openssl/engine.h>
 #include <openssl/rand.h>
 
-#include <keymaster/authorization_set.h>
 #include <keymaster/android_keymaster_utils.h>
-#include <keymaster/keymaster_tags.h>
+#include <keymaster/authorization_set.h>
 #include <keymaster/key_blob_utils/auth_encrypted_key_blob.h>
 #include <keymaster/key_blob_utils/integrity_assured_key_blob.h>
-#include <keymaster/key_blob_utils/ocb_utils.h>
+#include <keymaster/keymaster_tags.h>
+#include <keymaster/km_openssl/software_random_source.h>
 
 #include "android_keymaster_test_utils.h"
 
@@ -34,14 +34,18 @@
 
 namespace test {
 
-const uint8_t master_key_data[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+namespace {
+
+const uint8_t master_key_data[16] = {};
 const uint8_t key_data[5] = {21, 22, 23, 24, 25};
 
-class KeyBlobTest : public testing::Test {
+}  // namespace
+
+class KeyBlobTest : public testing::Test, public SoftwareRandomSource {
   protected:
     KeyBlobTest()
-        : master_key_(master_key_data, array_length(master_key_data)),
-          key_material_(key_data, array_length(key_data)) {
+        : key_material_(key_data, array_length(key_data)),
+          master_key_(master_key_data, array_length(master_key_data)) {
         hw_enforced_.push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
         hw_enforced_.push_back(TAG_KEY_SIZE, 256);
         hw_enforced_.push_back(TAG_BLOB_USAGE_REQUIREMENTS, KM_BLOB_STANDALONE);
@@ -56,72 +60,83 @@
 
         hidden_.push_back(TAG_ROOT_OF_TRUST, "foo", 3);
         hidden_.push_back(TAG_APPLICATION_ID, "my_app", 6);
-
-        nonce_.reserve(OCB_NONCE_LENGTH);
-        EXPECT_EQ(1, RAND_bytes(nonce_.peek_write(), OCB_NONCE_LENGTH));
-        nonce_.advance_write(OCB_NONCE_LENGTH);
-
-        tag_.reserve(OCB_TAG_LENGTH);
     }
 
-    keymaster_error_t Encrypt() {
-        return OcbEncryptKey(hw_enforced_, sw_enforced_, hidden_, master_key_, key_material_,
-                             nonce_, &ciphertext_, &tag_);
+    keymaster_error_t Encrypt(AuthEncryptedBlobFormat format = AES_GCM_WITH_SW_ENFORCED) {
+        keymaster_error_t error;
+        encrypted_key_ = EncryptKey(key_material_, format, hw_enforced_, sw_enforced_, hidden_,
+                                    master_key_, *this, &error);
+        return error;
     }
 
     keymaster_error_t Decrypt() {
-        return OcbDecryptKey(hw_enforced_, sw_enforced_, hidden_, master_key_, ciphertext_, nonce_,
-                             tag_, &decrypted_plaintext_);
+        keymaster_error_t error;
+        decrypted_plaintext_ = DecryptKey(move(deserialized_key_), hidden_, master_key_, &error);
+        return error;
     }
 
     keymaster_error_t Serialize() {
-        return SerializeAuthEncryptedBlob(ciphertext_, hw_enforced_, sw_enforced_, nonce_, tag_,
-                                          &serialized_blob_);
+        keymaster_error_t error;
+        serialized_blob_ =
+            SerializeAuthEncryptedBlob(encrypted_key_, hw_enforced_, sw_enforced_, &error);
+        return error;
     }
 
     keymaster_error_t Deserialize() {
-        return DeserializeAuthEncryptedBlob(serialized_blob_, &ciphertext_, &hw_enforced_,
-                                            &sw_enforced_, &nonce_, &tag_);
+        keymaster_error_t error;
+        deserialized_key_ = DeserializeAuthEncryptedBlob(serialized_blob_, &error);
+        return error;
     }
 
+    // Encryption inputs
     AuthorizationSet hw_enforced_;
     AuthorizationSet sw_enforced_;
     AuthorizationSet hidden_;
-    Buffer nonce_, tag_;
-
-    KeymasterKeyBlob master_key_;
     KeymasterKeyBlob key_material_;
-    KeymasterKeyBlob ciphertext_;
-    KeymasterKeyBlob decrypted_plaintext_;
+    KeymasterKeyBlob master_key_;
+
+    // Encryption output
+    EncryptedKey encrypted_key_;
+
+    // Serialization output
     KeymasterKeyBlob serialized_blob_;
+
+    // Deserialization output
+    DeserializedKey deserialized_key_;
+
+    // Decryption output.
+    KeymasterKeyBlob decrypted_plaintext_;
 };
 
 TEST_F(KeyBlobTest, EncryptDecrypt) {
-    ASSERT_EQ(KM_ERROR_OK, Encrypt());
-    ASSERT_EQ(KM_ERROR_OK, Serialize());
+    for (auto format : {AES_OCB, AES_GCM_WITH_SW_ENFORCED}) {
+        ASSERT_EQ(KM_ERROR_OK, Encrypt(format));
+        ASSERT_EQ(KM_ERROR_OK, Serialize());
 
-    // key_data shouldn't be anywhere in the blob, ciphertext should.
-    EXPECT_EQ(serialized_blob_.end(), std::search(serialized_blob_.begin(), serialized_blob_.end(),
-                                                  key_material_.begin(), key_material_.end()));
-    EXPECT_NE(serialized_blob_.end(), std::search(serialized_blob_.begin(), serialized_blob_.end(),
-                                                  ciphertext_.begin(), ciphertext_.end()));
+        // key_data shouldn't be anywhere in the blob, ciphertext should.
+        EXPECT_EQ(serialized_blob_.end(),
+                  std::search(serialized_blob_.begin(), serialized_blob_.end(),
+                              key_material_.begin(), key_material_.end()));
+        EXPECT_NE(serialized_blob_.end(),
+                  std::search(serialized_blob_.begin(), serialized_blob_.end(),
+                              encrypted_key_.ciphertext.begin(), encrypted_key_.ciphertext.end()));
 
-    ciphertext_.Clear();
-    nonce_.Clear();
-    tag_.Clear();
-    AuthorizationSet hw2;
-    AuthorizationSet sw2;
+        keymaster_error_t error;
+        DeserializedKey deserialized = DeserializeAuthEncryptedBlob(serialized_blob_, &error);
+        ASSERT_EQ(KM_ERROR_OK, error);
+        EXPECT_EQ(hw_enforced_, deserialized.hw_enforced);
+        switch (format) {
+        case AES_OCB:
+        case AES_GCM_WITH_SW_ENFORCED:
+            EXPECT_EQ(sw_enforced_, deserialized.sw_enforced);
+            break;
+        }
 
-    ASSERT_EQ(KM_ERROR_OK, DeserializeAuthEncryptedBlob(serialized_blob_, &ciphertext_, &hw2, &sw2,
-                                                        &nonce_, &tag_));
-    KeymasterKeyBlob plaintext;
-    OcbDecryptKey(hw2, sw2, hidden_, master_key_, ciphertext_, nonce_, tag_, &plaintext);
+        KeymasterKeyBlob plaintext = DecryptKey(move(deserialized), hidden_, master_key_, &error);
 
-    EXPECT_EQ(hw_enforced_, hw2);
-    EXPECT_EQ(sw_enforced_, sw2);
-
-    ASSERT_EQ(key_material_.key_material_size, plaintext.key_material_size);
-    EXPECT_EQ(0, memcmp(plaintext.begin(), key_material_.begin(), plaintext.key_material_size));
+        ASSERT_EQ(key_material_.size(), plaintext.size());
+        EXPECT_TRUE(std::equal(key_material_.begin(), key_material_.end(), plaintext.begin()));
+    }
 }
 
 TEST_F(KeyBlobTest, WrongKeyLength) {
@@ -139,11 +154,9 @@
     ASSERT_EQ(KM_ERROR_OK, Serialize());
 
     // Find the nonce, then modify it.
-    auto nonce_ptr =
-        std::search(serialized_blob_.begin(), serialized_blob_.end(), nonce_.begin(), nonce_.end());
+    auto nonce_ptr = std::search(serialized_blob_.begin(), serialized_blob_.end(),
+                                 encrypted_key_.nonce.begin(), encrypted_key_.nonce.end());
     ASSERT_NE(nonce_ptr, serialized_blob_.end());
-    EXPECT_EQ(serialized_blob_.end(),
-              std::search(nonce_ptr + 1, serialized_blob_.end(), nonce_.begin(), nonce_.end()));
     (*const_cast<uint8_t*>(nonce_ptr))++;
 
     // Deserialization shouldn't be affected, but decryption should fail.
@@ -155,12 +168,10 @@
     ASSERT_EQ(KM_ERROR_OK, Encrypt());
     ASSERT_EQ(KM_ERROR_OK, Serialize());
 
-    // Find the tag, them modify it.
-    auto tag_ptr =
-        std::search(serialized_blob_.begin(), serialized_blob_.end(), tag_.begin(), tag_.end());
+    // Find the tag, then modify it.
+    auto tag_ptr = std::search(serialized_blob_.begin(), serialized_blob_.end(),
+                               encrypted_key_.tag.begin(), encrypted_key_.tag.end());
     ASSERT_NE(tag_ptr, serialized_blob_.end());
-    EXPECT_EQ(serialized_blob_.end(),
-              std::search(tag_ptr + 1, serialized_blob_.end(), tag_.begin(), tag_.end()));
     (*const_cast<uint8_t*>(tag_ptr))++;
 
     // Deserialization shouldn't be affected, but decryption should fail.
@@ -172,12 +183,11 @@
     ASSERT_EQ(KM_ERROR_OK, Encrypt());
     ASSERT_EQ(KM_ERROR_OK, Serialize());
 
-    // Find the ciphertext, them modify it.
-    auto ciphertext_ptr = std::search(serialized_blob_.begin(), serialized_blob_.end(),
-                                      ciphertext_.begin(), ciphertext_.end());
+    // Find the ciphertext, then modify it.
+    auto ciphertext_ptr =
+        std::search(serialized_blob_.begin(), serialized_blob_.end(),
+                    encrypted_key_.ciphertext.begin(), encrypted_key_.ciphertext.end());
     ASSERT_NE(ciphertext_ptr, serialized_blob_.end());
-    EXPECT_EQ(serialized_blob_.end(), std::search(ciphertext_ptr + 1, serialized_blob_.end(),
-                                                  ciphertext_.begin(), ciphertext_.end()));
     (*const_cast<uint8_t*>(ciphertext_ptr))++;
 
     // Deserialization shouldn't be affected, but decryption should fail.
@@ -194,9 +204,10 @@
 
     // Decrypting with wrong master key should fail.
     ASSERT_EQ(KM_ERROR_OK, Deserialize());
-    ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB,
-              OcbDecryptKey(hw_enforced_, sw_enforced_, hidden_, wrong_master, ciphertext_, nonce_,
-                            tag_, &decrypted_plaintext_));
+    keymaster_error_t error;
+    DecryptKey(move(deserialized_key_), hidden_, wrong_master, &error);
+
+    ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, error);
 }
 
 TEST_F(KeyBlobTest, WrongHwEnforced) {
@@ -212,9 +223,6 @@
         std::search(serialized_blob_.begin(), serialized_blob_.end(), hw_enforced_data.get(),
                     hw_enforced_data.get() + hw_enforced_size);
     ASSERT_NE(serialized_blob_.end(), hw_enforced_ptr);
-    EXPECT_EQ(serialized_blob_.end(),
-              std::search(hw_enforced_ptr + 1, serialized_blob_.end(), hw_enforced_data.get(),
-                          hw_enforced_data.get() + hw_enforced_size));
     (*(const_cast<uint8_t*>(hw_enforced_ptr) + hw_enforced_size - 1))++;
 
     // Deserialization shouldn't be affected, but decryption should fail.
@@ -223,26 +231,25 @@
 }
 
 TEST_F(KeyBlobTest, WrongSwEnforced) {
-    ASSERT_EQ(KM_ERROR_OK, Encrypt());
-    ASSERT_EQ(KM_ERROR_OK, Serialize());
+    for (auto format : {AES_OCB, AES_GCM_WITH_SW_ENFORCED}) {
+        ASSERT_EQ(KM_ERROR_OK, Encrypt(format));
+        ASSERT_EQ(KM_ERROR_OK, Serialize());
 
-    // Find enforced serialization data and modify it.
-    size_t sw_enforced_size = sw_enforced_.SerializedSize();
-    UniquePtr<uint8_t[]> sw_enforced_data(new uint8_t[sw_enforced_size]);
-    sw_enforced_.Serialize(sw_enforced_data.get(), sw_enforced_data.get() + sw_enforced_size);
+        // Find enforced serialization data and modify it.
+        size_t sw_enforced_size = sw_enforced_.SerializedSize();
+        UniquePtr<uint8_t[]> sw_enforced_data(new uint8_t[sw_enforced_size]);
+        sw_enforced_.Serialize(sw_enforced_data.get(), sw_enforced_data.get() + sw_enforced_size);
 
-    auto sw_enforced_ptr =
-        std::search(serialized_blob_.begin(), serialized_blob_.end(), sw_enforced_data.get(),
-                    sw_enforced_data.get() + sw_enforced_size);
-    ASSERT_NE(serialized_blob_.end(), sw_enforced_ptr);
-    EXPECT_EQ(serialized_blob_.end(),
-              std::search(sw_enforced_ptr + 1, serialized_blob_.end(), sw_enforced_data.get(),
-                          sw_enforced_data.get() + sw_enforced_size));
-    (*(const_cast<uint8_t*>(sw_enforced_ptr) + sw_enforced_size - 1))++;
+        auto sw_enforced_ptr =
+            std::search(serialized_blob_.begin(), serialized_blob_.end(), sw_enforced_data.get(),
+                        sw_enforced_data.get() + sw_enforced_size);
+        ASSERT_NE(serialized_blob_.end(), sw_enforced_ptr);
+        (*(const_cast<uint8_t*>(sw_enforced_ptr) + sw_enforced_size - 1))++;
 
-    // Deserialization shouldn't be affected, but decryption should fail.
-    ASSERT_EQ(KM_ERROR_OK, Deserialize());
-    ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Decrypt());
+        // Deserialization shouldn't be affected, but decryption should fail.
+        ASSERT_EQ(KM_ERROR_OK, Deserialize());
+        ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Decrypt());
+    }
 }
 
 TEST_F(KeyBlobTest, EmptyHidden) {
@@ -253,9 +260,9 @@
 
     // Deserialization shouldn't be affected, but decryption should fail.
     ASSERT_EQ(KM_ERROR_OK, Deserialize());
-    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
-              OcbDecryptKey(hw_enforced_, sw_enforced_, wrong_hidden, master_key_, ciphertext_,
-                            nonce_, tag_, &decrypted_plaintext_));
+    keymaster_error_t error;
+    DecryptKey(move(deserialized_key_), wrong_hidden, master_key_, &error);
+    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, error);
 }
 
 TEST_F(KeyBlobTest, WrongRootOfTrust) {
@@ -268,9 +275,9 @@
 
     // Deserialization shouldn't be affected, but decryption should fail.
     ASSERT_EQ(KM_ERROR_OK, Deserialize());
-    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
-              OcbDecryptKey(hw_enforced_, sw_enforced_, wrong_hidden, master_key_, ciphertext_,
-                            nonce_, tag_, &decrypted_plaintext_));
+    keymaster_error_t error;
+    DecryptKey(move(deserialized_key_), wrong_hidden, master_key_, &error);
+    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, error);
 }
 
 TEST_F(KeyBlobTest, WrongAppId) {
@@ -283,9 +290,9 @@
 
     // Deserialization shouldn't be affected, but decryption should fail.
     ASSERT_EQ(KM_ERROR_OK, Deserialize());
-    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
-              OcbDecryptKey(hw_enforced_, sw_enforced_, wrong_hidden, master_key_, ciphertext_,
-                            nonce_, tag_, &decrypted_plaintext_));
+    keymaster_error_t error;
+    DecryptKey(move(deserialized_key_), wrong_hidden, master_key_, &error);
+    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, error);
 }
 
 // This test is especially useful when compiled for 32-bit mode and run under valgrind.
@@ -311,14 +318,13 @@
                   DeserializeIntegrityAssuredBlob(key_blob, hidden_, &key_material_, &hw_enforced_,
                                                   &sw_enforced_));
 
-        // Auth-encrypted OCB blob.
-        keymaster_error_t error = DeserializeAuthEncryptedBlob(
-            key_blob, &ciphertext_, &hw_enforced_, &sw_enforced_, &nonce_, &tag_);
+        // Auth-encrypted blob.
+        keymaster_error_t error;
+        auto deserialized = DeserializeAuthEncryptedBlob(key_blob, &error);
         if (error == KM_ERROR_OK) {
             // It's possible to deserialize successfully.  Decryption should always fail.
             ++deserialize_auth_encrypted_success;
-            error = OcbDecryptKey(hw_enforced_, sw_enforced_, hidden_, master_key_, ciphertext_,
-                                  nonce_, tag_, &decrypted_plaintext_);
+            DecryptKey(move(deserialized), hidden_, master_key_, &error);
         }
         ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, error)
             << "Somehow sucessfully parsed a blob with seed " << now << " at offset " << i;
@@ -336,9 +342,9 @@
               DeserializeIntegrityAssuredBlob(key_blob, hidden_, &key_material_, &hw_enforced_,
                                               &sw_enforced_));
 
-    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
-              DeserializeAuthEncryptedBlob(key_blob, &ciphertext_, &hw_enforced_, &sw_enforced_,
-                                           &nonce_, &tag_));
+    keymaster_error_t error;
+    DeserializeAuthEncryptedBlob(key_blob, &error);
+    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, error);
 }
 
 TEST_F(KeyBlobTest, DupBufferToolarge) {
@@ -353,9 +359,9 @@
               DeserializeIntegrityAssuredBlob(key_blob, hidden_, &key_material_, &hw_enforced_,
                                               &sw_enforced_));
 
-    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
-              DeserializeAuthEncryptedBlob(key_blob, &ciphertext_, &hw_enforced_, &sw_enforced_,
-                                           &nonce_, &tag_));
+    keymaster_error_t error;
+    DeserializeAuthEncryptedBlob(key_blob, &error);
+    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, error);
 }
 
 }  // namespace test
diff --git a/tests/keymaster_enforcement_test.cpp b/tests/keymaster_enforcement_test.cpp
index d446b32..341f0d7 100644
--- a/tests/keymaster_enforcement_test.cpp
+++ b/tests/keymaster_enforcement_test.cpp
@@ -27,9 +27,9 @@
 namespace keymaster {
 namespace test {
 
-class TestKeymasterEnforcement : public SoftKeymasterEnforcement {
+class EnforcementTestKeymasterEnforcement : public SoftKeymasterEnforcement {
   public:
-    TestKeymasterEnforcement()
+    EnforcementTestKeymasterEnforcement()
         : SoftKeymasterEnforcement(3, 3), current_time_(10000), report_token_valid_(true) {}
 
     keymaster_error_t AuthorizeOperation(const keymaster_purpose_t purpose, const km_id_t keyid,
@@ -82,7 +82,7 @@
     }
     virtual ~KeymasterBaseTest() {}
 
-    TestKeymasterEnforcement kmen;
+    EnforcementTestKeymasterEnforcement kmen;
 
     tm past_tm;
     tm* future_tm;
@@ -107,8 +107,10 @@
 
 TEST_F(KeymasterBaseTest, TestInvalidActiveTime) {
     keymaster_key_param_t params[] = {
-        Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
-        Authorization(TAG_NO_AUTH_REQUIRED), Authorization(TAG_ACTIVE_DATETIME, future_time),
+        Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+        Authorization(TAG_NO_AUTH_REQUIRED),
+        Authorization(TAG_ACTIVE_DATETIME, future_time),
     };
 
     AuthorizationSet auth_set(params, array_length(params));
@@ -123,7 +125,8 @@
 
 TEST_F(KeymasterBaseTest, TestValidActiveTime) {
     keymaster_key_param_t params[] = {
-        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_ACTIVE_DATETIME, past_time),
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+        Authorization(TAG_ACTIVE_DATETIME, past_time),
     };
 
     AuthorizationSet auth_set(params, array_length(params));
@@ -135,7 +138,8 @@
 
 TEST_F(KeymasterBaseTest, TestInvalidOriginationExpireTime) {
     keymaster_key_param_t params[] = {
-        Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+        Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
         Authorization(TAG_ORIGINATION_EXPIRE_DATETIME, past_time),
     };
 
@@ -248,7 +252,8 @@
 
 TEST_F(KeymasterBaseTest, TestInvalidMaxOps) {
     keymaster_key_param_t params[] = {
-        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+        Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
         Authorization(TAG_MAX_USES_PER_BOOT, 4),
     };
 
@@ -271,7 +276,8 @@
 
 TEST_F(KeymasterBaseTest, TestOverFlowMaxOpsTable) {
     keymaster_key_param_t params[] = {
-        Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+        Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
         Authorization(TAG_MAX_USES_PER_BOOT, 2),
     };
 
@@ -311,7 +317,8 @@
 
 TEST_F(KeymasterBaseTest, TestInvalidTimeBetweenOps) {
     keymaster_key_param_t params[] = {
-        Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+        Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
         Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 10),
     };
 
@@ -334,7 +341,8 @@
 
 TEST_F(KeymasterBaseTest, TestValidTimeBetweenOps) {
     keymaster_key_param_t params[] = {
-        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+        Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
         Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 2),
     };
 
@@ -455,7 +463,8 @@
 TEST_F(KeymasterBaseTest, TestPubkeyOptTimeoutTableOverflow) {
     keymaster_key_param_t params[] = {
         Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
-        Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 4), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+        Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 4),
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
     };
 
     AuthorizationSet auth_set(params, array_length(params));
diff --git a/tests/nist_curve_key_exchange_test.cpp b/tests/nist_curve_key_exchange_test.cpp
index 270f231..798c91c 100644
--- a/tests/nist_curve_key_exchange_test.cpp
+++ b/tests/nist_curve_key_exchange_test.cpp
@@ -29,8 +29,6 @@
 namespace keymaster {
 namespace test {
 
-StdoutLogger logger;
-
 static const keymaster_ec_curve_t kEcCurves[] = {KM_EC_CURVE_P_224, KM_EC_CURVE_P_256,
                                                  KM_EC_CURVE_P_384, KM_EC_CURVE_P_521};
 
@@ -69,7 +67,7 @@
  * a point not on the curve.)
  * The expected result of such a protocol should be that the
  * key agreement fails and returns an error.
-*/
+ */
 static const char* kInvalidPublicKeys[] = {
     "04"  // uncompressed public key
     "deadbeef7f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287"
@@ -151,9 +149,10 @@
         "46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b",
     },
     {
-        KM_EC_CURVE_P_256, "04"
-                           "809f04289c64348c01515eb03d5ce7ac1a8cb9498f5caa50197e58d43a86a7ae"
-                           "b29d84e811197f25eba8f5194092cb6ff440e26d4421011372461f579271cda3",
+        KM_EC_CURVE_P_256,
+        "04"
+        "809f04289c64348c01515eb03d5ce7ac1a8cb9498f5caa50197e58d43a86a7ae"
+        "b29d84e811197f25eba8f5194092cb6ff440e26d4421011372461f579271cda3",
         // https://tools.ietf.org/html/rfc5915
         "30770201010420"  // DER-encodeded EC private key header
         "38f65d6dce47676044d58ce5139582d568f64bb16098d179dbab07741dd5caf5"  // private key
@@ -164,9 +163,10 @@
         "057d636096cb80b67a8c038c890e887d1adfa4195e9b3ce241c8a778c59cda67",
     },
     {
-        KM_EC_CURVE_P_256, "04"
-                           "df3989b9fa55495719b3cf46dccd28b5153f7808191dd518eff0c3cff2b705ed"
-                           "422294ff46003429d739a33206c8752552c8ba54a270defc06e221e0feaf6ac4",
+        KM_EC_CURVE_P_256,
+        "04"
+        "df3989b9fa55495719b3cf46dccd28b5153f7808191dd518eff0c3cff2b705ed"
+        "422294ff46003429d739a33206c8752552c8ba54a270defc06e221e0feaf6ac4",
         // https://tools.ietf.org/html/rfc5915
         "30770201010420"  // DER-encodeded EC private key header
         "207c43a79bfee03db6f4b944f53d2fb76cc49ef1c9c4d34d51b6c65c4db6932d"  // private key
diff --git a/tests/test_keys.h b/tests/test_keys.h
new file mode 100644
index 0000000..015b3ba
--- /dev/null
+++ b/tests/test_keys.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+unsigned char rsa_privkey_pk8_der[] = {
+    0x30, 0x82, 0x02, 0x75, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+    0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x02, 0x5f, 0x30, 0x82, 0x02, 0x5b, 0x02, 0x01,
+    0x00, 0x02, 0x81, 0x81, 0x00, 0xc6, 0x09, 0x54, 0x09, 0x04, 0x7d, 0x86, 0x34, 0x81, 0x2d, 0x5a,
+    0x21, 0x81, 0x76, 0xe4, 0x5c, 0x41, 0xd6, 0x0a, 0x75, 0xb1, 0x39, 0x01, 0xf2, 0x34, 0x22, 0x6c,
+    0xff, 0xe7, 0x76, 0x52, 0x1c, 0x5a, 0x77, 0xb9, 0xe3, 0x89, 0x41, 0x7b, 0x71, 0xc0, 0xb6, 0xa4,
+    0x4d, 0x13, 0xaf, 0xe4, 0xe4, 0xa2, 0x80, 0x5d, 0x46, 0xc9, 0xda, 0x29, 0x35, 0xad, 0xb1, 0xff,
+    0x0c, 0x1f, 0x24, 0xea, 0x06, 0xe6, 0x2b, 0x20, 0xd7, 0x76, 0x43, 0x0a, 0x4d, 0x43, 0x51, 0x57,
+    0x23, 0x3c, 0x6f, 0x91, 0x67, 0x83, 0xc3, 0x0e, 0x31, 0x0f, 0xcb, 0xd8, 0x9b, 0x85, 0xc2, 0xd5,
+    0x67, 0x71, 0x16, 0x97, 0x85, 0xac, 0x12, 0xbc, 0xa2, 0x44, 0xab, 0xda, 0x72, 0xbf, 0xb1, 0x9f,
+    0xc4, 0x4d, 0x27, 0xc8, 0x1e, 0x1d, 0x92, 0xde, 0x28, 0x4f, 0x40, 0x61, 0xed, 0xfd, 0x99, 0x28,
+    0x07, 0x45, 0xea, 0x6d, 0x25, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x81, 0x80, 0x1b, 0xe0, 0xf0,
+    0x4d, 0x9c, 0xae, 0x37, 0x18, 0x69, 0x1f, 0x03, 0x53, 0x38, 0x30, 0x8e, 0x91, 0x56, 0x4b, 0x55,
+    0x89, 0x9f, 0xfb, 0x50, 0x84, 0xd2, 0x46, 0x0e, 0x66, 0x30, 0x25, 0x7e, 0x05, 0xb3, 0xce, 0xab,
+    0x02, 0x97, 0x2d, 0xfa, 0xbc, 0xd6, 0xce, 0x5f, 0x6e, 0xe2, 0x58, 0x9e, 0xb6, 0x79, 0x11, 0xed,
+    0x0f, 0xac, 0x16, 0xe4, 0x3a, 0x44, 0x4b, 0x8c, 0x86, 0x1e, 0x54, 0x4a, 0x05, 0x93, 0x36, 0x57,
+    0x72, 0xf8, 0xba, 0xf6, 0xb2, 0x2f, 0xc9, 0xe3, 0xc5, 0xf1, 0x02, 0x4b, 0x06, 0x3a, 0xc0, 0x80,
+    0xa7, 0xb2, 0x23, 0x4c, 0xf8, 0xae, 0xe8, 0xf6, 0xc4, 0x7b, 0xbf, 0x4f, 0xd3, 0xac, 0xe7, 0x24,
+    0x02, 0x90, 0xbe, 0xf1, 0x6c, 0x0b, 0x3f, 0x7f, 0x3c, 0xdd, 0x64, 0xce, 0x3a, 0xb5, 0x91, 0x2c,
+    0xf6, 0xe3, 0x2f, 0x39, 0xab, 0x18, 0x83, 0x58, 0xaf, 0xcc, 0xcd, 0x80, 0x81, 0x02, 0x41, 0x00,
+    0xe4, 0xb4, 0x9e, 0xf5, 0x0f, 0x76, 0x5d, 0x3b, 0x24, 0xdd, 0xe0, 0x1a, 0xce, 0xaa, 0xf1, 0x30,
+    0xf2, 0xc7, 0x66, 0x70, 0xa9, 0x1a, 0x61, 0xae, 0x08, 0xaf, 0x49, 0x7b, 0x4a, 0x82, 0xbe, 0x6d,
+    0xee, 0x8f, 0xcd, 0xd5, 0xe3, 0xf7, 0xba, 0x1c, 0xfb, 0x1f, 0x0c, 0x92, 0x6b, 0x88, 0xf8, 0x8c,
+    0x92, 0xbf, 0xab, 0x13, 0x7f, 0xba, 0x22, 0x85, 0x22, 0x7b, 0x83, 0xc3, 0x42, 0xff, 0x7c, 0x55,
+    0x02, 0x41, 0x00, 0xdd, 0xab, 0xb5, 0x83, 0x9c, 0x4c, 0x7f, 0x6b, 0xf3, 0xd4, 0x18, 0x32, 0x31,
+    0xf0, 0x05, 0xb3, 0x1a, 0xa5, 0x8a, 0xff, 0xdd, 0xa5, 0xc7, 0x9e, 0x4c, 0xce, 0x21, 0x7f, 0x6b,
+    0xc9, 0x30, 0xdb, 0xe5, 0x63, 0xd4, 0x80, 0x70, 0x6c, 0x24, 0xe9, 0xeb, 0xfc, 0xab, 0x28, 0xa6,
+    0xcd, 0xef, 0xd3, 0x24, 0xb7, 0x7e, 0x1b, 0xf7, 0x25, 0x1b, 0x70, 0x90, 0x92, 0xc2, 0x4f, 0xf5,
+    0x01, 0xfd, 0x91, 0x02, 0x40, 0x23, 0xd4, 0x34, 0x0e, 0xda, 0x34, 0x45, 0xd8, 0xcd, 0x26, 0xc1,
+    0x44, 0x11, 0xda, 0x6f, 0xdc, 0xa6, 0x3c, 0x1c, 0xcd, 0x4b, 0x80, 0xa9, 0x8a, 0xd5, 0x2b, 0x78,
+    0xcc, 0x8a, 0xd8, 0xbe, 0xb2, 0x84, 0x2c, 0x1d, 0x28, 0x04, 0x05, 0xbc, 0x2f, 0x6c, 0x1b, 0xea,
+    0x21, 0x4a, 0x1d, 0x74, 0x2a, 0xb9, 0x96, 0xb3, 0x5b, 0x63, 0xa8, 0x2a, 0x5e, 0x47, 0x0f, 0xa8,
+    0x8d, 0xbf, 0x82, 0x3c, 0xdd, 0x02, 0x40, 0x1b, 0x7b, 0x57, 0x44, 0x9a, 0xd3, 0x0d, 0x15, 0x18,
+    0x24, 0x9a, 0x5f, 0x56, 0xbb, 0x98, 0x29, 0x4d, 0x4b, 0x6a, 0xc1, 0x2f, 0xfc, 0x86, 0x94, 0x04,
+    0x97, 0xa5, 0xa5, 0x83, 0x7a, 0x6c, 0xf9, 0x46, 0x26, 0x2b, 0x49, 0x45, 0x26, 0xd3, 0x28, 0xc1,
+    0x1e, 0x11, 0x26, 0x38, 0x0f, 0xde, 0x04, 0xc2, 0x4f, 0x91, 0x6d, 0xec, 0x25, 0x08, 0x92, 0xdb,
+    0x09, 0xa6, 0xd7, 0x7c, 0xdb, 0xa3, 0x51, 0x02, 0x40, 0x77, 0x62, 0xcd, 0x8f, 0x4d, 0x05, 0x0d,
+    0xa5, 0x6b, 0xd5, 0x91, 0xad, 0xb5, 0x15, 0xd2, 0x4d, 0x7c, 0xcd, 0x32, 0xcc, 0xa0, 0xd0, 0x5f,
+    0x86, 0x6d, 0x58, 0x35, 0x14, 0xbd, 0x73, 0x24, 0xd5, 0xf3, 0x36, 0x45, 0xe8, 0xed, 0x8b, 0x4a,
+    0x1c, 0xb3, 0xcc, 0x4a, 0x1d, 0x67, 0x98, 0x73, 0x99, 0xf2, 0xa0, 0x9f, 0x5b, 0x3f, 0xb6, 0x8c,
+    0x88, 0xd5, 0xe5, 0xd9, 0x0a, 0xc3, 0x34, 0x92, 0xd6};
+unsigned int rsa_privkey_pk8_der_len = 633;
+
+unsigned char ec_privkey_pk8_der[] = {
+    0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
+    0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02,
+    0x01, 0x01, 0x04, 0x20, 0x73, 0x7c, 0x2e, 0xcd, 0x7b, 0x8d, 0x19, 0x40, 0xbf, 0x29, 0x30, 0xaa,
+    0x9b, 0x4e, 0xd3, 0xff, 0x94, 0x1e, 0xed, 0x09, 0x36, 0x6b, 0xc0, 0x32, 0x99, 0x98, 0x64, 0x81,
+    0xf3, 0xa4, 0xd8, 0x59, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0xbf, 0x85, 0xd7, 0x72, 0x0d, 0x07,
+    0xc2, 0x54, 0x61, 0x68, 0x3b, 0xc6, 0x48, 0xb4, 0x77, 0x8a, 0x9a, 0x14, 0xdd, 0x8a, 0x02, 0x4e,
+    0x3b, 0xdd, 0x8c, 0x7d, 0xdd, 0x9a, 0xb2, 0xb5, 0x28, 0xbb, 0xc7, 0xaa, 0x1b, 0x51, 0xf1, 0x4e,
+    0xbb, 0xbb, 0x0b, 0xd0, 0xce, 0x21, 0xbc, 0xc4, 0x1c, 0x6e, 0xb0, 0x00, 0x83, 0xcf, 0x33, 0x76,
+    0xd1, 0x1f, 0xd4, 0x49, 0x49, 0xe0, 0xb2, 0x18, 0x3b, 0xfe};
+unsigned int ec_privkey_pk8_der_len = 138;
diff --git a/tests/wrapped_key_test.cpp b/tests/wrapped_key_test.cpp
index 271b2cc..cb9e7d2 100644
--- a/tests/wrapped_key_test.cpp
+++ b/tests/wrapped_key_test.cpp
@@ -66,7 +66,6 @@
 TEST(WrappedKeyTest, Simple) {
 
     KeymasterKeyBlob asn1;
-    size_t asn1_len;
 
     KeymasterBlob iv = {reinterpret_cast<const uint8_t*>(test_iv.c_str()), test_iv.size()};
     KeymasterKeyBlob tk = {reinterpret_cast<const uint8_t*>(test_transit_key.c_str()),