Project import
diff --git a/keymaster/.clang-format b/keymaster/.clang-format
new file mode 100644
index 0000000..5747e19
--- /dev/null
+++ b/keymaster/.clang-format
@@ -0,0 +1,10 @@
+BasedOnStyle: LLVM
+IndentWidth: 4
+UseTab: Never
+BreakBeforeBraces: Attach
+AllowShortFunctionsOnASingleLine: Inline
+AllowShortIfStatementsOnASingleLine: false
+IndentCaseLabels: false
+ColumnLimit: 100
+PointerBindsToType: true
+SpacesBeforeTrailingComments: 2
diff --git a/keymaster/Android.mk b/keymaster/Android.mk
new file mode 100644
index 0000000..233ed95
--- /dev/null
+++ b/keymaster/Android.mk
@@ -0,0 +1,180 @@
+# Copyright (C) 2014 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.
+
+LOCAL_PATH := $(call my-dir)
+
+###
+# libkeymaster_messages contains just the code necessary to communicate with a
+# AndroidKeymaster implementation, e.g. one running in TrustZone.
+##
+include $(CLEAR_VARS)
+LOCAL_MODULE:= libkeymaster_messages
+LOCAL_SRC_FILES:= \
+ android_keymaster_messages.cpp \
+ android_keymaster_utils.cpp \
+ authorization_set.cpp \
+ keymaster_tags.cpp \
+ logger.cpp \
+ serializable.cpp
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/include
+LOCAL_CFLAGS = -Wall -Werror -Wunused -DKEYMASTER_NAME_TAGS
+LOCAL_CLANG := true
+# TODO(krasin): reenable coverage flags, when the new Clang toolchain is released.
+# Currently, if enabled, these flags will cause an internal error in Clang.
+LOCAL_CLANG_CFLAGS += -fno-sanitize-coverage=edge,indirect-calls,8bit-counters,trace-cmp
+LOCAL_MODULE_TAGS := optional
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+include $(BUILD_SHARED_LIBRARY)
+
+###
+# libkeymaster1 contains almost everything needed for a keymaster1
+# implementation, lacking only a subclass of the (abstract) KeymasterContext
+# class to provide environment-specific services and a wrapper to translate from
+# the function-based keymaster HAL API to the message-based AndroidKeymaster API.
+###
+include $(CLEAR_VARS)
+LOCAL_MODULE:= libkeymaster1
+LOCAL_SRC_FILES:= \
+ aes_key.cpp \
+ aes_operation.cpp \
+ android_keymaster.cpp \
+ android_keymaster_messages.cpp \
+ android_keymaster_utils.cpp \
+ asymmetric_key.cpp \
+ asymmetric_key_factory.cpp \
+ attestation_record.cpp \
+ auth_encrypted_key_blob.cpp \
+ ec_key.cpp \
+ ec_key_factory.cpp \
+ ecdsa_operation.cpp \
+ ecies_kem.cpp \
+ hkdf.cpp \
+ hmac.cpp \
+ hmac_key.cpp \
+ hmac_operation.cpp \
+ integrity_assured_key_blob.cpp \
+ iso18033kdf.cpp \
+ kdf.cpp \
+ key.cpp \
+ keymaster_enforcement.cpp \
+ nist_curve_key_exchange.cpp \
+ ocb.c \
+ ocb_utils.cpp \
+ openssl_err.cpp \
+ openssl_utils.cpp \
+ operation.cpp \
+ operation_table.cpp \
+ rsa_key.cpp \
+ rsa_key_factory.cpp \
+ rsa_operation.cpp \
+ symmetric_key.cpp
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/include
+LOCAL_SHARED_LIBRARIES := libcrypto libkeymaster_messages
+LOCAL_CFLAGS = -Wall -Werror -Wunused
+LOCAL_CLANG := true
+LOCAL_CLANG_CFLAGS += -Wno-error=unused-const-variable -Wno-error=unused-private-field
+# TODO(krasin): reenable coverage flags, when the new Clang toolchain is released.
+# Currently, if enabled, these flags will cause an internal error in Clang.
+LOCAL_CLANG_CFLAGS += -fno-sanitize-coverage=edge,indirect-calls,8bit-counters,trace-cmp
+# Ignore benigh warnings for now.
+LOCAL_CLANG_CFLAGS += -Wno-error=unused-private-field
+LOCAL_MODULE_TAGS := optional
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+include $(BUILD_SHARED_LIBRARY)
+
+
+###
+# libsoftkeymaster provides a software-based keymaster HAL implementation.
+# This is used by keystore as a fallback for when the hardware keymaster does
+# not support the request.
+###
+include $(CLEAR_VARS)
+LOCAL_MODULE := libsoftkeymasterdevice
+LOCAL_SRC_FILES := \
+ ec_keymaster0_key.cpp \
+ ec_keymaster1_key.cpp \
+ ecdsa_keymaster1_operation.cpp \
+ keymaster0_engine.cpp \
+ keymaster1_engine.cpp \
+ rsa_keymaster0_key.cpp \
+ rsa_keymaster1_key.cpp \
+ rsa_keymaster1_operation.cpp \
+ soft_keymaster_context.cpp \
+ soft_keymaster_device.cpp \
+ soft_keymaster_logger.cpp
+LOCAL_C_INCLUDES := \
+ system/security/keystore \
+ $(LOCAL_PATH)/include
+LOCAL_CFLAGS = -Wall -Werror -Wunused
+LOCAL_CLANG := true
+LOCAL_CLANG_CFLAGS += -Wno-error=unused-const-variable -Wno-error=unused-private-field
+# TODO(krasin): reenable coverage flags, when the new Clang toolchain is released.
+# Currently, if enabled, these flags will cause an internal error in Clang.
+LOCAL_CLANG_CFLAGS += -fno-sanitize-coverage=edge,indirect-calls,8bit-counters,trace-cmp
+LOCAL_SHARED_LIBRARIES := libkeymaster_messages libkeymaster1 liblog libcrypto
+LOCAL_MODULE_TAGS := optional
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+include $(BUILD_SHARED_LIBRARY)
+
+###
+# libkeymasterfiles is an empty library that exports all of the files in keymaster as includes.
+###
+include $(CLEAR_VARS)
+LOCAL_MODULE := libkeymasterfiles
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+ $(LOCAL_PATH) \
+ $(LOCAL_PATH)/include
+LOCAL_MODULE_TAGS := optional
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+include $(BUILD_STATIC_LIBRARY)
+
+# Unit tests for libkeymaster
+include $(CLEAR_VARS)
+LOCAL_MODULE := keymaster_tests
+LOCAL_SRC_FILES := \
+ android_keymaster_messages_test.cpp \
+ android_keymaster_test.cpp \
+ android_keymaster_test_utils.cpp \
+ attestation_record_test.cpp \
+ authorization_set_test.cpp \
+ hkdf_test.cpp \
+ hmac_test.cpp \
+ kdf1_test.cpp \
+ kdf2_test.cpp \
+ kdf_test.cpp \
+ key_blob_test.cpp \
+ keymaster_enforcement_test.cpp
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/include
+LOCAL_CFLAGS = -Wall -Werror -Wunused -DKEYMASTER_NAME_TAGS
+LOCAL_CLANG := true
+LOCAL_CLANG_CFLAGS += -Wno-error=unused-const-variable -Wno-error=unused-private-field
+# TODO(krasin): reenable coverage flags, when the new Clang toolchain is released.
+# Currently, if enabled, these flags will cause an internal error in Clang.
+LOCAL_CLANG_CFLAGS += -fno-sanitize-coverage=edge,indirect-calls,8bit-counters,trace-cmp
+LOCAL_MODULE_TAGS := tests
+LOCAL_SHARED_LIBRARIES := \
+ libsoftkeymasterdevice \
+ libkeymaster_messages \
+ libkeymaster1 \
+ libcrypto \
+ libsoftkeymaster
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+include $(BUILD_NATIVE_TEST)
diff --git a/keymaster/List.h b/keymaster/List.h
new file mode 100644
index 0000000..403cd7f
--- /dev/null
+++ b/keymaster/List.h
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Templated list class. Normally we'd use STL, but we don't have that.
+// This class mimics STL's interfaces.
+//
+// Objects are copied into the list with the '=' operator or with copy-
+// construction, so if the compiler's auto-generated versions won't work for
+// you, define your own.
+//
+// The only class you want to use from here is "List".
+//
+#ifndef _LIBS_UTILS_LIST_H
+#define _LIBS_UTILS_LIST_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace android {
+
+/*
+ * Doubly-linked list. Instantiate with "List<MyClass> myList".
+ *
+ * Objects added to the list are copied using the assignment operator,
+ * so this must be defined.
+ */
+template<typename T>
+class List
+{
+protected:
+ /*
+ * One element in the list.
+ */
+ class _Node {
+ public:
+ explicit _Node(const T& val) : mVal(val) {}
+ ~_Node() {}
+ inline T& getRef() { return mVal; }
+ inline const T& getRef() const { return mVal; }
+ inline _Node* getPrev() const { return mpPrev; }
+ inline _Node* getNext() const { return mpNext; }
+ inline void setVal(const T& val) { mVal = val; }
+ inline void setPrev(_Node* ptr) { mpPrev = ptr; }
+ inline void setNext(_Node* ptr) { mpNext = ptr; }
+ private:
+ friend class List;
+ friend class _ListIterator;
+ T mVal;
+ _Node* mpPrev;
+ _Node* mpNext;
+ };
+
+ /*
+ * Iterator for walking through the list.
+ */
+
+ template <typename TYPE>
+ struct CONST_ITERATOR {
+ typedef _Node const * NodePtr;
+ typedef const TYPE Type;
+ };
+
+ 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;
+
+ explicit _ListIterator(_NodePtr ptr) : mpNode(ptr) {}
+
+ 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) {}
+
+
+ /*
+ * Dereference operator. Used to get at the juicy insides.
+ */
+ _Type& operator*() const { return mpNode->getRef(); }
+ _Type* operator->() const { return &(mpNode->getRef()); }
+
+ /*
+ * Iterator comparison.
+ */
+ 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; }
+
+ /*
+ * Incr/decr, used to move through the list.
+ */
+ inline _Iter& operator++() { // pre-increment
+ mpNode = mpNode->getNext();
+ return *this;
+ }
+ const _Iter operator++(int) { // post-increment
+ _Iter tmp(*this);
+ mpNode = mpNode->getNext();
+ return tmp;
+ }
+ inline _Iter& operator--() { // pre-increment
+ mpNode = mpNode->getPrev();
+ return *this;
+ }
+ const _Iter operator--(int) { // post-increment
+ _Iter tmp(*this);
+ mpNode = mpNode->getPrev();
+ return tmp;
+ }
+
+ inline _NodePtr getNode() const { return mpNode; }
+
+ _NodePtr mpNode; /* should be private, but older gcc fails */
+ private:
+ friend class List;
+ };
+
+public:
+ List() {
+ prep();
+ }
+ List(const List<T>& src) { // copy-constructor
+ prep();
+ insert(begin(), src.begin(), src.end());
+ }
+ virtual ~List() {
+ clear();
+ delete[] (unsigned char*) mpMiddle;
+ }
+
+ typedef _ListIterator<T, NON_CONST_ITERATOR> iterator;
+ typedef _ListIterator<T, CONST_ITERATOR> const_iterator;
+
+ List<T>& operator=(const List<T>& right);
+
+ /* returns true if the list is empty */
+ inline bool empty() const { return mpMiddle->getNext() == mpMiddle; }
+
+ /* return #of elements in list */
+ 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 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));
+ }
+
+ /* 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 _Node(val); // alloc & copy-construct
+ newNode->setNext(posn.getNode());
+ newNode->setPrev(posn.getNode()->getPrev());
+ posn.getNode()->getPrev()->setNext(newNode);
+ posn.getNode()->setPrev(newNode);
+ return iterator(newNode);
+ }
+
+ /* insert a range of elements before the current node */
+ void insert(iterator posn, const_iterator first, const_iterator last) {
+ for ( ; first != last; ++first)
+ insert(posn, *first);
+ }
+
+ /* remove one entry; returns iterator at next node */
+ iterator erase(iterator posn) {
+ _Node* pNext = posn.getNode()->getNext();
+ _Node* pPrev = posn.getNode()->getPrev();
+ pPrev->setNext(pNext);
+ pNext->setPrev(pPrev);
+ delete posn.getNode();
+ return iterator(pNext);
+ }
+
+ /* remove a range of elements */
+ iterator erase(iterator first, iterator last) {
+ while (first != last)
+ erase(first++); // don't erase than incr later!
+ return iterator(last);
+ }
+
+ /* remove all contents of the list */
+ void clear() {
+ _Node* pCurrent = mpMiddle->getNext();
+ _Node* pNext;
+
+ while (pCurrent != mpMiddle) {
+ pNext = pCurrent->getNext();
+ delete pCurrent;
+ pCurrent = pNext;
+ }
+ mpMiddle->setPrev(mpMiddle);
+ mpMiddle->setNext(mpMiddle);
+ }
+
+ /*
+ * Measure the distance between two iterators. On exist, "first"
+ * 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
+ * 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
+ {
+ ptrdiff_t count = 0;
+ while (first != last) {
+ ++first;
+ ++count;
+ }
+ return count;
+ }
+
+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
+ * might have side-effects or require arguments. So, we do this
+ * slightly uncouth storage alloc.
+ */
+ void prep() {
+ mpMiddle = (_Node*) new unsigned char[sizeof(_Node)];
+ mpMiddle->setPrev(mpMiddle);
+ mpMiddle->setNext(mpMiddle);
+ }
+
+ /*
+ * This node plays the role of "pointer to head" and "pointer to tail".
+ * It sits in the middle of a circular list of nodes. The iterator
+ * runs around the circle until it encounters this one.
+ */
+ _Node* mpMiddle;
+};
+
+/*
+ * Assignment operator.
+ *
+ * The simplest way to do this would be to clear out the target list and
+ * 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
+ 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
+ else
+ insert(lastDst, firstSrc, lastSrc); // copy remaining over
+ return *this;
+}
+
+}; // namespace android
+
+#endif // _LIBS_UTILS_LIST_H
diff --git a/keymaster/MODULE_LICENSE_APACHE2 b/keymaster/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/keymaster/MODULE_LICENSE_APACHE2
diff --git a/keymaster/Makefile b/keymaster/Makefile
new file mode 100644
index 0000000..fc8a540
--- /dev/null
+++ b/keymaster/Makefile
@@ -0,0 +1,381 @@
+#####
+# 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/gtest
+
+INCLUDES=$(foreach dir,$(SUBS),-I $(BASE)/$(dir)/include) \
+ -I $(BASE)/libnativehelper/include/nativehelper \
+ -I $(GTEST) -Iinclude -I$(BASE)/../boringssl/include
+
+ifdef FORCE_32_BIT
+ARCH_FLAGS = -m32
+endif
+
+ifdef USE_CLANG
+CC=/usr/bin/clang
+CXX=/usr/bin/clang
+CXXFLAGS +=-std=c++11 -DKEYMASTER_CLANG_TEST_BUILD
+CFLAGS += -DKEYMASTER_CLANG_TEST_BUILD
+else
+CXXFLAGS +=-std=c++0x -fprofile-arcs -ftest-coverage
+CFLAGS += -fprofile-arcs -ftest-coverage
+endif
+
+LDFLAGS += $(ARCH_FLAGS)
+CPPFLAGS = $(INCLUDES) -g -O0 -MD -MP
+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)
+
+# Uncomment to enable debug logging.
+# CXXFLAGS += -DDEBUG
+
+LDLIBS=-L$(BASE)/../boringssl/build/crypto -lcrypto -lpthread -lstdc++ -lgcov
+
+CPPSRCS=\
+ aes_key.cpp \
+ aes_operation.cpp \
+ android_keymaster.cpp \
+ android_keymaster_messages.cpp \
+ android_keymaster_messages_test.cpp \
+ android_keymaster_test.cpp \
+ android_keymaster_test_utils.cpp \
+ android_keymaster_utils.cpp \
+ asymmetric_key.cpp \
+ asymmetric_key_factory.cpp \
+ attestation_record.cpp \
+ attestation_record_test.cpp \
+ auth_encrypted_key_blob.cpp \
+ authorization_set.cpp \
+ authorization_set_test.cpp \
+ ec_key.cpp \
+ ec_key_factory.cpp \
+ ec_keymaster0_key.cpp \
+ ec_keymaster1_key.cpp \
+ ecdsa_keymaster1_operation.cpp \
+ ecdsa_operation.cpp \
+ ecies_kem.cpp \
+ ecies_kem_test.cpp \
+ gtest_main.cpp \
+ hkdf.cpp \
+ hkdf_test.cpp \
+ hmac.cpp \
+ hmac_key.cpp \
+ hmac_operation.cpp \
+ hmac_test.cpp \
+ integrity_assured_key_blob.cpp \
+ iso18033kdf.cpp \
+ kdf.cpp \
+ kdf_test.cpp \
+ kdf1_test.cpp \
+ kdf2_test.cpp \
+ key.cpp \
+ key_blob_test.cpp \
+ keymaster0_engine.cpp \
+ keymaster1_engine.cpp \
+ keymaster_enforcement.cpp \
+ keymaster_enforcement_test.cpp \
+ keymaster_tags.cpp \
+ logger.cpp \
+ nist_curve_key_exchange.cpp \
+ nist_curve_key_exchange_test.cpp \
+ ocb_utils.cpp \
+ openssl_err.cpp \
+ openssl_utils.cpp \
+ operation.cpp \
+ operation_table.cpp \
+ rsa_key.cpp \
+ rsa_key_factory.cpp \
+ rsa_keymaster0_key.cpp \
+ rsa_keymaster1_key.cpp \
+ rsa_keymaster1_operation.cpp \
+ rsa_operation.cpp \
+ serializable.cpp \
+ soft_keymaster_context.cpp \
+ soft_keymaster_device.cpp \
+ symmetric_key.cpp
+
+CCSRCS=$(GTEST)/src/gtest-all.cc
+CSRCS=ocb.c
+
+OBJS=$(CPPSRCS:.cpp=.o) $(CCSRCS:.cc=.o) $(CSRCS:.c=.o)
+DEPS=$(CPPSRCS:.cpp=.d) $(CCSRCS:.cc=.d) $(CSRCS:.c=.d)
+
+BINARIES = \
+ android_keymaster_messages_test \
+ android_keymaster_test \
+ attestation_record_test \
+ authorization_set_test \
+ ecies_kem_test \
+ hkdf_test \
+ hmac_test \
+ kdf_test \
+ kdf1_test \
+ kdf2_test \
+ key_blob_test \
+ keymaster_enforcement_test \
+ 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 gtest_main.o
+
+hmac_test: hmac_test.o \
+ android_keymaster_test_utils.o \
+ android_keymaster_utils.o \
+ authorization_set.o \
+ hmac.o \
+ keymaster_tags.o \
+ logger.o \
+ serializable.o \
+ $(GTEST_OBJS)
+
+hkdf_test: hkdf_test.o \
+ android_keymaster_test_utils.o \
+ android_keymaster_utils.o \
+ authorization_set.o \
+ hkdf.o \
+ hmac.o \
+ kdf.o \
+ keymaster_tags.o \
+ logger.o \
+ serializable.o \
+ $(GTEST_OBJS)
+
+kdf_test: kdf_test.o \
+ android_keymaster_utils.o \
+ kdf.o \
+ logger.o \
+ serializable.o \
+ $(GTEST_OBJS)
+
+kdf1_test: kdf1_test.o \
+ android_keymaster_test_utils.o \
+ android_keymaster_utils.o \
+ authorization_set.o \
+ iso18033kdf.o \
+ kdf.o \
+ keymaster_tags.o \
+ logger.o \
+ serializable.o \
+ $(GTEST_OBJS)
+
+kdf2_test: kdf2_test.o \
+ android_keymaster_test_utils.o \
+ android_keymaster_utils.o \
+ authorization_set.o \
+ iso18033kdf.o \
+ kdf.o \
+ keymaster_tags.o \
+ logger.o \
+ serializable.o \
+ $(GTEST_OBJS)
+
+nist_curve_key_exchange_test: nist_curve_key_exchange_test.o \
+ android_keymaster_test_utils.o \
+ authorization_set.o \
+ keymaster_tags.o \
+ logger.o \
+ nist_curve_key_exchange.o \
+ openssl_err.o \
+ openssl_utils.o \
+ serializable.o \
+ $(GTEST_OBJS)
+
+ecies_kem_test: ecies_kem_test.o \
+ android_keymaster_utils.o \
+ android_keymaster_test_utils.o \
+ authorization_set.o \
+ ecies_kem.o \
+ hkdf.o \
+ hmac.o \
+ kdf.o \
+ keymaster_tags.o \
+ logger.o \
+ nist_curve_key_exchange.o \
+ openssl_err.o \
+ openssl_utils.o \
+ serializable.o \
+ $(GTEST_OBJS)
+
+authorization_set_test: authorization_set_test.o \
+ android_keymaster_test_utils.o \
+ authorization_set.o \
+ keymaster_tags.o \
+ logger.o \
+ serializable.o \
+ $(GTEST_OBJS)
+
+key_blob_test: key_blob_test.o \
+ android_keymaster_test_utils.o \
+ android_keymaster_utils.o \
+ auth_encrypted_key_blob.o \
+ authorization_set.o \
+ integrity_assured_key_blob.o \
+ keymaster_tags.o \
+ logger.o \
+ ocb.o \
+ ocb_utils.o \
+ openssl_err.o \
+ serializable.o \
+ $(GTEST_OBJS)
+
+android_keymaster_messages_test: android_keymaster_messages_test.o \
+ android_keymaster_messages.o \
+ android_keymaster_test_utils.o \
+ android_keymaster_utils.o \
+ authorization_set.o \
+ keymaster_tags.o \
+ logger.o \
+ serializable.o \
+ $(GTEST_OBJS)
+
+android_keymaster_test: android_keymaster_test.o \
+ aes_key.o \
+ aes_operation.o \
+ android_keymaster.o \
+ android_keymaster_messages.o \
+ android_keymaster_test_utils.o \
+ android_keymaster_utils.o \
+ asymmetric_key.o \
+ asymmetric_key_factory.o \
+ attestation_record.o \
+ auth_encrypted_key_blob.o \
+ authorization_set.o \
+ ec_key.o \
+ ec_key_factory.o \
+ ec_keymaster0_key.o \
+ ec_keymaster1_key.o \
+ ecdsa_keymaster1_operation.o \
+ ecdsa_operation.o \
+ hmac_key.o \
+ hmac_operation.o \
+ integrity_assured_key_blob.o \
+ key.o \
+ keymaster0_engine.o \
+ keymaster1_engine.o \
+ keymaster_enforcement.o \
+ keymaster_tags.o \
+ logger.o \
+ ocb.o \
+ ocb_utils.o \
+ openssl_err.o \
+ openssl_utils.o \
+ operation.o \
+ operation_table.o \
+ rsa_key.o \
+ rsa_key_factory.o \
+ rsa_keymaster0_key.o \
+ rsa_keymaster1_key.o \
+ rsa_keymaster1_operation.o \
+ rsa_operation.o \
+ serializable.o \
+ soft_keymaster_context.o \
+ soft_keymaster_device.o \
+ symmetric_key.o \
+ $(BASE)/system/security/softkeymaster/keymaster_openssl.o \
+ $(BASE)/system/security/keystore/keyblob_utils.o \
+ $(GTEST_OBJS)
+
+keymaster_enforcement_test: keymaster_enforcement_test.o \
+ android_keymaster_messages.o \
+ android_keymaster_test_utils.o \
+ android_keymaster_utils.o \
+ authorization_set.o \
+ keymaster_enforcement.o \
+ keymaster_tags.o \
+ logger.o \
+ serializable.o \
+ $(GTEST_OBJS)
+
+attestation_record_test: attestation_record_test.o \
+ android_keymaster_test_utils.o \
+ attestation_record.o \
+ authorization_set.o \
+ keymaster_tags.o \
+ logger.o \
+ openssl_err.o \
+ serializable.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/keymaster/NOTICE b/keymaster/NOTICE
new file mode 100644
index 0000000..34bdaf1
--- /dev/null
+++ b/keymaster/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/keymaster/ae.h b/keymaster/ae.h
new file mode 100644
index 0000000..864d349
--- /dev/null
+++ b/keymaster/ae.h
@@ -0,0 +1,164 @@
+/* ---------------------------------------------------------------------------
+ *
+ * AEAD API 0.12 - 23-MAY-2012
+ *
+ * This file gives an interface appropriate for many authenticated
+ * encryption with associated data (AEAD) implementations. It does not try
+ * to accommodate all possible options or limitations that an implementation
+ * might have -- you should consult the documentation of your chosen
+ * implementation to find things like RFC 5116 constants, alignment
+ * requirements, whether the incremental interface is supported, etc.
+ *
+ * This file is in the public domain. It is provided "as is", without
+ * warranty of any kind. Use at your own risk.
+ *
+ * Comments are welcome: Ted Krovetz <ted@krovetz>.
+ *
+ * ------------------------------------------------------------------------ */
+
+#ifndef _AE_H_
+#define _AE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* --------------------------------------------------------------------------
+ *
+ * Constants
+ *
+ * ----------------------------------------------------------------------- */
+
+/* Return status codes: Negative return values indicate an error occurred.
+ * For full explanations of error values, consult the implementation's
+ * documentation. */
+#define AE_SUCCESS (0) /* Indicates successful completion of call */
+#define AE_INVALID (-1) /* Indicates bad tag during decryption */
+#define AE_NOT_SUPPORTED (-2) /* Indicates unsupported option requested */
+
+/* Flags: When data can be processed "incrementally", these flags are used
+ * to indicate whether the submitted data is the last or not. */
+#define AE_FINALIZE (1) /* This is the last of data */
+#define AE_PENDING (0) /* More data of is coming */
+
+/* --------------------------------------------------------------------------
+ *
+ * AEAD opaque structure definition
+ *
+ * ----------------------------------------------------------------------- */
+
+typedef struct _ae_ctx ae_ctx;
+
+/* --------------------------------------------------------------------------
+ *
+ * Data Structure Routines
+ *
+ * ----------------------------------------------------------------------- */
+
+ae_ctx* ae_allocate(void* misc); /* Allocate ae_ctx, set optional ptr */
+void ae_free(ae_ctx* ctx); /* Deallocate ae_ctx struct */
+int ae_clear(ae_ctx* ctx); /* Undo initialization */
+int ae_ctx_sizeof(void); /* Return sizeof(ae_ctx) */
+/* ae_allocate() allocates an ae_ctx structure, but does not initialize it.
+ * ae_free() deallocates an ae_ctx structure, but does not zero it.
+ * ae_clear() zeroes sensitive values associated with an ae_ctx structure
+ * and deallocates any auxiliary structures allocated during ae_init().
+ * ae_ctx_sizeof() returns sizeof(ae_ctx), to aid in any static allocations.
+ */
+
+/* --------------------------------------------------------------------------
+ *
+ * AEAD Routines
+ *
+ * ----------------------------------------------------------------------- */
+
+int ae_init(ae_ctx* ctx, const void* key, int key_len, int nonce_len, int tag_len);
+/* --------------------------------------------------------------------------
+ *
+ * Initialize an ae_ctx context structure.
+ *
+ * Parameters:
+ * ctx - Pointer to an ae_ctx structure to be initialized
+ * key - Pointer to user-supplied key
+ * key_len - Length of key supplied, in bytes
+ * nonce_len - Length of nonces to be used for this key, in bytes
+ * tag_len - Length of tags to be produced for this key, in bytes
+ *
+ * Returns:
+ * AE_SUCCESS - Success. Ctx ready for use.
+ * AE_NOT_SUPPORTED - An unsupported length was supplied. Ctx is untouched.
+ * Otherwise - Error. Check implementation documentation for codes.
+ *
+ * ----------------------------------------------------------------------- */
+
+int ae_encrypt(ae_ctx* ctx, const void* nonce, const void* pt, int pt_len, const void* ad,
+ int ad_len, void* ct, void* tag, int final);
+/* --------------------------------------------------------------------------
+ *
+ * Encrypt plaintext; provide for authentication of ciphertext/associated data.
+ *
+ * Parameters:
+ * ctx - Pointer to an ae_ctx structure initialized by ae_init.
+ * nonce - Pointer to a nonce_len (defined in ae_init) byte nonce.
+ * pt - Pointer to plaintext bytes to be encrypted.
+ * pt_len - number of bytes pointed to by pt.
+ * ad - Pointer to associated data.
+ * ad_len - number of bytes pointed to by ad.
+ * ct - Pointer to buffer to receive ciphertext encryption.
+ * tag - Pointer to receive authentication tag; or NULL
+ * if tag is to be bundled into the ciphertext.
+ * final - Non-zero if this call completes the plaintext being encrypted.
+ *
+ * If nonce!=NULL then a message is being initiated. If final!=0
+ * then a message is being finalized. If final==0 or nonce==NULL
+ * then the incremental interface is being used. If nonce!=NULL and
+ * ad_len<0, then use same ad as last message.
+ *
+ * Returns:
+ * non-negative - Number of bytes written to ct.
+ * AE_NOT_SUPPORTED - Usage mode unsupported (eg, incremental and/or sticky).
+ * Otherwise - Error. Check implementation documentation for codes.
+ *
+ * ----------------------------------------------------------------------- */
+
+int ae_decrypt(ae_ctx* ctx, const void* nonce, const void* ct, int ct_len, const void* ad,
+ int ad_len, void* pt, const void* tag, int final);
+/* --------------------------------------------------------------------------
+ *
+ * Decrypt ciphertext; provide authenticity of plaintext and associated data.
+ *
+ * Parameters:
+ * ctx - Pointer to an ae_ctx structure initialized by ae_init.
+ * nonce - Pointer to a nonce_len (defined in ae_init) byte nonce.
+ * ct - Pointer to ciphertext bytes to be decrypted.
+ * ct_len - number of bytes pointed to by ct.
+ * ad - Pointer to associated data.
+ * ad_len - number of bytes pointed to by ad.
+ * pt - Pointer to buffer to receive plaintext decryption.
+ * tag - Pointer to tag_len (defined in ae_init) bytes; or NULL
+ * if tag is bundled into the ciphertext. Non-NULL tag is only
+ * read when final is non-zero.
+ * final - Non-zero if this call completes the ciphertext being decrypted.
+ *
+ * If nonce!=NULL then "ct" points to the start of a ciphertext. If final!=0
+ * then "in" points to the final piece of ciphertext. If final==0 or nonce==
+ * NULL then the incremental interface is being used. If nonce!=NULL and
+ * ad_len<0, then use same ad as last message.
+ *
+ * Returns:
+ * non-negative - Number of bytes written to pt.
+ * AE_INVALID - Authentication failure.
+ * AE_NOT_SUPPORTED - Usage mode unsupported (eg, incremental and/or sticky).
+ * Otherwise - Error. Check implementation documentation for codes.
+ *
+ * NOTE !!! NOTE !!! -- The ciphertext should be assumed possibly inauthentic
+ * until it has been completely written and it is
+ * verified that this routine did not return AE_INVALID.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifdef __cplusplus
+} /* closing brace for extern "C" */
+#endif
+
+#endif /* _AE_H_ */
diff --git a/keymaster/aes_key.cpp b/keymaster/aes_key.cpp
new file mode 100644
index 0000000..6b784b7
--- /dev/null
+++ b/keymaster/aes_key.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2014 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 "aes_key.h"
+
+#include <assert.h>
+
+#include <new>
+
+#include <openssl/err.h>
+#include <openssl/rand.h>
+
+#include "aes_operation.h"
+
+namespace keymaster {
+
+AesEncryptionOperationFactory encrypt_factory;
+AesDecryptionOperationFactory decrypt_factory;
+
+OperationFactory* AesKeyFactory::GetOperationFactory(keymaster_purpose_t purpose) const {
+ switch (purpose) {
+ case KM_PURPOSE_ENCRYPT:
+ return &encrypt_factory;
+ case KM_PURPOSE_DECRYPT:
+ return &decrypt_factory;
+ default:
+ return nullptr;
+ }
+}
+
+keymaster_error_t AesKeyFactory::LoadKey(const KeymasterKeyBlob& key_material,
+ const AuthorizationSet& /* additional_params */,
+ const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ UniquePtr<Key>* key) const {
+ if (!key)
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+ uint32_t min_mac_length = 0;
+ if (hw_enforced.Contains(TAG_BLOCK_MODE, KM_MODE_GCM) ||
+ sw_enforced.Contains(TAG_BLOCK_MODE, KM_MODE_GCM)) {
+
+ if (!hw_enforced.GetTagValue(TAG_MIN_MAC_LENGTH, &min_mac_length) &&
+ !sw_enforced.GetTagValue(TAG_MIN_MAC_LENGTH, &min_mac_length)) {
+
+ LOG_E("AES-GCM key must have KM_TAG_MIN_MAC_LENGTH", 0);
+ return KM_ERROR_INVALID_KEY_BLOB;
+ }
+ }
+
+ keymaster_error_t error = KM_ERROR_OK;
+ key->reset(new (std::nothrow) AesKey(key_material, hw_enforced, sw_enforced, &error));
+ if (!key->get())
+ error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return error;
+}
+
+keymaster_error_t AesKeyFactory::validate_algorithm_specific_new_key_params(
+ const AuthorizationSet& key_description) const {
+ if (key_description.Contains(TAG_BLOCK_MODE, KM_MODE_GCM)) {
+ uint32_t min_tag_length;
+ 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 < kMinGcmTagLength || min_tag_length > kMaxGcmTagLength)
+ return KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH;
+ } else {
+ // Not GCM
+ if (key_description.find(TAG_MIN_MAC_LENGTH) != -1) {
+ LOG_W("KM_TAG_MIN_MAC_LENGTH found for non AES-GCM key", 0);
+ return KM_ERROR_INVALID_TAG;
+ }
+ }
+
+ return KM_ERROR_OK;
+}
+
+} // namespace keymaster
diff --git a/keymaster/aes_key.h b/keymaster/aes_key.h
new file mode 100644
index 0000000..a4ab2f2
--- /dev/null
+++ b/keymaster/aes_key.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2014 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_AES_KEY_H_
+#define SYSTEM_KEYMASTER_AES_KEY_H_
+
+#include <openssl/aes.h>
+
+#include "symmetric_key.h"
+
+namespace keymaster {
+
+const size_t kMinGcmTagLength = 12 * 8;
+const size_t kMaxGcmTagLength = 16 * 8;
+
+class AesKeyFactory : public SymmetricKeyFactory {
+ public:
+ explicit AesKeyFactory(const KeymasterContext* context) : SymmetricKeyFactory(context) {}
+
+ keymaster_algorithm_t registry_key() const { return KM_ALGORITHM_AES; }
+
+ keymaster_error_t LoadKey(const KeymasterKeyBlob& key_material,
+ const AuthorizationSet& additional_params,
+ const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ UniquePtr<Key>* key) const override;
+
+ OperationFactory* GetOperationFactory(keymaster_purpose_t purpose) const override;
+
+ private:
+ bool key_size_supported(size_t key_size_bits) const override {
+ return key_size_bits == 128 || key_size_bits == 192 || key_size_bits == 256;
+ }
+ keymaster_error_t validate_algorithm_specific_new_key_params(
+ const AuthorizationSet& key_description) const override;
+};
+
+class AesKey : public SymmetricKey {
+ public:
+ AesKey(const KeymasterKeyBlob& key_material, const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced, keymaster_error_t* error)
+ : SymmetricKey(key_material, hw_enforced, sw_enforced, error) {}
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_AES_KEY_H_
diff --git a/keymaster/aes_operation.cpp b/keymaster/aes_operation.cpp
new file mode 100644
index 0000000..4c5c88c
--- /dev/null
+++ b/keymaster/aes_operation.cpp
@@ -0,0 +1,651 @@
+/*
+ * Copyright 2014 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 "aes_operation.h"
+
+#include <stdio.h>
+
+#include <new>
+
+#include <UniquePtr.h>
+
+#include <openssl/aes.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+
+#include <keymaster/logger.h>
+
+#include "aes_key.h"
+#include "openssl_err.h"
+
+namespace keymaster {
+
+static const size_t GCM_NONCE_SIZE = 12;
+
+inline bool allows_padding(keymaster_block_mode_t block_mode) {
+ switch (block_mode) {
+ case KM_MODE_CTR:
+ case KM_MODE_GCM:
+ return false;
+ case KM_MODE_ECB:
+ case KM_MODE_CBC:
+ return true;
+ }
+ assert(false /* Can't get here */);
+ return false;
+}
+
+static keymaster_error_t GetAndValidateGcmTagLength(const AuthorizationSet& begin_params,
+ const AuthorizationSet& key_params,
+ size_t* tag_length) {
+ uint32_t tag_length_bits;
+ if (!begin_params.GetTagValue(TAG_MAC_LENGTH, &tag_length_bits)) {
+ return KM_ERROR_MISSING_MAC_LENGTH;
+ }
+
+ uint32_t min_tag_length_bits;
+ if (!key_params.GetTagValue(TAG_MIN_MAC_LENGTH, &min_tag_length_bits)) {
+ LOG_E("AES GCM key must have KM_TAG_MIN_MAC_LENGTH", 0);
+ return KM_ERROR_INVALID_KEY_BLOB;
+ }
+
+ if (tag_length_bits % 8 != 0 || tag_length_bits > kMaxGcmTagLength ||
+ tag_length_bits < kMinGcmTagLength) {
+ return KM_ERROR_UNSUPPORTED_MAC_LENGTH;
+ }
+
+ if (tag_length_bits < min_tag_length_bits) {
+ return KM_ERROR_INVALID_MAC_LENGTH;
+ }
+
+ *tag_length = tag_length_bits / 8;
+ return KM_ERROR_OK;
+}
+
+Operation* AesOperationFactory::CreateOperation(const Key& key,
+ const AuthorizationSet& begin_params,
+ keymaster_error_t* error) {
+ *error = KM_ERROR_OK;
+ const SymmetricKey* symmetric_key = static_cast<const SymmetricKey*>(&key);
+
+ switch (symmetric_key->key_data_size()) {
+ case 16:
+ case 24:
+ case 32:
+ break;
+ default:
+ *error = KM_ERROR_UNSUPPORTED_KEY_SIZE;
+ return nullptr;
+ }
+
+ keymaster_block_mode_t block_mode;
+ if (!begin_params.GetTagValue(TAG_BLOCK_MODE, &block_mode)) {
+ LOG_E("%d block modes specified in begin params", begin_params.GetTagCount(TAG_BLOCK_MODE));
+ *error = KM_ERROR_UNSUPPORTED_BLOCK_MODE;
+ return nullptr;
+ } else if (!supported(block_mode)) {
+ LOG_E("Block mode %d not supported", block_mode);
+ *error = KM_ERROR_UNSUPPORTED_BLOCK_MODE;
+ return nullptr;
+ } else if (!key.authorizations().Contains(TAG_BLOCK_MODE, block_mode)) {
+ LOG_E("Block mode %d was specified, but not authorized by key", block_mode);
+ *error = KM_ERROR_INCOMPATIBLE_BLOCK_MODE;
+ return nullptr;
+ }
+
+ size_t tag_length = 0;
+ if (block_mode == KM_MODE_GCM) {
+ *error = GetAndValidateGcmTagLength(begin_params, key.authorizations(), &tag_length);
+ if (*error != KM_ERROR_OK) {
+ return nullptr;
+ }
+ }
+
+ keymaster_padding_t padding;
+ if (!GetAndValidatePadding(begin_params, key, &padding, error)) {
+ return nullptr;
+ }
+ if (!allows_padding(block_mode) && padding != KM_PAD_NONE) {
+ LOG_E("Mode does not support padding", 0);
+ *error = KM_ERROR_INCOMPATIBLE_PADDING_MODE;
+ return nullptr;
+ }
+
+ bool caller_nonce = key.authorizations().GetTagValue(TAG_CALLER_NONCE);
+
+ Operation* op = nullptr;
+ switch (purpose()) {
+ case KM_PURPOSE_ENCRYPT:
+ op = new (std::nothrow)
+ AesEvpEncryptOperation(block_mode, padding, caller_nonce, tag_length,
+ symmetric_key->key_data(), symmetric_key->key_data_size());
+ break;
+ case KM_PURPOSE_DECRYPT:
+ op = new (std::nothrow)
+ AesEvpDecryptOperation(block_mode, padding, tag_length, symmetric_key->key_data(),
+ symmetric_key->key_data_size());
+ break;
+ default:
+ *error = KM_ERROR_UNSUPPORTED_PURPOSE;
+ return nullptr;
+ }
+
+ if (!op)
+ *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return op;
+}
+
+static const keymaster_block_mode_t supported_block_modes[] = {KM_MODE_ECB, KM_MODE_CBC,
+ KM_MODE_CTR, KM_MODE_GCM};
+
+const keymaster_block_mode_t*
+AesOperationFactory::SupportedBlockModes(size_t* block_mode_count) const {
+ *block_mode_count = array_length(supported_block_modes);
+ return supported_block_modes;
+}
+
+static const keymaster_padding_t supported_padding_modes[] = {KM_PAD_NONE, KM_PAD_PKCS7};
+const keymaster_padding_t*
+AesOperationFactory::SupportedPaddingModes(size_t* padding_mode_count) const {
+ *padding_mode_count = array_length(supported_padding_modes);
+ return supported_padding_modes;
+}
+
+AesEvpOperation::AesEvpOperation(keymaster_purpose_t purpose, keymaster_block_mode_t block_mode,
+ keymaster_padding_t padding, bool caller_iv, size_t tag_length,
+ const uint8_t* key, size_t key_size)
+ : Operation(purpose), block_mode_(block_mode), caller_iv_(caller_iv), tag_length_(tag_length),
+ data_started_(false), key_size_(key_size), padding_(padding) {
+ memcpy(key_, key, key_size_);
+ EVP_CIPHER_CTX_init(&ctx_);
+}
+
+AesEvpOperation::~AesEvpOperation() {
+ EVP_CIPHER_CTX_cleanup(&ctx_);
+ memset_s(aad_block_buf_.get(), AES_BLOCK_SIZE, 0);
+}
+
+keymaster_error_t AesEvpOperation::Begin(const AuthorizationSet& /* input_params */,
+ AuthorizationSet* /* output_params */) {
+ if (block_mode_ == KM_MODE_GCM) {
+ aad_block_buf_length_ = 0;
+ aad_block_buf_.reset(new (std::nothrow) uint8_t[AES_BLOCK_SIZE]);
+ if (!aad_block_buf_.get())
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ }
+
+ return InitializeCipher();
+}
+
+keymaster_error_t AesEvpOperation::Update(const AuthorizationSet& additional_params,
+ const Buffer& input,
+ AuthorizationSet* /* output_params */, Buffer* output,
+ size_t* input_consumed) {
+ keymaster_error_t error;
+ if (block_mode_ == KM_MODE_GCM)
+ if (!HandleAad(additional_params, input, &error))
+ return error;
+
+ if (!InternalUpdate(input.peek_read(), input.available_read(), output, &error))
+ return error;
+ *input_consumed = input.available_read();
+
+ return KM_ERROR_OK;
+}
+
+inline bool is_bad_decrypt(unsigned long error) {
+ return (ERR_GET_LIB(error) == ERR_LIB_CIPHER && //
+ ERR_GET_REASON(error) == CIPHER_R_BAD_DECRYPT);
+}
+
+keymaster_error_t AesEvpOperation::Finish(const AuthorizationSet& additional_params,
+ const Buffer& input, const Buffer& /* signature */,
+ AuthorizationSet* output_params, Buffer* output) {
+ keymaster_error_t error;
+ if (!UpdateForFinish(additional_params, input, output_params, output, &error))
+ return error;
+
+ if (!output->reserve(AES_BLOCK_SIZE))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ if (block_mode_ == KM_MODE_GCM && aad_block_buf_length_ > 0 && !ProcessBufferedAadBlock(&error))
+ return error;
+
+ 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(), NULL));
+ return TranslateLastOpenSslError();
+ }
+
+ assert(output_written <= AES_BLOCK_SIZE);
+ if (!output->advance_write(output_written))
+ return KM_ERROR_UNKNOWN_ERROR;
+ return KM_ERROR_OK;
+}
+
+bool AesEvpOperation::need_iv() const {
+ switch (block_mode_) {
+ case KM_MODE_CBC:
+ case KM_MODE_CTR:
+ case KM_MODE_GCM:
+ return true;
+ case KM_MODE_ECB:
+ return false;
+ default:
+ // Shouldn't get here.
+ assert(false);
+ return false;
+ }
+}
+
+keymaster_error_t AesEvpOperation::InitializeCipher() {
+ const EVP_CIPHER* cipher;
+ switch (block_mode_) {
+ case KM_MODE_ECB:
+ switch (key_size_) {
+ case 16:
+ cipher = EVP_aes_128_ecb();
+ break;
+ case 24:
+ cipher = EVP_aes_192_ecb();
+ break;
+ case 32:
+ cipher = EVP_aes_256_ecb();
+ break;
+ default:
+ return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+ }
+ break;
+ case KM_MODE_CBC:
+ switch (key_size_) {
+ case 16:
+ cipher = EVP_aes_128_cbc();
+ break;
+ case 24:
+ cipher = EVP_aes_192_cbc();
+ break;
+ case 32:
+ cipher = EVP_aes_256_cbc();
+ break;
+ default:
+ return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+ }
+ break;
+ case KM_MODE_CTR:
+ switch (key_size_) {
+ case 16:
+ cipher = EVP_aes_128_ctr();
+ break;
+ case 24:
+ cipher = EVP_aes_192_ctr();
+ break;
+ case 32:
+ cipher = EVP_aes_256_ctr();
+ break;
+ default:
+ return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+ }
+ break;
+ case KM_MODE_GCM:
+ switch (key_size_) {
+ case 16:
+ cipher = EVP_aes_128_gcm();
+ break;
+ case 24:
+ cipher = EVP_aes_192_gcm();
+ break;
+ case 32:
+ cipher = EVP_aes_256_gcm();
+ break;
+ default:
+ return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+ }
+ break;
+ default:
+ return KM_ERROR_UNSUPPORTED_BLOCK_MODE;
+ }
+
+ if (!EVP_CipherInit_ex(&ctx_, cipher, NULL /* engine */, key_, iv_.get(), evp_encrypt_mode()))
+ return TranslateLastOpenSslError();
+
+ switch (padding_) {
+ case KM_PAD_NONE:
+ EVP_CIPHER_CTX_set_padding(&ctx_, 0 /* disable padding */);
+ break;
+ case KM_PAD_PKCS7:
+ // This is the default for OpenSSL EVP cipher operations.
+ break;
+ default:
+ return KM_ERROR_UNSUPPORTED_PADDING_MODE;
+ }
+
+ if (block_mode_ == KM_MODE_GCM) {
+ aad_block_buf_length_ = 0;
+ aad_block_buf_.reset(new (std::nothrow) uint8_t[AES_BLOCK_SIZE]);
+ if (!aad_block_buf_.get())
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ }
+
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t AesEvpOperation::GetIv(const AuthorizationSet& input_params) {
+ keymaster_blob_t iv_blob;
+ if (!input_params.GetTagValue(TAG_NONCE, &iv_blob)) {
+ LOG_E("No IV provided", 0);
+ return KM_ERROR_INVALID_ARGUMENT;
+ }
+ if (block_mode_ != KM_MODE_GCM && iv_blob.data_length != AES_BLOCK_SIZE) {
+ LOG_E("Expected %d-byte IV for AES operation, but got %d bytes", AES_BLOCK_SIZE,
+ iv_blob.data_length);
+ return KM_ERROR_INVALID_NONCE;
+ }
+ if (block_mode_ == KM_MODE_GCM && iv_blob.data_length != GCM_NONCE_SIZE) {
+ LOG_E("Expected %d-byte nonce for AES-GCM operation, but got %d bytes", GCM_NONCE_SIZE,
+ iv_blob.data_length);
+ return KM_ERROR_INVALID_NONCE;
+ }
+ iv_.reset(dup_array(iv_blob.data, iv_blob.data_length));
+ if (!iv_.get())
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ iv_length_ = iv_blob.data_length;
+ return KM_ERROR_OK;
+}
+
+/*
+ * Process Incoming Associated Authentication Data.
+ *
+ * This method is more complex than might be expected, because the underlying library silently does
+ * the wrong thing when given partial AAD blocks, so we have to take care to process AAD in
+ * AES_BLOCK_SIZE increments, buffering (in aad_block_buf_) when given smaller amounts of data.
+ */
+bool AesEvpOperation::HandleAad(const AuthorizationSet& input_params, const Buffer& input,
+ keymaster_error_t* error) {
+ assert(tag_length_ > 0);
+ assert(error);
+
+ keymaster_blob_t aad;
+ if (input_params.GetTagValue(TAG_ASSOCIATED_DATA, &aad)) {
+ if (data_started_) {
+ *error = KM_ERROR_INVALID_TAG;
+ return false;
+ }
+
+ if (aad_block_buf_length_ > 0) {
+ FillBufferedAadBlock(&aad);
+ if (aad_block_buf_length_ == AES_BLOCK_SIZE && !ProcessBufferedAadBlock(error))
+ return false;
+ }
+
+ size_t blocks_to_process = aad.data_length / AES_BLOCK_SIZE;
+ if (blocks_to_process && !ProcessAadBlocks(aad.data, blocks_to_process, error))
+ return false;
+ aad.data += blocks_to_process * AES_BLOCK_SIZE;
+ aad.data_length -= blocks_to_process * AES_BLOCK_SIZE;
+
+ FillBufferedAadBlock(&aad);
+ assert(aad.data_length == 0);
+ }
+
+ if (input.available_read()) {
+ data_started_ = true;
+ // Data has begun, no more AAD is allowed. Process any buffered AAD.
+ if (aad_block_buf_length_ > 0 && !ProcessBufferedAadBlock(error))
+ return false;
+ }
+
+ return true;
+}
+
+bool AesEvpOperation::ProcessBufferedAadBlock(keymaster_error_t* error) {
+ int output_written;
+ if (EVP_CipherUpdate(&ctx_, nullptr /* out */, &output_written, aad_block_buf_.get(),
+ aad_block_buf_length_)) {
+ aad_block_buf_length_ = 0;
+ return true;
+ }
+ *error = TranslateLastOpenSslError();
+ return false;
+}
+
+bool AesEvpOperation::ProcessAadBlocks(const uint8_t* data, size_t blocks,
+ keymaster_error_t* error) {
+ int output_written;
+ if (EVP_CipherUpdate(&ctx_, nullptr /* out */, &output_written, data, blocks * AES_BLOCK_SIZE))
+ return true;
+ *error = TranslateLastOpenSslError();
+ return false;
+}
+
+inline size_t min(size_t a, size_t b) {
+ return (a < b) ? a : b;
+}
+
+void AesEvpOperation::FillBufferedAadBlock(keymaster_blob_t* aad) {
+ size_t to_buffer = min(AES_BLOCK_SIZE - aad_block_buf_length_, aad->data_length);
+ memcpy(aad_block_buf_.get() + aad_block_buf_length_, aad->data, to_buffer);
+ aad->data += to_buffer;
+ aad->data_length -= to_buffer;
+ aad_block_buf_length_ += to_buffer;
+}
+
+bool AesEvpOperation::InternalUpdate(const uint8_t* input, size_t input_length, Buffer* output,
+ keymaster_error_t* error) {
+ assert(output);
+ assert(error);
+
+ if (!input_length)
+ return true;
+
+ if (!output->reserve(input_length + AES_BLOCK_SIZE)) {
+ *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return false;
+ }
+
+ int output_written = -1;
+ if (!EVP_CipherUpdate(&ctx_, output->peek_write(), &output_written, input, input_length)) {
+ *error = TranslateLastOpenSslError();
+ return false;
+ }
+ return output->advance_write(output_written);
+}
+
+bool AesEvpOperation::UpdateForFinish(const AuthorizationSet& additional_params,
+ const Buffer& input, AuthorizationSet* output_params,
+ Buffer* output, keymaster_error_t* error) {
+ if (input.available_read() || !additional_params.empty()) {
+ size_t input_consumed;
+ *error = Update(additional_params, input, output_params, output, &input_consumed);
+ if (*error != KM_ERROR_OK)
+ return false;
+ if (input_consumed != input.available_read()) {
+ *error = KM_ERROR_INVALID_INPUT_LENGTH;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+keymaster_error_t AesEvpEncryptOperation::Begin(const AuthorizationSet& input_params,
+ AuthorizationSet* output_params) {
+ if (!output_params)
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+ if (need_iv()) {
+ keymaster_error_t error = KM_ERROR_OK;
+ if (input_params.find(TAG_NONCE) == -1)
+ error = GenerateIv();
+ else if (caller_iv_)
+ error = GetIv(input_params);
+ else
+ error = KM_ERROR_CALLER_NONCE_PROHIBITED;
+
+ if (error == KM_ERROR_OK)
+ output_params->push_back(TAG_NONCE, iv_.get(), iv_length_);
+ else
+ return error;
+ }
+
+ return AesEvpOperation::Begin(input_params, output_params);
+}
+
+keymaster_error_t AesEvpEncryptOperation::Finish(const AuthorizationSet& additional_params,
+ const Buffer& input, const Buffer& signature,
+ AuthorizationSet* output_params, Buffer* output) {
+ if (!output->reserve(input.available_read() + AES_BLOCK_SIZE + tag_length_))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ keymaster_error_t error =
+ AesEvpOperation::Finish(additional_params, input, signature, output_params, output);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ if (tag_length_ > 0) {
+ if (!output->reserve(tag_length_))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ if (!EVP_CIPHER_CTX_ctrl(&ctx_, EVP_CTRL_GCM_GET_TAG, tag_length_, output->peek_write()))
+ return TranslateLastOpenSslError();
+ if (!output->advance_write(tag_length_))
+ return KM_ERROR_UNKNOWN_ERROR;
+ }
+
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t AesEvpEncryptOperation::GenerateIv() {
+ iv_length_ = (block_mode_ == KM_MODE_GCM) ? GCM_NONCE_SIZE : AES_BLOCK_SIZE;
+ iv_.reset(new (std::nothrow) uint8_t[iv_length_]);
+ if (!iv_.get())
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ if (RAND_bytes(iv_.get(), iv_length_) != 1)
+ return TranslateLastOpenSslError();
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t AesEvpDecryptOperation::Begin(const AuthorizationSet& input_params,
+ AuthorizationSet* output_params) {
+ if (need_iv()) {
+ keymaster_error_t error = GetIv(input_params);
+ if (error != KM_ERROR_OK)
+ return error;
+ }
+
+ if (tag_length_ > 0) {
+ tag_buf_length_ = 0;
+ tag_buf_.reset(new (std::nothrow) uint8_t[tag_length_]);
+ if (!tag_buf_.get())
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ }
+
+ return AesEvpOperation::Begin(input_params, output_params);
+}
+
+keymaster_error_t AesEvpDecryptOperation::Update(const AuthorizationSet& additional_params,
+ const Buffer& input,
+ AuthorizationSet* /* output_params */,
+ Buffer* output, size_t* input_consumed) {
+ if (!output || !input_consumed)
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+ // Barring error, we'll consume it all.
+ *input_consumed = input.available_read();
+
+ keymaster_error_t error;
+ if (block_mode_ == KM_MODE_GCM) {
+ if (!HandleAad(additional_params, input, &error))
+ return error;
+ return ProcessAllButTagLengthBytes(input, output);
+ }
+
+ if (!InternalUpdate(input.peek_read(), input.available_read(), output, &error))
+ return error;
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t AesEvpDecryptOperation::ProcessAllButTagLengthBytes(const Buffer& input,
+ Buffer* output) {
+ if (input.available_read() <= tag_buf_unused()) {
+ BufferCandidateTagData(input.peek_read(), input.available_read());
+ return KM_ERROR_OK;
+ }
+
+ const size_t data_available = tag_buf_length_ + input.available_read();
+
+ const size_t to_process = data_available - tag_length_;
+ const size_t to_process_from_tag_buf = min(to_process, tag_buf_length_);
+ const size_t to_process_from_input = to_process - to_process_from_tag_buf;
+
+ if (!output->reserve(to_process + AES_BLOCK_SIZE))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ keymaster_error_t error;
+ if (!ProcessTagBufContentsAsData(to_process_from_tag_buf, output, &error))
+ return error;
+
+ if (!InternalUpdate(input.peek_read(), to_process_from_input, output, &error))
+ return error;
+
+ BufferCandidateTagData(input.peek_read() + to_process_from_input,
+ input.available_read() - to_process_from_input);
+ assert(tag_buf_unused() == 0);
+
+ return KM_ERROR_OK;
+}
+
+bool AesEvpDecryptOperation::ProcessTagBufContentsAsData(size_t to_process, Buffer* output,
+ keymaster_error_t* error) {
+ assert(to_process <= tag_buf_length_);
+ if (!InternalUpdate(tag_buf_.get(), to_process, output, error))
+ return false;
+ if (to_process < tag_buf_length_)
+ memmove(tag_buf_.get(), tag_buf_.get() + to_process, tag_buf_length_ - to_process);
+ tag_buf_length_ -= to_process;
+ return true;
+}
+
+void AesEvpDecryptOperation::BufferCandidateTagData(const uint8_t* data, size_t data_length) {
+ assert(data_length <= tag_length_ - tag_buf_length_);
+ memcpy(tag_buf_.get() + tag_buf_length_, data, data_length);
+ tag_buf_length_ += data_length;
+}
+
+keymaster_error_t AesEvpDecryptOperation::Finish(const AuthorizationSet& additional_params,
+ const Buffer& input, const Buffer& signature,
+ AuthorizationSet* output_params, Buffer* output) {
+ keymaster_error_t error;
+ if (!UpdateForFinish(additional_params, input, output_params, output, &error))
+ return error;
+
+ if (tag_buf_length_ < tag_length_)
+ return KM_ERROR_INVALID_INPUT_LENGTH;
+ else if (tag_length_ > 0 &&
+ !EVP_CIPHER_CTX_ctrl(&ctx_, EVP_CTRL_GCM_SET_TAG, tag_length_, tag_buf_.get()))
+ return TranslateLastOpenSslError();
+
+ AuthorizationSet empty_params;
+ Buffer empty_input;
+ return AesEvpOperation::Finish(empty_params, empty_input, signature, output_params, output);
+}
+
+keymaster_error_t AesEvpOperation::Abort() {
+ return KM_ERROR_OK;
+}
+
+} // namespace keymaster
diff --git a/keymaster/aes_operation.h b/keymaster/aes_operation.h
new file mode 100644
index 0000000..1a296bb
--- /dev/null
+++ b/keymaster/aes_operation.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2014 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_AES_OPERATION_H_
+#define SYSTEM_KEYMASTER_AES_OPERATION_H_
+
+#include <openssl/evp.h>
+
+#include "ocb_utils.h"
+#include "operation.h"
+
+namespace keymaster {
+
+/**
+ * Abstract base for AES operation factories. This class does all of the work to create
+ * AES operations.
+ */
+class AesOperationFactory : public OperationFactory {
+ public:
+ KeyType registry_key() const override { return KeyType(KM_ALGORITHM_AES, purpose()); }
+
+ Operation* CreateOperation(const Key& key, const AuthorizationSet& begin_params,
+ keymaster_error_t* error) override;
+ const keymaster_block_mode_t* SupportedBlockModes(size_t* block_mode_count) const override;
+ const keymaster_padding_t* SupportedPaddingModes(size_t* padding_count) const override;
+
+ virtual keymaster_purpose_t purpose() const = 0;
+};
+
+/**
+ * Concrete factory for AES encryption operations.
+ */
+class AesEncryptionOperationFactory : public AesOperationFactory {
+ keymaster_purpose_t purpose() const override { return KM_PURPOSE_ENCRYPT; }
+};
+
+/**
+ * Concrete factory for AES decryption operations.
+ */
+class AesDecryptionOperationFactory : public AesOperationFactory {
+ keymaster_purpose_t purpose() const override { return KM_PURPOSE_DECRYPT; }
+};
+
+static const size_t MAX_EVP_KEY_SIZE = 32;
+
+class AesEvpOperation : public Operation {
+ public:
+ AesEvpOperation(keymaster_purpose_t purpose, keymaster_block_mode_t block_mode,
+ keymaster_padding_t padding, bool caller_iv, size_t tag_length,
+ const uint8_t* key, size_t key_size);
+ ~AesEvpOperation();
+
+ 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;
+ keymaster_error_t Abort() override;
+
+ virtual int evp_encrypt_mode() = 0;
+
+ protected:
+ bool need_iv() const;
+ keymaster_error_t InitializeCipher();
+ keymaster_error_t GetIv(const AuthorizationSet& input_params);
+ bool HandleAad(const AuthorizationSet& input_params, const Buffer& input,
+ keymaster_error_t* error);
+ bool ProcessAadBlocks(const uint8_t* data, size_t blocks, keymaster_error_t* error);
+ void FillBufferedAadBlock(keymaster_blob_t* aad);
+ bool ProcessBufferedAadBlock(keymaster_error_t* error);
+ bool InternalUpdate(const uint8_t* input, size_t input_length, Buffer* output,
+ keymaster_error_t* error);
+ bool UpdateForFinish(const AuthorizationSet& additional_params, const Buffer& input,
+ AuthorizationSet* output_params, Buffer* output, keymaster_error_t* error);
+
+ const keymaster_block_mode_t block_mode_;
+ EVP_CIPHER_CTX ctx_;
+ UniquePtr<uint8_t[]> iv_;
+ size_t iv_length_;
+ const bool caller_iv_;
+ size_t tag_length_;
+ UniquePtr<uint8_t[]> aad_block_buf_;
+ size_t aad_block_buf_length_;
+
+ private:
+ bool data_started_;
+ const size_t key_size_;
+ const keymaster_padding_t padding_;
+ uint8_t key_[MAX_EVP_KEY_SIZE];
+};
+
+class AesEvpEncryptOperation : public AesEvpOperation {
+ public:
+ AesEvpEncryptOperation(keymaster_block_mode_t block_mode, keymaster_padding_t padding,
+ bool caller_iv, size_t tag_length, const uint8_t* key, size_t key_size)
+ : AesEvpOperation(KM_PURPOSE_ENCRYPT, block_mode, padding, caller_iv, tag_length, key,
+ key_size) {}
+
+ keymaster_error_t Begin(const AuthorizationSet& input_params,
+ AuthorizationSet* output_params) override;
+ keymaster_error_t Finish(const AuthorizationSet& additional_params, const Buffer& input,
+ const Buffer& signature, AuthorizationSet* output_params,
+ Buffer* output) override;
+
+ int evp_encrypt_mode() override { return 1; }
+
+ private:
+ keymaster_error_t GenerateIv();
+};
+
+class AesEvpDecryptOperation : public AesEvpOperation {
+ public:
+ AesEvpDecryptOperation(keymaster_block_mode_t block_mode, keymaster_padding_t padding,
+ size_t tag_length, const uint8_t* key, size_t key_size)
+ : AesEvpOperation(KM_PURPOSE_DECRYPT, block_mode, padding,
+ false /* caller_iv -- don't care */, tag_length, key, key_size) {}
+
+ 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;
+
+ int evp_encrypt_mode() override { return 0; }
+
+ private:
+ size_t tag_buf_unused() { return tag_length_ - tag_buf_length_; }
+
+ keymaster_error_t ProcessAllButTagLengthBytes(const Buffer& input, Buffer* output);
+ bool ProcessTagBufContentsAsData(size_t to_process, Buffer* output, keymaster_error_t* error);
+ void BufferCandidateTagData(const uint8_t* data, size_t data_length);
+
+ UniquePtr<uint8_t[]> tag_buf_;
+ size_t tag_buf_length_;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_AES_OPERATION_H_
diff --git a/keymaster/android_keymaster.cpp b/keymaster/android_keymaster.cpp
new file mode 100644
index 0000000..3a53394
--- /dev/null
+++ b/keymaster/android_keymaster.cpp
@@ -0,0 +1,440 @@
+/*
+ * Copyright 2014 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/android_keymaster.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <cstddef>
+
+#include <openssl/rand.h>
+#include <openssl/x509.h>
+
+#include <UniquePtr.h>
+
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/key_factory.h>
+#include <keymaster/keymaster_context.h>
+
+#include "ae.h"
+#include "key.h"
+#include "openssl_err.h"
+#include "operation.h"
+#include "operation_table.h"
+
+namespace keymaster {
+
+const uint8_t MAJOR_VER = 1;
+const uint8_t MINOR_VER = 1;
+const uint8_t SUBMINOR_VER = 0;
+
+AndroidKeymaster::AndroidKeymaster(KeymasterContext* context, size_t operation_table_size)
+ : context_(context), operation_table_(new OperationTable(operation_table_size)) {}
+
+AndroidKeymaster::~AndroidKeymaster() {}
+
+struct AE_CTX_Delete {
+ void operator()(ae_ctx* ctx) const { ae_free(ctx); }
+};
+typedef UniquePtr<ae_ctx, AE_CTX_Delete> Unique_ae_ctx;
+
+// TODO(swillden): Unify support analysis. Right now, we have per-keytype methods that determine if
+// specific modes, padding, etc. are supported for that key type, and AndroidKeymaster also has
+// methods that return the same information. They'll get out of sync. Best to put the knowledge in
+// the keytypes and provide some mechanism for AndroidKeymaster to query the keytypes for the
+// information.
+
+template <typename T>
+bool check_supported(const KeymasterContext& context, keymaster_algorithm_t algorithm,
+ SupportedResponse<T>* response) {
+ if (context.GetKeyFactory(algorithm) == NULL) {
+ response->error = KM_ERROR_UNSUPPORTED_ALGORITHM;
+ return false;
+ }
+ return true;
+}
+
+void AndroidKeymaster::GetVersion(const GetVersionRequest&, GetVersionResponse* rsp) {
+ if (rsp == NULL)
+ return;
+
+ rsp->major_ver = MAJOR_VER;
+ rsp->minor_ver = MINOR_VER;
+ rsp->subminor_ver = SUBMINOR_VER;
+ rsp->error = KM_ERROR_OK;
+}
+
+void AndroidKeymaster::SupportedAlgorithms(const SupportedAlgorithmsRequest& /* request */,
+ SupportedAlgorithmsResponse* response) {
+ if (response == NULL)
+ 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;
+ response->results_length = algorithm_count;
+ response->results = dup_array(algorithms, algorithm_count);
+ if (!response->results)
+ response->error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+}
+
+template <typename T>
+void GetSupported(const KeymasterContext& context, keymaster_algorithm_t algorithm,
+ keymaster_purpose_t purpose,
+ const T* (OperationFactory::*get_supported_method)(size_t* count) const,
+ SupportedResponse<T>* response) {
+ if (response == NULL || !check_supported(context, algorithm, response))
+ return;
+
+ const OperationFactory* factory = context.GetOperationFactory(algorithm, purpose);
+ if (!factory) {
+ response->error = KM_ERROR_UNSUPPORTED_PURPOSE;
+ return;
+ }
+
+ size_t count;
+ const T* supported = (factory->*get_supported_method)(&count);
+ response->SetResults(supported, count);
+}
+
+void AndroidKeymaster::SupportedBlockModes(const SupportedBlockModesRequest& request,
+ SupportedBlockModesResponse* response) {
+ GetSupported(*context_, request.algorithm, request.purpose,
+ &OperationFactory::SupportedBlockModes, response);
+}
+
+void AndroidKeymaster::SupportedPaddingModes(const SupportedPaddingModesRequest& request,
+ SupportedPaddingModesResponse* response) {
+ GetSupported(*context_, request.algorithm, request.purpose,
+ &OperationFactory::SupportedPaddingModes, response);
+}
+
+void AndroidKeymaster::SupportedDigests(const SupportedDigestsRequest& request,
+ SupportedDigestsResponse* response) {
+ GetSupported(*context_, request.algorithm, request.purpose, &OperationFactory::SupportedDigests,
+ response);
+}
+
+void AndroidKeymaster::SupportedImportFormats(const SupportedImportFormatsRequest& request,
+ SupportedImportFormatsResponse* response) {
+ if (response == NULL || !check_supported(*context_, request.algorithm, response))
+ return;
+
+ size_t count;
+ const keymaster_key_format_t* formats =
+ context_->GetKeyFactory(request.algorithm)->SupportedImportFormats(&count);
+ response->SetResults(formats, count);
+}
+
+void AndroidKeymaster::SupportedExportFormats(const SupportedExportFormatsRequest& request,
+ SupportedExportFormatsResponse* response) {
+ if (response == NULL || !check_supported(*context_, request.algorithm, response))
+ return;
+
+ size_t count;
+ const keymaster_key_format_t* formats =
+ context_->GetKeyFactory(request.algorithm)->SupportedExportFormats(&count);
+ response->SetResults(formats, count);
+}
+
+void AndroidKeymaster::AddRngEntropy(const AddEntropyRequest& request,
+ AddEntropyResponse* response) {
+ response->error = context_->AddRngEntropy(request.random_data.peek_read(),
+ request.random_data.available_read());
+}
+
+void AndroidKeymaster::GenerateKey(const GenerateKeyRequest& request,
+ GenerateKeyResponse* response) {
+ if (response == NULL)
+ return;
+
+ keymaster_algorithm_t algorithm;
+ KeyFactory* factory = 0;
+ 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();
+ }
+}
+
+void AndroidKeymaster::GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
+ GetKeyCharacteristicsResponse* response) {
+ if (response == NULL)
+ return;
+
+ KeymasterKeyBlob key_material;
+ response->error =
+ context_->ParseKeyBlob(KeymasterKeyBlob(request.key_blob), request.additional_params,
+ &key_material, &response->enforced, &response->unenforced);
+ if (response->error != KM_ERROR_OK)
+ return;
+}
+
+static KeyFactory* GetKeyFactory(const KeymasterContext& context,
+ const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ keymaster_algorithm_t* algorithm, keymaster_error_t* error) {
+ *error = KM_ERROR_UNSUPPORTED_ALGORITHM;
+ if (!hw_enforced.GetTagValue(TAG_ALGORITHM, algorithm) &&
+ !sw_enforced.GetTagValue(TAG_ALGORITHM, algorithm))
+ return nullptr;
+ KeyFactory* factory = context.GetKeyFactory(*algorithm);
+ if (factory)
+ *error = KM_ERROR_OK;
+ return factory;
+}
+
+void AndroidKeymaster::BeginOperation(const BeginOperationRequest& request,
+ BeginOperationResponse* response) {
+ if (response == NULL)
+ return;
+ response->op_handle = 0;
+
+ AuthorizationSet hw_enforced;
+ AuthorizationSet sw_enforced;
+ const KeyFactory* key_factory;
+ UniquePtr<Key> key;
+ response->error = LoadKey(request.key_blob, request.additional_params, &hw_enforced,
+ &sw_enforced, &key_factory, &key);
+ if (response->error != KM_ERROR_OK)
+ return;
+
+ response->error = KM_ERROR_UNKNOWN_ERROR;
+ keymaster_algorithm_t key_algorithm;
+ if (!key->authorizations().GetTagValue(TAG_ALGORITHM, &key_algorithm))
+ return;
+
+ response->error = KM_ERROR_UNSUPPORTED_PURPOSE;
+ OperationFactory* factory = key_factory->GetOperationFactory(request.purpose);
+ if (!factory)
+ return;
+
+ UniquePtr<Operation> operation(
+ factory->CreateOperation(*key, request.additional_params, &response->error));
+ if (operation.get() == NULL)
+ return;
+
+ if (context_->enforcement_policy()) {
+ km_id_t key_id;
+ response->error = KM_ERROR_UNKNOWN_ERROR;
+ if (!context_->enforcement_policy()->CreateKeyId(request.key_blob, &key_id))
+ return;
+ operation->set_key_id(key_id);
+ response->error = context_->enforcement_policy()->AuthorizeOperation(
+ request.purpose, key_id, key->authorizations(), request.additional_params,
+ 0 /* op_handle */, true /* is_begin_operation */);
+ if (response->error != KM_ERROR_OK)
+ return;
+ }
+
+ response->output_params.Clear();
+ response->error = operation->Begin(request.additional_params, &response->output_params);
+ if (response->error != KM_ERROR_OK)
+ return;
+
+ operation->SetAuthorizations(key->authorizations());
+ response->error = operation_table_->Add(operation.release(), &response->op_handle);
+}
+
+void AndroidKeymaster::UpdateOperation(const UpdateOperationRequest& request,
+ UpdateOperationResponse* response) {
+ if (response == NULL)
+ return;
+
+ response->error = KM_ERROR_INVALID_OPERATION_HANDLE;
+ Operation* operation = operation_table_->Find(request.op_handle);
+ if (operation == NULL)
+ return;
+
+ if (context_->enforcement_policy()) {
+ response->error = context_->enforcement_policy()->AuthorizeOperation(
+ operation->purpose(), operation->key_id(), operation->authorizations(),
+ request.additional_params, request.op_handle, false /* is_begin_operation */);
+ if (response->error != KM_ERROR_OK) {
+ operation_table_->Delete(request.op_handle);
+ return;
+ }
+ }
+
+ response->error =
+ operation->Update(request.additional_params, request.input, &response->output_params,
+ &response->output, &response->input_consumed);
+ if (response->error != KM_ERROR_OK) {
+ // Any error invalidates the operation.
+ operation_table_->Delete(request.op_handle);
+ }
+}
+
+void AndroidKeymaster::FinishOperation(const FinishOperationRequest& request,
+ FinishOperationResponse* response) {
+ if (response == NULL)
+ return;
+
+ response->error = KM_ERROR_INVALID_OPERATION_HANDLE;
+ Operation* operation = operation_table_->Find(request.op_handle);
+ if (operation == NULL)
+ return;
+
+ if (context_->enforcement_policy()) {
+ response->error = context_->enforcement_policy()->AuthorizeOperation(
+ operation->purpose(), operation->key_id(), operation->authorizations(),
+ request.additional_params, request.op_handle, false /* is_begin_operation */);
+ if (response->error != KM_ERROR_OK) {
+ operation_table_->Delete(request.op_handle);
+ return;
+ }
+ }
+
+ response->error = operation->Finish(request.additional_params, request.input, request.signature,
+ &response->output_params, &response->output);
+ operation_table_->Delete(request.op_handle);
+}
+
+void AndroidKeymaster::AbortOperation(const AbortOperationRequest& request,
+ AbortOperationResponse* response) {
+ if (!response)
+ return;
+
+ Operation* operation = operation_table_->Find(request.op_handle);
+ if (!operation) {
+ response->error = KM_ERROR_INVALID_OPERATION_HANDLE;
+ return;
+ }
+
+ response->error = operation->Abort();
+ operation_table_->Delete(request.op_handle);
+}
+
+void AndroidKeymaster::ExportKey(const ExportKeyRequest& request, ExportKeyResponse* response) {
+ if (response == NULL)
+ return;
+
+ AuthorizationSet hw_enforced;
+ AuthorizationSet sw_enforced;
+ KeymasterKeyBlob key_material;
+ response->error =
+ context_->ParseKeyBlob(KeymasterKeyBlob(request.key_blob), request.additional_params,
+ &key_material, &hw_enforced, &sw_enforced);
+ if (response->error != KM_ERROR_OK)
+ return;
+
+ keymaster_algorithm_t algorithm;
+ KeyFactory* key_factory =
+ GetKeyFactory(*context_, hw_enforced, sw_enforced, &algorithm, &response->error);
+ if (!key_factory)
+ return;
+
+ UniquePtr<Key> key;
+ response->error = key_factory->LoadKey(key_material, request.additional_params, hw_enforced,
+ sw_enforced, &key);
+ if (response->error != KM_ERROR_OK)
+ return;
+
+ UniquePtr<uint8_t[]> out_key;
+ size_t size;
+ response->error = key->formatted_key_material(request.key_format, &out_key, &size);
+ if (response->error == KM_ERROR_OK) {
+ response->key_data = out_key.release();
+ response->key_data_length = size;
+ }
+}
+
+void AndroidKeymaster::AttestKey(const AttestKeyRequest& request, AttestKeyResponse* response) {
+ if (!response)
+ return;
+
+ AuthorizationSet tee_enforced;
+ AuthorizationSet sw_enforced;
+ const KeyFactory* key_factory;
+ UniquePtr<Key> key;
+ response->error = LoadKey(request.key_blob, request.attest_params, &tee_enforced, &sw_enforced,
+ &key_factory, &key);
+ if (response->error != KM_ERROR_OK)
+ return;
+
+ response->error = key->GenerateAttestation(*context_, request.attest_params, tee_enforced,
+ sw_enforced, &response->certificate_chain);
+}
+
+void AndroidKeymaster::ImportKey(const ImportKeyRequest& request, ImportKeyResponse* response) {
+ if (response == NULL)
+ return;
+
+ keymaster_algorithm_t algorithm;
+ KeyFactory* factory = 0;
+ 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();
+ }
+}
+
+void AndroidKeymaster::DeleteKey(const DeleteKeyRequest& request, DeleteKeyResponse* response) {
+ if (!response)
+ return;
+ response->error = context_->DeleteKey(KeymasterKeyBlob(request.key_blob));
+}
+
+void AndroidKeymaster::DeleteAllKeys(const DeleteAllKeysRequest&, DeleteAllKeysResponse* response) {
+ if (!response)
+ return;
+ response->error = context_->DeleteAllKeys();
+}
+
+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,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced,
+ const KeyFactory** factory, UniquePtr<Key>* key) {
+ KeymasterKeyBlob key_material;
+ keymaster_error_t error = context_->ParseKeyBlob(KeymasterKeyBlob(key_blob), additional_params,
+ &key_material, hw_enforced, sw_enforced);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ keymaster_algorithm_t algorithm;
+ *factory = GetKeyFactory(*context_, *hw_enforced, *sw_enforced, &algorithm, &error);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ return (*factory)->LoadKey(key_material, additional_params, *hw_enforced, *sw_enforced, key);
+}
+
+} // namespace keymaster
diff --git a/keymaster/android_keymaster_messages.cpp b/keymaster/android_keymaster_messages.cpp
new file mode 100644
index 0000000..1b8f36e
--- /dev/null
+++ b/keymaster/android_keymaster_messages.cpp
@@ -0,0 +1,526 @@
+/*
+ * Copyright 2014 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/android_keymaster_messages.h>
+#include <keymaster/android_keymaster_utils.h>
+
+namespace keymaster {
+
+/*
+ * 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) {
+ 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) {
+ 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) {
+ 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) {
+ delete[] key_blob->key_material;
+ key_blob->key_material = 0;
+ UniquePtr<uint8_t[]> deserialized_key_material;
+ if (!copy_size_and_data_from_buf(buf_ptr, end, &key_blob->key_material_size,
+ &deserialized_key_material))
+ return false;
+ key_blob->key_material = deserialized_key_material.release();
+ return true;
+}
+
+size_t KeymasterResponse::SerializedSize() const {
+ if (error != KM_ERROR_OK)
+ return sizeof(int32_t);
+ else
+ return sizeof(int32_t) + NonErrorSerializedSize();
+}
+
+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);
+ 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;
+ return NonErrorDeserialize(buf_ptr, end);
+}
+
+GenerateKeyResponse::~GenerateKeyResponse() {
+ delete[] key_blob.key_material;
+}
+
+size_t GenerateKeyResponse::NonErrorSerializedSize() const {
+ return key_blob_size(key_blob) + enforced.SerializedSize() + unenforced.SerializedSize();
+}
+
+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);
+}
+
+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);
+}
+
+GetKeyCharacteristicsRequest::~GetKeyCharacteristicsRequest() {
+ delete[] key_blob.key_material;
+}
+
+void GetKeyCharacteristicsRequest::SetKeyMaterial(const void* key_material, size_t length) {
+ set_key_blob(&key_blob, key_material, length);
+}
+
+size_t GetKeyCharacteristicsRequest::SerializedSize() const {
+ return key_blob_size(key_blob) + additional_params.SerializedSize();
+}
+
+uint8_t* GetKeyCharacteristicsRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
+ buf = serialize_key_blob(key_blob, buf, end);
+ return additional_params.Serialize(buf, end);
+}
+
+bool GetKeyCharacteristicsRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+ return deserialize_key_blob(&key_blob, buf_ptr, end) &&
+ additional_params.Deserialize(buf_ptr, end);
+}
+
+size_t GetKeyCharacteristicsResponse::NonErrorSerializedSize() const {
+ return enforced.SerializedSize() + unenforced.SerializedSize();
+}
+
+uint8_t* GetKeyCharacteristicsResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
+ buf = enforced.Serialize(buf, end);
+ return unenforced.Serialize(buf, end);
+}
+
+bool GetKeyCharacteristicsResponse::NonErrorDeserialize(const uint8_t** buf_ptr,
+ const uint8_t* end) {
+ return enforced.Deserialize(buf_ptr, end) && unenforced.Deserialize(buf_ptr, end);
+}
+
+void BeginOperationRequest::SetKeyMaterial(const void* key_material, size_t length) {
+ set_key_blob(&key_blob, key_material, length);
+}
+
+size_t BeginOperationRequest::SerializedSize() const {
+ return sizeof(uint32_t) /* purpose */ + key_blob_size(key_blob) +
+ additional_params.SerializedSize();
+}
+
+uint8_t* BeginOperationRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
+ buf = append_uint32_to_buf(buf, end, purpose);
+ buf = serialize_key_blob(key_blob, buf, end);
+ return additional_params.Serialize(buf, end);
+}
+
+bool BeginOperationRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+ return copy_uint32_from_buf(buf_ptr, end, &purpose) &&
+ deserialize_key_blob(&key_blob, buf_ptr, end) &&
+ additional_params.Deserialize(buf_ptr, end);
+}
+
+size_t BeginOperationResponse::NonErrorSerializedSize() const {
+ if (message_version == 0)
+ return sizeof(op_handle);
+ else
+ return sizeof(op_handle) + output_params.SerializedSize();
+}
+
+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);
+ 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);
+ return retval;
+}
+
+size_t UpdateOperationRequest::SerializedSize() const {
+ if (message_version == 0)
+ return sizeof(op_handle) + input.SerializedSize();
+ else
+ return sizeof(op_handle) + input.SerializedSize() + additional_params.SerializedSize();
+}
+
+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);
+ 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);
+ return retval;
+}
+
+size_t UpdateOperationResponse::NonErrorSerializedSize() const {
+ size_t size = 0;
+ switch (message_version) {
+ case 3:
+ case 2:
+ size += output_params.SerializedSize();
+ ; /* falls through */
+ case 1:
+ size += sizeof(uint32_t);
+ ; /* falls through */
+ case 0:
+ size += output.SerializedSize();
+ break;
+
+ default:
+ assert(false);
+ }
+
+ return size;
+}
+
+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);
+ 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);
+ return retval;
+}
+
+size_t FinishOperationRequest::SerializedSize() const {
+ size_t size = 0;
+ switch (message_version) {
+ case 3:
+ size += input.SerializedSize();
+ ; /* falls through */
+ case 2:
+ case 1:
+ size += additional_params.SerializedSize();
+ ; /* falls through */
+ case 0:
+ size += sizeof(op_handle) + signature.SerializedSize();
+ break;
+
+ default:
+ assert(false); // Should never get here.
+ }
+
+ return size;
+}
+
+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);
+ 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);
+ return retval;
+}
+
+size_t FinishOperationResponse::NonErrorSerializedSize() const {
+ if (message_version < 2)
+ return output.SerializedSize();
+ else
+ return output.SerializedSize() + output_params.SerializedSize();
+}
+
+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);
+ 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);
+ return retval;
+}
+
+size_t AddEntropyRequest::SerializedSize() const {
+ return random_data.SerializedSize();
+}
+
+uint8_t* AddEntropyRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
+ return random_data.Serialize(buf, end);
+}
+
+bool AddEntropyRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+ 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;
+}
+
+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);
+}
+
+bool ImportKeyRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+ delete[] key_data;
+ key_data = NULL;
+ 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))
+ return false;
+ key_data = deserialized_key_material.release();
+ return true;
+}
+
+void ImportKeyResponse::SetKeyMaterial(const void* key_material, size_t length) {
+ set_key_blob(&key_blob, key_material, length);
+}
+
+size_t ImportKeyResponse::NonErrorSerializedSize() const {
+ return key_blob_size(key_blob) + enforced.SerializedSize() + unenforced.SerializedSize();
+}
+
+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);
+}
+
+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);
+}
+
+void ExportKeyRequest::SetKeyMaterial(const void* key_material, size_t length) {
+ set_key_blob(&key_blob, key_material, length);
+}
+
+size_t ExportKeyRequest::SerializedSize() const {
+ return additional_params.SerializedSize() + sizeof(uint32_t) /* key_format */ +
+ key_blob_size(key_blob);
+}
+
+uint8_t* ExportKeyRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
+ buf = additional_params.Serialize(buf, end);
+ buf = append_uint32_to_buf(buf, end, key_format);
+ return serialize_key_blob(key_blob, buf, end);
+}
+
+bool ExportKeyRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+ return additional_params.Deserialize(buf_ptr, end) &&
+ copy_uint32_from_buf(buf_ptr, end, &key_format) &&
+ deserialize_key_blob(&key_blob, buf_ptr, end);
+}
+
+void ExportKeyResponse::SetKeyMaterial(const void* key_material, size_t length) {
+ delete[] key_data;
+ key_data = dup_buffer(key_material, length);
+ key_data_length = length;
+}
+
+size_t ExportKeyResponse::NonErrorSerializedSize() const {
+ return sizeof(uint32_t) /* key_data_length */ + key_data_length;
+}
+
+uint8_t* ExportKeyResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
+ return append_size_and_data_to_buf(buf, end, key_data, key_data_length);
+}
+
+bool ExportKeyResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+ delete[] key_data;
+ key_data = NULL;
+ UniquePtr<uint8_t[]> deserialized_key_material;
+ if (!copy_size_and_data_from_buf(buf_ptr, end, &key_data_length, &deserialized_key_material))
+ return false;
+ key_data = deserialized_key_material.release();
+ return true;
+}
+
+void DeleteKeyRequest::SetKeyMaterial(const void* key_material, size_t length) {
+ set_key_blob(&key_blob, key_material, length);
+}
+
+size_t DeleteKeyRequest::SerializedSize() const {
+ return key_blob_size(key_blob);
+}
+
+uint8_t* DeleteKeyRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
+ return serialize_key_blob(key_blob, buf, end);
+}
+
+bool DeleteKeyRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+ return deserialize_key_blob(&key_blob, buf_ptr, end);
+}
+
+size_t GetVersionResponse::NonErrorSerializedSize() const {
+ return sizeof(major_ver) + sizeof(minor_ver) + sizeof(subminor_ver);
+}
+
+uint8_t* GetVersionResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
+ if (buf + NonErrorSerializedSize() <= end) {
+ *buf++ = major_ver;
+ *buf++ = minor_ver;
+ *buf++ = subminor_ver;
+ } else {
+ buf += NonErrorSerializedSize();
+ }
+ return buf;
+}
+
+bool GetVersionResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+ if (*buf_ptr + NonErrorSerializedSize() > end)
+ return false;
+ const uint8_t* tmp = *buf_ptr;
+ major_ver = *tmp++;
+ minor_ver = *tmp++;
+ subminor_ver = *tmp++;
+ *buf_ptr = tmp;
+ return true;
+}
+
+AttestKeyRequest::~AttestKeyRequest() {
+ delete[] key_blob.key_material;
+}
+
+void AttestKeyRequest::SetKeyMaterial(const void* key_material, size_t length) {
+ set_key_blob(&key_blob, key_material, length);
+}
+
+size_t AttestKeyRequest::SerializedSize() const {
+ return key_blob_size(key_blob) + attest_params.SerializedSize();
+}
+
+uint8_t* AttestKeyRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
+ buf = serialize_key_blob(key_blob, buf, end);
+ return attest_params.Serialize(buf, end);
+}
+
+bool AttestKeyRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+ 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 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;
+}
+
+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;
+}
+
+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;
+}
+
+} // namespace keymaster
diff --git a/keymaster/android_keymaster_messages_test.cpp b/keymaster/android_keymaster_messages_test.cpp
new file mode 100644
index 0000000..1ec5894
--- /dev/null
+++ b/keymaster/android_keymaster_messages_test.cpp
@@ -0,0 +1,683 @@
+/*
+ * Copyright (C) 2014 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 <UniquePtr.h>
+
+#include <gtest/gtest.h>
+
+#include <keymaster/android_keymaster.h>
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/keymaster_tags.h>
+
+#include "android_keymaster_test_utils.h"
+
+namespace keymaster {
+namespace test {
+
+/**
+ * Serialize and deserialize a message.
+ */
+template <typename Message>
+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 NULL;
+
+ UniquePtr<uint8_t[]> buf(new uint8_t[size]);
+ EXPECT_EQ(buf.get() + size, message.Serialize(buf.get(), buf.get() + size));
+
+ Message* deserialized = new Message(ver);
+ const uint8_t* p = buf.get();
+ EXPECT_TRUE(deserialized->Deserialize(&p, p + size));
+ EXPECT_EQ((ptrdiff_t)size, p - buf.get());
+ 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) {
+ 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;
+
+ 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)));
+ }
+}
+
+static 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_USER_AUTH_TYPE, HW_AUTH_PASSWORD),
+ Authorization(TAG_APPLICATION_ID, "app_id", 6),
+ Authorization(TAG_AUTH_TIMEOUT, 300),
+};
+uint8_t TEST_DATA[] = "a key blob";
+
+TEST(RoundTrip, GenerateKeyRequest) {
+ for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+ GenerateKeyRequest req(ver);
+ req.key_description.Reinitialize(params, array_length(params));
+ UniquePtr<GenerateKeyRequest> deserialized(round_trip(ver, req, 78));
+ EXPECT_EQ(deserialized->key_description, req.key_description);
+ }
+}
+
+TEST(RoundTrip, GenerateKeyResponse) {
+ for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++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));
+ EXPECT_EQ(KM_ERROR_OK, deserialized->error);
+ EXPECT_EQ(deserialized->enforced, rsp.enforced);
+ EXPECT_EQ(deserialized->unenforced, rsp.unenforced);
+ }
+}
+
+TEST(RoundTrip, GenerateKeyResponseTestError) {
+ for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+ GenerateKeyResponse rsp(ver);
+ rsp.error = KM_ERROR_UNSUPPORTED_ALGORITHM;
+ 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, 4));
+ EXPECT_EQ(KM_ERROR_UNSUPPORTED_ALGORITHM, deserialized->error);
+ EXPECT_EQ(0U, deserialized->enforced.size());
+ EXPECT_EQ(0U, deserialized->unenforced.size());
+ EXPECT_EQ(0U, deserialized->key_blob.key_material_size);
+ }
+}
+
+TEST(RoundTrip, GetKeyCharacteristicsRequest) {
+ for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+ GetKeyCharacteristicsRequest req(ver);
+ req.additional_params.Reinitialize(params, array_length(params));
+ req.SetKeyMaterial("foo", 3);
+
+ UniquePtr<GetKeyCharacteristicsRequest> deserialized(round_trip(ver, req, 85));
+ EXPECT_EQ(7U, deserialized->additional_params.size());
+ EXPECT_EQ(3U, deserialized->key_blob.key_material_size);
+ EXPECT_EQ(0, memcmp(deserialized->key_blob.key_material, "foo", 3));
+ }
+}
+
+TEST(RoundTrip, GetKeyCharacteristicsResponse) {
+ for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+ GetKeyCharacteristicsResponse msg(ver);
+ msg.error = KM_ERROR_OK;
+ msg.enforced.Reinitialize(params, array_length(params));
+ msg.unenforced.Reinitialize(params, array_length(params));
+
+ UniquePtr<GetKeyCharacteristicsResponse> deserialized(round_trip(ver, msg, 160));
+ EXPECT_EQ(msg.enforced, deserialized->enforced);
+ EXPECT_EQ(msg.unenforced, deserialized->unenforced);
+ }
+}
+
+TEST(RoundTrip, BeginOperationRequest) {
+ for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+ BeginOperationRequest msg(ver);
+ msg.purpose = KM_PURPOSE_SIGN;
+ msg.SetKeyMaterial("foo", 3);
+ msg.additional_params.Reinitialize(params, array_length(params));
+
+ UniquePtr<BeginOperationRequest> deserialized(round_trip(ver, msg, 89));
+ EXPECT_EQ(KM_PURPOSE_SIGN, deserialized->purpose);
+ EXPECT_EQ(3U, deserialized->key_blob.key_material_size);
+ EXPECT_EQ(0, memcmp(deserialized->key_blob.key_material, "foo", 3));
+ EXPECT_EQ(msg.additional_params, deserialized->additional_params);
+ }
+}
+
+TEST(RoundTrip, BeginOperationResponse) {
+ for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+ BeginOperationResponse msg(ver);
+ msg.error = KM_ERROR_OK;
+ msg.op_handle = 0xDEADBEEF;
+ msg.output_params.push_back(Authorization(TAG_NONCE, "foo", 3));
+
+ UniquePtr<BeginOperationResponse> deserialized;
+ switch (ver) {
+ case 0:
+ deserialized.reset(round_trip(ver, msg, 12));
+ break;
+ case 1:
+ case 2:
+ case 3:
+ deserialized.reset(round_trip(ver, msg, 39));
+ break;
+ default:
+ FAIL();
+ }
+
+ EXPECT_EQ(KM_ERROR_OK, deserialized->error);
+ EXPECT_EQ(0xDEADBEEF, deserialized->op_handle);
+
+ switch (ver) {
+ case 0:
+ EXPECT_EQ(0U, deserialized->output_params.size());
+ break;
+ case 1:
+ case 2:
+ case 3:
+ EXPECT_EQ(msg.output_params, deserialized->output_params);
+ break;
+ default:
+ FAIL();
+ }
+ }
+}
+
+TEST(RoundTrip, BeginOperationResponseError) {
+ for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+ BeginOperationResponse msg(ver);
+ msg.error = KM_ERROR_INVALID_OPERATION_HANDLE;
+ msg.op_handle = 0xDEADBEEF;
+
+ UniquePtr<BeginOperationResponse> deserialized(round_trip(ver, msg, 4));
+ EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, deserialized->error);
+ }
+}
+
+TEST(RoundTrip, UpdateOperationRequest) {
+ for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+ UpdateOperationRequest msg(ver);
+ msg.op_handle = 0xDEADBEEF;
+ msg.input.Reinitialize("foo", 3);
+
+ UniquePtr<UpdateOperationRequest> deserialized;
+ switch (ver) {
+ case 0:
+ deserialized.reset(round_trip(ver, msg, 15));
+ break;
+ case 1:
+ case 2:
+ case 3:
+ deserialized.reset(round_trip(ver, msg, 27));
+ break;
+ default:
+ FAIL();
+ }
+ EXPECT_EQ(3U, deserialized->input.available_read());
+ EXPECT_EQ(0, memcmp(deserialized->input.peek_read(), "foo", 3));
+ }
+}
+
+TEST(RoundTrip, UpdateOperationResponse) {
+ for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+ UpdateOperationResponse msg(ver);
+ msg.error = KM_ERROR_OK;
+ msg.output.Reinitialize("foo", 3);
+ msg.input_consumed = 99;
+ msg.output_params.push_back(TAG_APPLICATION_ID, "bar", 3);
+
+ UniquePtr<UpdateOperationResponse> deserialized;
+ switch (ver) {
+ case 0:
+ deserialized.reset(round_trip(ver, msg, 11));
+ break;
+ case 1:
+ deserialized.reset(round_trip(ver, msg, 15));
+ break;
+ case 2:
+ case 3:
+ deserialized.reset(round_trip(ver, msg, 42));
+ break;
+ default:
+ FAIL();
+ }
+ EXPECT_EQ(KM_ERROR_OK, deserialized->error);
+ EXPECT_EQ(3U, deserialized->output.available_read());
+ EXPECT_EQ(0, memcmp(deserialized->output.peek_read(), "foo", 3));
+
+ switch (ver) {
+ case 0:
+ EXPECT_EQ(0U, deserialized->input_consumed);
+ break;
+ case 1:
+ EXPECT_EQ(99U, deserialized->input_consumed);
+ break;
+ case 2:
+ case 3:
+ EXPECT_EQ(99U, deserialized->input_consumed);
+ EXPECT_EQ(1U, deserialized->output_params.size());
+ break;
+ default:
+ FAIL();
+ }
+ }
+}
+
+TEST(RoundTrip, FinishOperationRequest) {
+ for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+ FinishOperationRequest msg(ver);
+ msg.op_handle = 0xDEADBEEF;
+ msg.signature.Reinitialize("bar", 3);
+ msg.input.Reinitialize("baz", 3);
+
+ UniquePtr<FinishOperationRequest> deserialized;
+ switch (ver) {
+ case 0:
+ deserialized.reset(round_trip(ver, msg, 15));
+ break;
+ case 1:
+ case 2:
+ deserialized.reset(round_trip(ver, msg, 27));
+ break;
+ case 3:
+ deserialized.reset(round_trip(ver, msg, 34));
+ break;
+ default:
+ FAIL();
+ }
+ EXPECT_EQ(0xDEADBEEF, deserialized->op_handle);
+ EXPECT_EQ(3U, deserialized->signature.available_read());
+ EXPECT_EQ(0, memcmp(deserialized->signature.peek_read(), "bar", 3));
+ }
+}
+
+TEST(Round_Trip, FinishOperationResponse) {
+ for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+ FinishOperationResponse msg(ver);
+ msg.error = KM_ERROR_OK;
+ msg.output.Reinitialize("foo", 3);
+
+ UniquePtr<FinishOperationResponse> deserialized;
+ switch (ver) {
+ case 0:
+ case 1:
+ deserialized.reset(round_trip(ver, msg, 11));
+ break;
+ case 2:
+ case 3:
+ deserialized.reset(round_trip(ver, msg, 23));
+ break;
+ default:
+ FAIL();
+ }
+ EXPECT_EQ(msg.error, deserialized->error);
+ EXPECT_EQ(msg.output.available_read(), deserialized->output.available_read());
+ EXPECT_EQ(0, memcmp(msg.output.peek_read(), deserialized->output.peek_read(),
+ msg.output.available_read()));
+ }
+}
+
+TEST(RoundTrip, ImportKeyRequest) {
+ for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+ ImportKeyRequest msg(ver);
+ msg.key_description.Reinitialize(params, array_length(params));
+ msg.key_format = KM_KEY_FORMAT_X509;
+ msg.SetKeyMaterial("foo", 3);
+
+ UniquePtr<ImportKeyRequest> deserialized(round_trip(ver, msg, 89));
+ 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));
+ }
+}
+
+TEST(RoundTrip, ImportKeyResponse) {
+ for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++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));
+ 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);
+ }
+}
+
+TEST(RoundTrip, ExportKeyRequest) {
+ for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+ ExportKeyRequest msg(ver);
+ msg.additional_params.Reinitialize(params, array_length(params));
+ msg.key_format = KM_KEY_FORMAT_X509;
+ msg.SetKeyMaterial("foo", 3);
+
+ UniquePtr<ExportKeyRequest> deserialized(round_trip(ver, msg, 89));
+ EXPECT_EQ(msg.additional_params, deserialized->additional_params);
+ EXPECT_EQ(msg.key_format, deserialized->key_format);
+ EXPECT_EQ(3U, deserialized->key_blob.key_material_size);
+ EXPECT_EQ(0, memcmp("foo", deserialized->key_blob.key_material, 3));
+ }
+}
+
+TEST(RoundTrip, ExportKeyResponse) {
+ for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+ ExportKeyResponse msg(ver);
+ msg.error = KM_ERROR_OK;
+ msg.SetKeyMaterial("foo", 3);
+
+ UniquePtr<ExportKeyResponse> deserialized(round_trip(ver, msg, 11));
+ EXPECT_EQ(3U, deserialized->key_data_length);
+ EXPECT_EQ(0, memcmp("foo", deserialized->key_data, 3));
+ }
+}
+
+TEST(RoundTrip, DeleteKeyRequest) {
+ for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+ DeleteKeyRequest msg(ver);
+ msg.SetKeyMaterial("foo", 3);
+
+ UniquePtr<DeleteKeyRequest> deserialized(round_trip(ver, msg, 7));
+ EXPECT_EQ(3U, deserialized->key_blob.key_material_size);
+ EXPECT_EQ(0, memcmp("foo", deserialized->key_blob.key_material, 3));
+ }
+}
+
+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) {
+ 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;
+
+ size_t size = msg.SerializedSize();
+ ASSERT_EQ(0U, size);
+
+ UniquePtr<uint8_t[]> buf(new uint8_t[size]);
+ EXPECT_EQ(buf.get() + size, msg.Serialize(buf.get(), buf.get() + size));
+
+ GetVersionRequest deserialized;
+ const uint8_t* p = buf.get();
+ EXPECT_TRUE(deserialized.Deserialize(&p, p + size));
+ EXPECT_EQ((ptrdiff_t)size, p - buf.get());
+}
+
+TEST(RoundTrip, GetVersionResponse) {
+ GetVersionResponse msg;
+ msg.error = KM_ERROR_OK;
+ msg.major_ver = 9;
+ msg.minor_ver = 98;
+ msg.subminor_ver = 38;
+
+ size_t size = msg.SerializedSize();
+ ASSERT_EQ(7U, size);
+
+ UniquePtr<uint8_t[]> buf(new uint8_t[size]);
+ EXPECT_EQ(buf.get() + size, msg.Serialize(buf.get(), buf.get() + size));
+
+ GetVersionResponse deserialized;
+ const uint8_t* p = buf.get();
+ EXPECT_TRUE(deserialized.Deserialize(&p, p + size));
+ EXPECT_EQ((ptrdiff_t)size, p - buf.get());
+ EXPECT_EQ(9U, msg.major_ver);
+ EXPECT_EQ(98U, msg.minor_ver);
+ EXPECT_EQ(38U, msg.subminor_ver);
+}
+
+TEST(RoundTrip, AddEntropyRequest) {
+ for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+ AddEntropyRequest msg(ver);
+ msg.random_data.Reinitialize("foo", 3);
+
+ UniquePtr<AddEntropyRequest> deserialized(round_trip(ver, msg, 7));
+ EXPECT_EQ(3U, deserialized->random_data.available_read());
+ EXPECT_EQ(0, memcmp("foo", deserialized->random_data.peek_read(), 3));
+ }
+}
+
+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) {
+ 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) {
+ AttestKeyRequest msg(ver);
+ msg.SetKeyMaterial("foo", 3);
+ msg.attest_params.Reinitialize(params, array_length(params));
+
+ UniquePtr<AttestKeyRequest> deserialized(round_trip(ver, msg, 85));
+ EXPECT_EQ(3U, deserialized->key_blob.key_material_size);
+ EXPECT_EQ(0, memcmp("foo", deserialized->key_blob.key_material, 3));
+ EXPECT_EQ(msg.attest_params, deserialized->attest_params);
+ }
+}
+
+TEST(RoundTrip, AttestKeyResponse) {
+ for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+ AttestKeyResponse msg(ver);
+ msg.error = KM_ERROR_OK;
+ EXPECT_TRUE(msg.AllocateChain(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<AttestKeyResponse> deserialized(round_trip(ver, msg, 29));
+ keymaster_cert_chain_t* chain = &deserialized->certificate_chain;
+
+ 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));
+ }
+}
+
+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,
+ 237, 79, 87, 32, 94, 5, 204, 46, 154, 30, 91, 6, 103, 148, 254, 129, 65, 171, 228,
+ 167, 224, 163, 9, 15, 206, 90, 58, 11, 205, 55, 211, 33, 87, 178, 149, 91, 28, 236,
+ 218, 112, 231, 34, 82, 82, 134, 103, 137, 115, 27, 156, 102, 159, 220, 226, 89, 42, 25,
+ 37, 9, 84, 239, 76, 161, 198, 72, 167, 163, 39, 91, 148, 191, 17, 191, 87, 169, 179,
+ 136, 10, 194, 154, 4, 40, 107, 109, 61, 161, 20, 176, 247, 13, 214, 106, 229, 45, 17,
+ 5, 60, 189, 64, 39, 166, 208, 14, 57, 25, 140, 148, 25, 177, 246, 189, 43, 181, 88,
+ 204, 29, 126, 224, 100, 143, 93, 60, 57, 249, 55, 0, 87, 83, 227, 224, 166, 59, 214,
+ 81, 144, 129, 58, 6, 57, 46, 254, 232, 41, 220, 209, 230, 167, 138, 158, 94, 180, 125,
+ 247, 26, 162, 116, 238, 202, 187, 100, 65, 13, 180, 44, 245, 159, 83, 161, 176, 58, 72,
+ 236, 109, 105, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 11, 0, 0, 0, 98, 0, 0, 0, 1, 0, 0, 32, 2, 0, 0, 0, 1, 0,
+ 0, 32, 3, 0, 0, 0, 2, 0, 0, 16, 1, 0, 0, 0, 3, 0, 0, 48, 0,
+ 1, 0, 0, 200, 0, 0, 80, 3, 0, 0, 0, 0, 0, 0, 0, 244, 1, 0, 112,
+ 1, 246, 1, 0, 112, 1, 189, 2, 0, 96, 144, 178, 236, 250, 255, 255, 255, 255, 145,
+ 1, 0, 96, 144, 226, 33, 60, 222, 2, 0, 0, 189, 2, 0, 96, 0, 0, 0, 0,
+ 0, 0, 0, 0, 190, 2, 0, 16, 1, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 11, 0,
+ 0, 0, 98, 0, 0, 0, 1, 0, 0, 32, 2, 0, 0, 0, 1, 0, 0, 32, 3,
+ 0, 0, 0, 2, 0, 0, 16, 1, 0, 0, 0, 3, 0, 0, 48, 0, 1, 0, 0,
+ 200, 0, 0, 80, 3, 0, 0, 0, 0, 0, 0, 0, 244, 1, 0, 112, 1, 246, 1,
+ 0, 112, 1, 189, 2, 0, 96, 144, 178, 236, 250, 255, 255, 255, 255, 145, 1, 0, 96,
+ 144, 226, 33, 60, 222, 2, 0, 0, 189, 2, 0, 96, 0, 0, 0, 0, 0, 0, 0,
+ 0, 190, 2, 0, 16, 1, 0, 0, 0,
+};
+
+/*
+ * These tests don't have any assertions or expectations. They just try to parse garbage, to see if
+ * the result will be a crash. This is especially informative when run under Valgrind memcheck.
+ */
+
+template <typename Message> void parse_garbage() {
+ for (int32_t ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+ Message msg(ver);
+ const uint8_t* end = msgbuf + array_length(msgbuf);
+ for (size_t i = 0; i < array_length(msgbuf); ++i) {
+ const uint8_t* begin = msgbuf + i;
+ const uint8_t* p = begin;
+ msg.Deserialize(&p, end);
+ }
+ }
+
+ time_t now = time(NULL);
+ std::cout << "Seeding rand() with " << now << " for fuzz test." << std::endl;
+ srand(now);
+
+ // Fill large buffer with random bytes.
+ const int kBufSize = 10000;
+ UniquePtr<uint8_t[]> buf(new uint8_t[kBufSize]);
+ 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) {
+ Message msg(ver);
+ const uint8_t* end = buf.get() + kBufSize;
+ for (size_t i = 0; i < kBufSize; ++i) {
+ const uint8_t* begin = buf.get() + i;
+ const uint8_t* p = begin;
+ msg.Deserialize(&p, end);
+ }
+ }
+}
+
+#define GARBAGE_TEST(Message) \
+ TEST(GarbageTest, Message) { parse_garbage<Message>(); }
+
+GARBAGE_TEST(AbortOperationRequest);
+GARBAGE_TEST(AbortOperationResponse);
+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);
+GARBAGE_TEST(FinishOperationResponse);
+GARBAGE_TEST(GenerateKeyRequest);
+GARBAGE_TEST(GenerateKeyResponse);
+GARBAGE_TEST(GetKeyCharacteristicsRequest);
+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);
+
+// The macro doesn't work on this one.
+TEST(GarbageTest, SupportedResponse) {
+ parse_garbage<SupportedResponse<keymaster_digest_t>>();
+}
+
+} // namespace test
+
+} // namespace keymaster
diff --git a/keymaster/android_keymaster_test.cpp b/keymaster/android_keymaster_test.cpp
new file mode 100644
index 0000000..ddc9783
--- /dev/null
+++ b/keymaster/android_keymaster_test.cpp
@@ -0,0 +1,3599 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#include <hardware/keymaster0.h>
+#include <keymaster/key_factory.h>
+#include <keymaster/soft_keymaster_context.h>
+#include <keymaster/soft_keymaster_device.h>
+#include <keymaster/softkeymaster.h>
+
+#include "android_keymaster_test_utils.h"
+#include "attestation_record.h"
+#include "keymaster0_engine.h"
+#include "openssl_utils.h"
+
+using std::ifstream;
+using std::istreambuf_iterator;
+using std::ofstream;
+using std::string;
+using std::unique_ptr;
+using std::vector;
+
+extern "C" {
+int __android_log_print(int prio, const char* tag, const char* fmt);
+int __android_log_print(int prio, const char* tag, const char* fmt) {
+ (void)prio, (void)tag, (void)fmt;
+ return 0;
+}
+} // extern "C"
+
+namespace keymaster {
+namespace test {
+
+StdoutLogger logger;
+
+template <typename T> vector<T> make_vector(const T* array, size_t len) {
+ return vector<T>(array, array + len);
+}
+
+/**
+ * KeymasterEnforcement class for use in testing. It's permissive in the sense that it doesn't
+ * check cryptoperiods, but restrictive in the sense that the clock never advances (so rate-limited
+ * keys will only work once).
+ */
+class TestKeymasterEnforcement : public KeymasterEnforcement {
+ public:
+ TestKeymasterEnforcement() : KeymasterEnforcement(3, 3) {}
+
+ virtual bool activation_date_valid(uint64_t /* activation_date */) const { return true; }
+ virtual bool expiration_date_passed(uint64_t /* expiration_date */) const { return false; }
+ virtual bool auth_token_timed_out(const hw_auth_token_t& /* token */,
+ uint32_t /* timeout */) const {
+ return false;
+ }
+ virtual uint32_t get_current_time() const { return 0; }
+ virtual bool ValidateTokenSignature(const hw_auth_token_t& /* token */) const { return true; }
+};
+
+/**
+ * Variant of SoftKeymasterContext that provides a TestKeymasterEnforcement.
+ */
+class TestKeymasterContext : public SoftKeymasterContext {
+ public:
+ TestKeymasterContext() {}
+ explicit TestKeymasterContext(const string& root_of_trust) : SoftKeymasterContext(root_of_trust) {}
+
+ KeymasterEnforcement* enforcement_policy() override { return &test_policy_; }
+
+ private:
+ TestKeymasterEnforcement test_policy_;
+};
+
+/**
+ * Test instance creator that builds a pure software keymaster1 implementations.
+ */
+class SoftKeymasterTestInstanceCreator : public Keymaster2TestInstanceCreator {
+ public:
+ keymaster2_device_t* CreateDevice() const override {
+ std::cerr << "Creating software-only device" << std::endl;
+ SoftKeymasterDevice* device = new SoftKeymasterDevice(new TestKeymasterContext);
+ return device->keymaster2_device();
+ }
+
+ bool algorithm_in_km0_hardware(keymaster_algorithm_t) const override { return false; }
+ int keymaster0_calls() const override { return 0; }
+};
+
+/**
+ * Test instance creator that builds keymaster1 instances which wrap a faked hardware keymaster0
+ * instance, with or without EC support.
+ */
+class Keymaster0AdapterTestInstanceCreator : public Keymaster2TestInstanceCreator {
+ public:
+ explicit Keymaster0AdapterTestInstanceCreator(bool support_ec) : support_ec_(support_ec) {}
+
+ keymaster2_device_t* CreateDevice() const {
+ std::cerr << "Creating keymaster0-backed device (with ec: " << std::boolalpha << support_ec_
+ << ")." << std::endl;
+ hw_device_t* softkeymaster_device;
+ EXPECT_EQ(0, openssl_open(&softkeymaster_module.common, KEYSTORE_KEYMASTER,
+ &softkeymaster_device));
+ // Make the software device pretend to be hardware
+ keymaster0_device_t* keymaster0_device =
+ reinterpret_cast<keymaster0_device_t*>(softkeymaster_device);
+ keymaster0_device->flags &= ~KEYMASTER_SOFTWARE_ONLY;
+
+ if (!support_ec_) {
+ // Make the software device pretend not to support EC
+ keymaster0_device->flags &= ~KEYMASTER_SUPPORTS_EC;
+ }
+
+ counting_keymaster0_device_ = new Keymaster0CountingWrapper(keymaster0_device);
+
+ SoftKeymasterDevice* keymaster = new SoftKeymasterDevice(new TestKeymasterContext);
+ keymaster->SetHardwareDevice(counting_keymaster0_device_);
+ return keymaster->keymaster2_device();
+ }
+
+ bool algorithm_in_km0_hardware(keymaster_algorithm_t algorithm) const override {
+ switch (algorithm) {
+ case KM_ALGORITHM_RSA:
+ return true;
+ case KM_ALGORITHM_EC:
+ return support_ec_;
+ default:
+ return false;
+ }
+ }
+ int keymaster0_calls() const override { return counting_keymaster0_device_->count(); }
+
+ private:
+ mutable Keymaster0CountingWrapper* counting_keymaster0_device_;
+ bool support_ec_;
+};
+
+/**
+ * Test instance creator that builds a SoftKeymasterDevice which wraps a fake hardware keymaster1
+ * instance, with minimal digest support.
+ */
+class Sha256OnlyKeymaster1TestInstanceCreator : public Keymaster2TestInstanceCreator {
+ keymaster2_device_t* CreateDevice() const {
+ 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());
+
+ // device doesn't leak; it's cleaned up by device->keymaster_device()->common.close().
+ SoftKeymasterDevice* device = new SoftKeymasterDevice(new TestKeymasterContext);
+ device->SetHardwareDevice(fake_device);
+
+ 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; }
+};
+
+static auto test_params = testing::Values(
+ InstanceCreatorPtr(new SoftKeymasterTestInstanceCreator),
+ InstanceCreatorPtr(new Keymaster0AdapterTestInstanceCreator(true /* support_ec */)),
+ InstanceCreatorPtr(new Keymaster0AdapterTestInstanceCreator(false /* support_ec */)),
+ InstanceCreatorPtr(new Sha256OnlyKeymaster1TestInstanceCreator));
+
+class NewKeyGeneration : public Keymaster2Test {
+ protected:
+ void CheckBaseParams() {
+ AuthorizationSet auths = sw_enforced();
+ EXPECT_GT(auths.SerializedSize(), 12U);
+
+ EXPECT_TRUE(contains(auths, TAG_PURPOSE, KM_PURPOSE_SIGN));
+ EXPECT_TRUE(contains(auths, TAG_PURPOSE, KM_PURPOSE_VERIFY));
+ EXPECT_TRUE(contains(auths, TAG_USER_ID, 7));
+ EXPECT_TRUE(contains(auths, TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD));
+ EXPECT_TRUE(contains(auths, TAG_AUTH_TIMEOUT, 300));
+
+ // Verify that App ID, App data and ROT are NOT included.
+ EXPECT_FALSE(contains(auths, TAG_ROOT_OF_TRUST));
+ EXPECT_FALSE(contains(auths, TAG_APPLICATION_ID));
+ EXPECT_FALSE(contains(auths, TAG_APPLICATION_DATA));
+
+ // Just for giggles, check that some unexpected tags/values are NOT present.
+ EXPECT_FALSE(contains(auths, TAG_PURPOSE, KM_PURPOSE_ENCRYPT));
+ EXPECT_FALSE(contains(auths, TAG_PURPOSE, KM_PURPOSE_DECRYPT));
+ EXPECT_FALSE(contains(auths, TAG_AUTH_TIMEOUT, 301));
+
+ // Now check that unspecified, defaulted tags are correct.
+ EXPECT_TRUE(contains(auths, KM_TAG_CREATION_DATETIME));
+ }
+};
+INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, NewKeyGeneration, test_params);
+
+TEST_P(NewKeyGeneration, Rsa) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(256, 3)
+ .Digest(KM_DIGEST_NONE)
+ .Padding(KM_PAD_NONE)));
+ CheckBaseParams();
+
+ // 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_TRUE(contains(crypto_params, TAG_ALGORITHM, KM_ALGORITHM_RSA));
+ EXPECT_FALSE(contains(non_crypto_params, TAG_ALGORITHM, KM_ALGORITHM_RSA));
+ EXPECT_TRUE(contains(crypto_params, TAG_KEY_SIZE, 256));
+ EXPECT_FALSE(contains(non_crypto_params, TAG_KEY_SIZE, 256));
+ EXPECT_TRUE(contains(crypto_params, TAG_RSA_PUBLIC_EXPONENT, 3));
+ 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) {
+ ASSERT_EQ(KM_ERROR_UNSUPPORTED_KEY_SIZE,
+ GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+ .Authorization(TAG_RSA_PUBLIC_EXPONENT, 3)
+ .SigningKey()));
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(NewKeyGeneration, Ecdsa) {
+ ASSERT_EQ(KM_ERROR_OK,
+ GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest(KM_DIGEST_NONE)));
+ CheckBaseParams();
+
+ // 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_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) {
+ ASSERT_EQ(KM_ERROR_UNSUPPORTED_KEY_SIZE,
+ GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_ALGORITHM, KM_ALGORITHM_EC)
+ .SigningKey()
+ .Digest(KM_DIGEST_NONE)));
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(NewKeyGeneration, EcdsaInvalidSize) {
+ if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
+ ASSERT_EQ(
+ KM_ERROR_UNKNOWN_ERROR,
+ GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(190).Digest(KM_DIGEST_NONE)));
+ else
+ ASSERT_EQ(
+ KM_ERROR_UNSUPPORTED_KEY_SIZE,
+ GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(190).Digest(KM_DIGEST_NONE)));
+
+ if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
+ EXPECT_EQ(1, GetParam()->keymaster0_calls());
+}
+
+TEST_P(NewKeyGeneration, EcdsaAllValidSizes) {
+ size_t valid_sizes[] = {224, 256, 384, 521};
+ for (size_t size : valid_sizes) {
+ EXPECT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(size).Digest(
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(KM_DIGEST_SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 256)));
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(NewKeyGeneration, HmacMultipleDigests) {
+ ASSERT_EQ(KM_ERROR_UNSUPPORTED_DIGEST,
+ GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .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) {
+ ASSERT_EQ(KM_ERROR_UNSUPPORTED_DIGEST,
+ GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(KM_DIGEST_NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(NewKeyGeneration, HmacSha256TooShortMacLength) {
+ ASSERT_EQ(KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH,
+ GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(KM_DIGEST_SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 48)));
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(NewKeyGeneration, HmacSha256NonIntegralOctetMacLength) {
+ ASSERT_EQ(KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH,
+ GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(KM_DIGEST_SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 130)));
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(NewKeyGeneration, HmacSha256TooLongMacLength) {
+ ASSERT_EQ(KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH,
+ GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(KM_DIGEST_SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 384)));
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+typedef Keymaster2Test GetKeyCharacteristics;
+INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, GetKeyCharacteristics, test_params);
+
+TEST_P(GetKeyCharacteristics, SimpleRsa) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(256, 3)
+ .Digest(KM_DIGEST_NONE)
+ .Padding(KM_PAD_NONE)));
+ AuthorizationSet original(sw_enforced());
+
+ 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;
+INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, SigningOperationsTest, test_params);
+
+TEST_P(SigningOperationsTest, RsaSuccess) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(256, 3)
+ .Digest(KM_DIGEST_NONE)
+ .Padding(KM_PAD_NONE)));
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(512, 3)
+ .Digest(KM_DIGEST_SHA_2_256)
+ .Padding(KM_PAD_RSA_PSS)));
+ // Use large message, which won't work without digesting.
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(512, 3)
+ .Digest(KM_DIGEST_NONE)
+ .Padding(KM_PAD_NONE)));
+ string message = "12345678901234567890123456789012";
+ string signature;
+
+ AuthorizationSet begin_params(client_params());
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(512, 3)
+ .Digest(KM_DIGEST_SHA_2_256)
+ .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN)));
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(512, 3)
+ .Digest(KM_DIGEST_NONE)
+ .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN)));
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(512, 3)
+ .Digest(KM_DIGEST_NONE)
+ .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN)));
+ string message(54, 'a');
+
+ AuthorizationSet begin_params(client_params());
+ 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_OK, BeginOperation(KM_PURPOSE_SIGN, begin_params));
+ string result;
+ size_t input_consumed;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+ string signature;
+ EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(&signature));
+
+ if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+ EXPECT_EQ(2, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, RsaPssSha256TooSmallKey) {
+ // Key must be at least 10 bytes larger than hash, to provide eight bytes of random salt, so
+ // verify that nine bytes larger than hash won't work.
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(256 + 9 * 8, 3)
+ .Digest(KM_DIGEST_SHA_2_256)
+ .Padding(KM_PAD_RSA_PSS)));
+ string message(1024, 'a');
+ string signature;
+
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
+ begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PSS);
+ EXPECT_EQ(KM_ERROR_INCOMPATIBLE_DIGEST, BeginOperation(KM_PURPOSE_SIGN, begin_params));
+}
+
+TEST_P(SigningOperationsTest, RsaNoPaddingHugeData) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(256, 3)
+ .Digest(KM_DIGEST_NONE)
+ .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN)));
+ string message(64 * 1024, 'a');
+ string signature;
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
+ begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN);
+ ASSERT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_SIGN, begin_params));
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(256, 3)
+ .Digest(KM_DIGEST_NONE)
+ .Padding(KM_PAD_NONE)));
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
+ begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+ ASSERT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_SIGN, begin_params));
+ 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) {
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(256, 3)
+ .Digest(KM_DIGEST_SHA_2_256 /* supported digest */)
+ .Padding(KM_PAD_PKCS7));
+ 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) {
+ // PSS requires a digest.
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(256, 3)
+ .Digest(KM_DIGEST_NONE)
+ .Padding(KM_PAD_RSA_PSS));
+ AuthorizationSet begin_params(client_params());
+ 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) {
+ // Padding must be specified
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().RsaKey(256, 3).SigningKey().Digest(
+ KM_DIGEST_NONE)));
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(256, 3)
+ .Digest(KM_DIGEST_NONE)
+ .Padding(KM_PAD_NONE)));
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaEncryptionKey(256, 3)
+ .Digest(KM_DIGEST_NONE)
+ .Padding(KM_PAD_NONE)));
+ AuthorizationSet begin_params(client_params());
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(256, 3)
+ .Digest(KM_DIGEST_NONE)
+ .Padding(KM_PAD_NONE)));
+ string message(256 / 8, static_cast<char>(0xff));
+ string signature;
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+ begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
+ ASSERT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_SIGN, begin_params));
+ string result;
+ size_t input_consumed;
+ ASSERT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK,
+ GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest(KM_DIGEST_NONE)));
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest(
+ KM_DIGEST_SHA_2_256)));
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest(
+ KM_DIGEST_SHA_2_384)));
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK,
+ GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest(KM_DIGEST_NONE)));
+ string message(64 * 1024, 'a');
+ string signature;
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_DIGEST, KM_DIGEST_NONE);
+ ASSERT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_SIGN, begin_params));
+ 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) {
+ vector<int> key_sizes = {224, 256, 384, 521};
+ vector<keymaster_digest_t> digests = {
+ KM_DIGEST_SHA1, KM_DIGEST_SHA_2_224, KM_DIGEST_SHA_2_256,
+ KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512,
+ };
+
+ for (int key_size : key_sizes) {
+ for (keymaster_digest_t digest : digests) {
+ ASSERT_EQ(
+ KM_ERROR_OK,
+ GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(key_size).Digest(digest)));
+
+ string message(1024, 'a');
+ string signature;
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK,
+ GenerateKey(AuthorizationSetBuilder().AesEncryptionKey(128).Authorization(
+ 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) {
+ if (GetParam()->minimal_digest_set())
+ // Can't emulate other digests for HMAC.
+ return;
+
+ GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(KM_DIGEST_SHA1)
+ .Authorization(TAG_MIN_MAC_LENGTH, 160));
+ string message = "12345678901234567890123456789012";
+ string signature;
+ MacMessage(message, &signature, 160);
+ ASSERT_EQ(20U, signature.size());
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, HmacSha224Success) {
+ if (GetParam()->minimal_digest_set())
+ // Can't emulate other digests for HMAC.
+ return;
+
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(KM_DIGEST_SHA_2_224)
+ .Authorization(TAG_MIN_MAC_LENGTH, 160)));
+ string message = "12345678901234567890123456789012";
+ string signature;
+ MacMessage(message, &signature, 224);
+ ASSERT_EQ(28U, signature.size());
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, HmacSha256Success) {
+ if (GetParam()->minimal_digest_set())
+ // Can't emulate other digests for HMAC.
+ return;
+
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(KM_DIGEST_SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 256)));
+ string message = "12345678901234567890123456789012";
+ string signature;
+ MacMessage(message, &signature, 256);
+ ASSERT_EQ(32U, signature.size());
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, HmacSha384Success) {
+ if (GetParam()->minimal_digest_set())
+ // Can't emulate other digests for HMAC.
+ return;
+
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(KM_DIGEST_SHA_2_384)
+ .Authorization(TAG_MIN_MAC_LENGTH, 384)));
+
+ string message = "12345678901234567890123456789012";
+ string signature;
+ MacMessage(message, &signature, 384);
+ ASSERT_EQ(48U, signature.size());
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, HmacSha512Success) {
+ if (GetParam()->minimal_digest_set())
+ // Can't emulate other digests for HMAC.
+ return;
+
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(KM_DIGEST_SHA_2_512)
+ .Authorization(TAG_MIN_MAC_LENGTH, 384)));
+ string message = "12345678901234567890123456789012";
+ string signature;
+ MacMessage(message, &signature, 512);
+ ASSERT_EQ(64U, signature.size());
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, HmacLengthInKey) {
+ // TODO(swillden): unified API should generate an error on key generation.
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(KM_DIGEST_SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+ string message = "12345678901234567890123456789012";
+ string signature;
+ MacMessage(message, &signature, 160);
+ ASSERT_EQ(20U, signature.size());
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(SigningOperationsTest, HmacRfc4231TestCase1) {
+ uint8_t key_data[] = {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ };
+ string message = "Hi There";
+ uint8_t sha_224_expected[] = {
+ 0x89, 0x6f, 0xb1, 0x12, 0x8a, 0xbb, 0xdf, 0x19, 0x68, 0x32, 0x10, 0x7c, 0xd4, 0x9d,
+ 0xf3, 0x3f, 0x47, 0xb4, 0xb1, 0x16, 0x99, 0x12, 0xba, 0x4f, 0x53, 0x68, 0x4b, 0x22,
+ };
+ uint8_t sha_256_expected[] = {
+ 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf,
+ 0xce, 0xaf, 0x0b, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83,
+ 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7,
+ };
+ uint8_t sha_384_expected[] = {
+ 0xaf, 0xd0, 0x39, 0x44, 0xd8, 0x48, 0x95, 0x62, 0x6b, 0x08, 0x25, 0xf4,
+ 0xab, 0x46, 0x90, 0x7f, 0x15, 0xf9, 0xda, 0xdb, 0xe4, 0x10, 0x1e, 0xc6,
+ 0x82, 0xaa, 0x03, 0x4c, 0x7c, 0xeb, 0xc5, 0x9c, 0xfa, 0xea, 0x9e, 0xa9,
+ 0x07, 0x6e, 0xde, 0x7f, 0x4a, 0xf1, 0x52, 0xe8, 0xb2, 0xfa, 0x9c, 0xb6,
+ };
+ uint8_t sha_512_expected[] = {
+ 0x87, 0xaa, 0x7c, 0xde, 0xa5, 0xef, 0x61, 0x9d, 0x4f, 0xf0, 0xb4, 0x24, 0x1a,
+ 0x1d, 0x6c, 0xb0, 0x23, 0x79, 0xf4, 0xe2, 0xce, 0x4e, 0xc2, 0x78, 0x7a, 0xd0,
+ 0xb3, 0x05, 0x45, 0xe1, 0x7c, 0xde, 0xda, 0xa8, 0x33, 0xb7, 0xd6, 0xb8, 0xa7,
+ 0x02, 0x03, 0x8b, 0x27, 0x4e, 0xae, 0xa3, 0xf4, 0xe4, 0xbe, 0x9d, 0x91, 0x4e,
+ 0xeb, 0x61, 0xf1, 0x70, 0x2e, 0x69, 0x6c, 0x20, 0x3a, 0x12, 0x68, 0x54,
+ };
+
+ string key = make_string(key_data);
+
+ CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
+ if (!GetParam()->minimal_digest_set()) {
+ CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_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, HmacRfc4231TestCase2) {
+ string key = "Jefe";
+ string message = "what do ya want for nothing?";
+ uint8_t sha_224_expected[] = {
+ 0xa3, 0x0e, 0x01, 0x09, 0x8b, 0xc6, 0xdb, 0xbf, 0x45, 0x69, 0x0f, 0x3a, 0x7e, 0x9e,
+ 0x6d, 0x0f, 0x8b, 0xbe, 0xa2, 0xa3, 0x9e, 0x61, 0x48, 0x00, 0x8f, 0xd0, 0x5e, 0x44,
+ };
+ uint8_t sha_256_expected[] = {
+ 0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, 0x6a, 0x04, 0x24,
+ 0x26, 0x08, 0x95, 0x75, 0xc7, 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27,
+ 0x39, 0x83, 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43,
+ };
+ uint8_t sha_384_expected[] = {
+ 0xaf, 0x45, 0xd2, 0xe3, 0x76, 0x48, 0x40, 0x31, 0x61, 0x7f, 0x78, 0xd2,
+ 0xb5, 0x8a, 0x6b, 0x1b, 0x9c, 0x7e, 0xf4, 0x64, 0xf5, 0xa0, 0x1b, 0x47,
+ 0xe4, 0x2e, 0xc3, 0x73, 0x63, 0x22, 0x44, 0x5e, 0x8e, 0x22, 0x40, 0xca,
+ 0x5e, 0x69, 0xe2, 0xc7, 0x8b, 0x32, 0x39, 0xec, 0xfa, 0xb2, 0x16, 0x49,
+ };
+ uint8_t sha_512_expected[] = {
+ 0x16, 0x4b, 0x7a, 0x7b, 0xfc, 0xf8, 0x19, 0xe2, 0xe3, 0x95, 0xfb, 0xe7, 0x3b,
+ 0x56, 0xe0, 0xa3, 0x87, 0xbd, 0x64, 0x22, 0x2e, 0x83, 0x1f, 0xd6, 0x10, 0x27,
+ 0x0c, 0xd7, 0xea, 0x25, 0x05, 0x54, 0x97, 0x58, 0xbf, 0x75, 0xc0, 0x5a, 0x99,
+ 0x4a, 0x6d, 0x03, 0x4f, 0x65, 0xf8, 0xf0, 0xe6, 0xfd, 0xca, 0xea, 0xb1, 0xa3,
+ 0x4d, 0x4a, 0x6b, 0x4b, 0x63, 0x6e, 0x07, 0x0a, 0x38, 0xbc, 0xe7, 0x37,
+ };
+
+ CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
+ if (!GetParam()->minimal_digest_set()) {
+ CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_expected));
+ 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, HmacRfc4231TestCase3) {
+ string key(20, 0xaa);
+ string message(50, 0xdd);
+ uint8_t sha_224_expected[] = {
+ 0x7f, 0xb3, 0xcb, 0x35, 0x88, 0xc6, 0xc1, 0xf6, 0xff, 0xa9, 0x69, 0x4d, 0x7d, 0x6a,
+ 0xd2, 0x64, 0x93, 0x65, 0xb0, 0xc1, 0xf6, 0x5d, 0x69, 0xd1, 0xec, 0x83, 0x33, 0xea,
+ };
+ uint8_t sha_256_expected[] = {
+ 0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8,
+ 0xeb, 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8,
+ 0xc1, 0x22, 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe,
+ };
+ uint8_t sha_384_expected[] = {
+ 0x88, 0x06, 0x26, 0x08, 0xd3, 0xe6, 0xad, 0x8a, 0x0a, 0xa2, 0xac, 0xe0,
+ 0x14, 0xc8, 0xa8, 0x6f, 0x0a, 0xa6, 0x35, 0xd9, 0x47, 0xac, 0x9f, 0xeb,
+ 0xe8, 0x3e, 0xf4, 0xe5, 0x59, 0x66, 0x14, 0x4b, 0x2a, 0x5a, 0xb3, 0x9d,
+ 0xc1, 0x38, 0x14, 0xb9, 0x4e, 0x3a, 0xb6, 0xe1, 0x01, 0xa3, 0x4f, 0x27,
+ };
+ uint8_t sha_512_expected[] = {
+ 0xfa, 0x73, 0xb0, 0x08, 0x9d, 0x56, 0xa2, 0x84, 0xef, 0xb0, 0xf0, 0x75, 0x6c,
+ 0x89, 0x0b, 0xe9, 0xb1, 0xb5, 0xdb, 0xdd, 0x8e, 0xe8, 0x1a, 0x36, 0x55, 0xf8,
+ 0x3e, 0x33, 0xb2, 0x27, 0x9d, 0x39, 0xbf, 0x3e, 0x84, 0x82, 0x79, 0xa7, 0x22,
+ 0xc8, 0x06, 0xb4, 0x85, 0xa4, 0x7e, 0x67, 0xc8, 0x07, 0xb9, 0x46, 0xa3, 0x37,
+ 0xbe, 0xe8, 0x94, 0x26, 0x74, 0x27, 0x88, 0x59, 0xe1, 0x32, 0x92, 0xfb,
+ };
+
+ CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
+ if (!GetParam()->minimal_digest_set()) {
+ CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_expected));
+ 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) {
+ uint8_t key_data[25] = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
+ 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
+ };
+ string key = make_string(key_data);
+ string message(50, 0xcd);
+ uint8_t sha_224_expected[] = {
+ 0x6c, 0x11, 0x50, 0x68, 0x74, 0x01, 0x3c, 0xac, 0x6a, 0x2a, 0xbc, 0x1b, 0xb3, 0x82,
+ 0x62, 0x7c, 0xec, 0x6a, 0x90, 0xd8, 0x6e, 0xfc, 0x01, 0x2d, 0xe7, 0xaf, 0xec, 0x5a,
+ };
+ uint8_t sha_256_expected[] = {
+ 0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e, 0xa4, 0xcc, 0x81,
+ 0x98, 0x99, 0xf2, 0x08, 0x3a, 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78,
+ 0xf8, 0x07, 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b,
+ };
+ uint8_t sha_384_expected[] = {
+ 0x3e, 0x8a, 0x69, 0xb7, 0x78, 0x3c, 0x25, 0x85, 0x19, 0x33, 0xab, 0x62,
+ 0x90, 0xaf, 0x6c, 0xa7, 0x7a, 0x99, 0x81, 0x48, 0x08, 0x50, 0x00, 0x9c,
+ 0xc5, 0x57, 0x7c, 0x6e, 0x1f, 0x57, 0x3b, 0x4e, 0x68, 0x01, 0xdd, 0x23,
+ 0xc4, 0xa7, 0xd6, 0x79, 0xcc, 0xf8, 0xa3, 0x86, 0xc6, 0x74, 0xcf, 0xfb,
+ };
+ uint8_t sha_512_expected[] = {
+ 0xb0, 0xba, 0x46, 0x56, 0x37, 0x45, 0x8c, 0x69, 0x90, 0xe5, 0xa8, 0xc5, 0xf6,
+ 0x1d, 0x4a, 0xf7, 0xe5, 0x76, 0xd9, 0x7f, 0xf9, 0x4b, 0x87, 0x2d, 0xe7, 0x6f,
+ 0x80, 0x50, 0x36, 0x1e, 0xe3, 0xdb, 0xa9, 0x1c, 0xa5, 0xc1, 0x1a, 0xa2, 0x5e,
+ 0xb4, 0xd6, 0x79, 0x27, 0x5c, 0xc5, 0x78, 0x80, 0x63, 0xa5, 0xf1, 0x97, 0x41,
+ 0x12, 0x0c, 0x4f, 0x2d, 0xe2, 0xad, 0xeb, 0xeb, 0x10, 0xa2, 0x98, 0xdd,
+ };
+
+ CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
+ if (!GetParam()->minimal_digest_set()) {
+ CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_expected));
+ 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) {
+ string key(20, 0x0c);
+ string message = "Test With Truncation";
+
+ uint8_t sha_224_expected[] = {
+ 0x0e, 0x2a, 0xea, 0x68, 0xa9, 0x0c, 0x8d, 0x37,
+ 0xc9, 0x88, 0xbc, 0xdb, 0x9f, 0xca, 0x6f, 0xa8,
+ };
+ uint8_t sha_256_expected[] = {
+ 0xa3, 0xb6, 0x16, 0x74, 0x73, 0x10, 0x0e, 0xe0,
+ 0x6e, 0x0c, 0x79, 0x6c, 0x29, 0x55, 0x55, 0x2b,
+ };
+ uint8_t sha_384_expected[] = {
+ 0x3a, 0xbf, 0x34, 0xc3, 0x50, 0x3b, 0x2a, 0x23,
+ 0xa4, 0x6e, 0xfc, 0x61, 0x9b, 0xae, 0xf8, 0x97,
+ };
+ uint8_t sha_512_expected[] = {
+ 0x41, 0x5f, 0xad, 0x62, 0x71, 0x58, 0x0a, 0x53,
+ 0x1d, 0x41, 0x79, 0xbc, 0x89, 0x1d, 0x87, 0xa6,
+ };
+
+ CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
+ if (!GetParam()->minimal_digest_set()) {
+ CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_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) {
+ string key(131, 0xaa);
+ string message = "Test Using Larger Than Block-Size Key - Hash Key First";
+
+ uint8_t sha_224_expected[] = {
+ 0x95, 0xe9, 0xa0, 0xdb, 0x96, 0x20, 0x95, 0xad, 0xae, 0xbe, 0x9b, 0x2d, 0x6f, 0x0d,
+ 0xbc, 0xe2, 0xd4, 0x99, 0xf1, 0x12, 0xf2, 0xd2, 0xb7, 0x27, 0x3f, 0xa6, 0x87, 0x0e,
+ };
+ uint8_t sha_256_expected[] = {
+ 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26,
+ 0xaa, 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28,
+ 0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54,
+ };
+ uint8_t sha_384_expected[] = {
+ 0x4e, 0xce, 0x08, 0x44, 0x85, 0x81, 0x3e, 0x90, 0x88, 0xd2, 0xc6, 0x3a,
+ 0x04, 0x1b, 0xc5, 0xb4, 0x4f, 0x9e, 0xf1, 0x01, 0x2a, 0x2b, 0x58, 0x8f,
+ 0x3c, 0xd1, 0x1f, 0x05, 0x03, 0x3a, 0xc4, 0xc6, 0x0c, 0x2e, 0xf6, 0xab,
+ 0x40, 0x30, 0xfe, 0x82, 0x96, 0x24, 0x8d, 0xf1, 0x63, 0xf4, 0x49, 0x52,
+ };
+ uint8_t sha_512_expected[] = {
+ 0x80, 0xb2, 0x42, 0x63, 0xc7, 0xc1, 0xa3, 0xeb, 0xb7, 0x14, 0x93, 0xc1, 0xdd,
+ 0x7b, 0xe8, 0xb4, 0x9b, 0x46, 0xd1, 0xf4, 0x1b, 0x4a, 0xee, 0xc1, 0x12, 0x1b,
+ 0x01, 0x37, 0x83, 0xf8, 0xf3, 0x52, 0x6b, 0x56, 0xd0, 0x37, 0xe0, 0x5f, 0x25,
+ 0x98, 0xbd, 0x0f, 0xd2, 0x21, 0x5d, 0x6a, 0x1e, 0x52, 0x95, 0xe6, 0x4f, 0x73,
+ 0xf6, 0x3f, 0x0a, 0xec, 0x8b, 0x91, 0x5a, 0x98, 0x5d, 0x78, 0x65, 0x98,
+ };
+
+ CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
+ if (!GetParam()->minimal_digest_set()) {
+ CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_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) {
+ string key(131, 0xaa);
+ string message = "This is a test using a larger than block-size key and a larger than "
+ "block-size data. The key needs to be hashed before being used by the HMAC "
+ "algorithm.";
+
+ uint8_t sha_224_expected[] = {
+ 0x3a, 0x85, 0x41, 0x66, 0xac, 0x5d, 0x9f, 0x02, 0x3f, 0x54, 0xd5, 0x17, 0xd0, 0xb3,
+ 0x9d, 0xbd, 0x94, 0x67, 0x70, 0xdb, 0x9c, 0x2b, 0x95, 0xc9, 0xf6, 0xf5, 0x65, 0xd1,
+ };
+ uint8_t sha_256_expected[] = {
+ 0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f,
+ 0xbc, 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07,
+ 0x13, 0x93, 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2,
+ };
+ uint8_t sha_384_expected[] = {
+ 0x66, 0x17, 0x17, 0x8e, 0x94, 0x1f, 0x02, 0x0d, 0x35, 0x1e, 0x2f, 0x25,
+ 0x4e, 0x8f, 0xd3, 0x2c, 0x60, 0x24, 0x20, 0xfe, 0xb0, 0xb8, 0xfb, 0x9a,
+ 0xdc, 0xce, 0xbb, 0x82, 0x46, 0x1e, 0x99, 0xc5, 0xa6, 0x78, 0xcc, 0x31,
+ 0xe7, 0x99, 0x17, 0x6d, 0x38, 0x60, 0xe6, 0x11, 0x0c, 0x46, 0x52, 0x3e,
+ };
+ uint8_t sha_512_expected[] = {
+ 0xe3, 0x7b, 0x6a, 0x77, 0x5d, 0xc8, 0x7d, 0xba, 0xa4, 0xdf, 0xa9, 0xf9, 0x6e,
+ 0x5e, 0x3f, 0xfd, 0xde, 0xbd, 0x71, 0xf8, 0x86, 0x72, 0x89, 0x86, 0x5d, 0xf5,
+ 0xa3, 0x2d, 0x20, 0xcd, 0xc9, 0x44, 0xb6, 0x02, 0x2c, 0xac, 0x3c, 0x49, 0x82,
+ 0xb1, 0x0d, 0x5e, 0xeb, 0x55, 0xc3, 0xe4, 0xde, 0x15, 0x13, 0x46, 0x76, 0xfb,
+ 0x6d, 0xe0, 0x44, 0x60, 0x65, 0xc9, 0x74, 0x40, 0xfa, 0x8c, 0x6a, 0x58,
+ };
+
+ CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_256, make_string(sha_256_expected));
+ if (!GetParam()->minimal_digest_set()) {
+ CheckHmacTestVector(key, message, KM_DIGEST_SHA_2_224, make_string(sha_224_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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(KM_DIGEST_SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 256)));
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_MAC_LENGTH, 264);
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(KM_DIGEST_SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_MAC_LENGTH, 120);
+ 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.
+
+typedef Keymaster2Test VerificationOperationsTest;
+INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, VerificationOperationsTest, test_params);
+
+TEST_P(VerificationOperationsTest, RsaSuccess) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(256, 3)
+ .Digest(KM_DIGEST_NONE)
+ .Padding(KM_PAD_NONE)));
+ string message = "12345678901234567890123456789012";
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(512, 3)
+ .Digest(KM_DIGEST_SHA_2_256)
+ .Padding(KM_PAD_RSA_PSS)));
+ // Use large message, which won't work without digesting.
+ string message(1024, 'a');
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(512, 3)
+ .Digest(KM_DIGEST_SHA_2_224)
+ .Padding(KM_PAD_RSA_PSS)));
+ // Use large message, which won't work without digesting.
+ string message(1024, 'a');
+ string signature;
+ 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));
+
+ const uint8_t* p = reinterpret_cast<const uint8_t*>(pubkey.data());
+ unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(
+ d2i_PUBKEY(nullptr /* alloc new */, &p, pubkey.size()));
+ ASSERT_TRUE(pkey.get());
+
+ EVP_MD_CTX digest_ctx;
+ EVP_MD_CTX_init(&digest_ctx);
+ EVP_PKEY_CTX* pkey_ctx;
+ EXPECT_EQ(1, EVP_DigestVerifyInit(&digest_ctx, &pkey_ctx, EVP_sha224(), nullptr /* engine */,
+ pkey.get()));
+ EXPECT_EQ(1, EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING));
+ EXPECT_EQ(1, EVP_DigestVerifyUpdate(&digest_ctx, message.data(), message.size()));
+ EXPECT_EQ(1,
+ EVP_DigestVerifyFinal(&digest_ctx, reinterpret_cast<const uint8_t*>(signature.data()),
+ signature.size()));
+ EVP_MD_CTX_cleanup(&digest_ctx);
+}
+
+TEST_P(VerificationOperationsTest, RsaPssSha256CorruptSignature) {
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(512, 3)
+ .Digest(KM_DIGEST_SHA_2_256)
+ .Padding(KM_PAD_RSA_PSS));
+ string message(1024, 'a');
+ string signature;
+ SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PSS);
+ ++signature[signature.size() / 2];
+
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
+ begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PSS);
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params));
+
+ string result;
+ size_t input_consumed;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+ EXPECT_EQ(message.size(), input_consumed);
+ EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result));
+
+ if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+ EXPECT_EQ(4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, RsaPssSha256CorruptInput) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(512, 3)
+ .Digest(KM_DIGEST_SHA_2_256)
+ .Padding(KM_PAD_RSA_PSS)));
+ // Use large message, which won't work without digesting.
+ string message(1024, 'a');
+ string signature;
+ SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PSS);
+ ++message[message.size() / 2];
+
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
+ begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PSS);
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params));
+
+ string result;
+ size_t input_consumed;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+ EXPECT_EQ(message.size(), input_consumed);
+ EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result));
+
+ if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+ EXPECT_EQ(4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, RsaPkcs1Sha256Success) {
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(512, 3)
+ .Digest(KM_DIGEST_SHA_2_256)
+ .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN));
+ string message(1024, 'a');
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(512, 3)
+ .Digest(KM_DIGEST_SHA_2_224)
+ .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN)));
+ // Use large message, which won't work without digesting.
+ string message(1024, 'a');
+ string signature;
+ 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));
+
+ const uint8_t* p = reinterpret_cast<const uint8_t*>(pubkey.data());
+ unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(
+ d2i_PUBKEY(nullptr /* alloc new */, &p, pubkey.size()));
+ ASSERT_TRUE(pkey.get());
+
+ EVP_MD_CTX digest_ctx;
+ EVP_MD_CTX_init(&digest_ctx);
+ EVP_PKEY_CTX* pkey_ctx;
+ EXPECT_EQ(1, EVP_DigestVerifyInit(&digest_ctx, &pkey_ctx, EVP_sha224(), nullptr /* engine */,
+ pkey.get()));
+ EXPECT_EQ(1, EVP_DigestVerifyUpdate(&digest_ctx, message.data(), message.size()));
+ EXPECT_EQ(1,
+ EVP_DigestVerifyFinal(&digest_ctx, reinterpret_cast<const uint8_t*>(signature.data()),
+ signature.size()));
+ EVP_MD_CTX_cleanup(&digest_ctx);
+}
+
+TEST_P(VerificationOperationsTest, RsaPkcs1Sha256CorruptSignature) {
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(512, 3)
+ .Digest(KM_DIGEST_SHA_2_256)
+ .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN));
+ string message(1024, 'a');
+ string signature;
+ SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PKCS1_1_5_SIGN);
+ ++signature[signature.size() / 2];
+
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
+ begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN);
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params));
+
+ string result;
+ size_t input_consumed;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+ EXPECT_EQ(message.size(), input_consumed);
+ EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result));
+
+ if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+ EXPECT_EQ(4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, RsaPkcs1Sha256CorruptInput) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(512, 3)
+ .Digest(KM_DIGEST_SHA_2_256)
+ .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN)));
+ // Use large message, which won't work without digesting.
+ string message(1024, 'a');
+ string signature;
+ SignMessage(message, &signature, KM_DIGEST_SHA_2_256, KM_PAD_RSA_PKCS1_1_5_SIGN);
+ ++message[message.size() / 2];
+
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
+ begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN);
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params));
+
+ string result;
+ size_t input_consumed;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+ EXPECT_EQ(message.size(), input_consumed);
+ EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result));
+
+ if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+ EXPECT_EQ(4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, RsaAllDigestAndPadCombinations) {
+ vector<keymaster_digest_t> digests = {
+ KM_DIGEST_NONE, KM_DIGEST_MD5, KM_DIGEST_SHA1, KM_DIGEST_SHA_2_224,
+ KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512,
+ };
+
+ vector<keymaster_padding_t> padding_modes{
+ KM_PAD_NONE, KM_PAD_RSA_PKCS1_1_5_SIGN, KM_PAD_RSA_PSS,
+ };
+
+ int trial_count = 0;
+ for (keymaster_padding_t padding_mode : padding_modes) {
+ for (keymaster_digest_t digest : digests) {
+ if (digest != KM_DIGEST_NONE && padding_mode == KM_PAD_NONE)
+ // Digesting requires padding
+ continue;
+
+ // Compute key & message size that will work.
+ size_t key_bits = 0;
+ size_t message_len = 1000;
+
+ if (digest == KM_DIGEST_NONE) {
+ key_bits = 256;
+ switch (padding_mode) {
+ case KM_PAD_NONE:
+ // Match key size.
+ message_len = key_bits / 8;
+ break;
+ case KM_PAD_RSA_PKCS1_1_5_SIGN:
+ message_len = key_bits / 8 - 11;
+ break;
+ case KM_PAD_RSA_PSS:
+ // PSS requires a digest.
+ continue;
+ default:
+ FAIL() << "Missing padding";
+ break;
+ }
+ } else {
+ size_t digest_bits;
+ switch (digest) {
+ case KM_DIGEST_MD5:
+ digest_bits = 128;
+ break;
+ case KM_DIGEST_SHA1:
+ digest_bits = 160;
+ break;
+ case KM_DIGEST_SHA_2_224:
+ digest_bits = 224;
+ break;
+ case KM_DIGEST_SHA_2_256:
+ digest_bits = 256;
+ break;
+ case KM_DIGEST_SHA_2_384:
+ digest_bits = 384;
+ break;
+ case KM_DIGEST_SHA_2_512:
+ digest_bits = 512;
+ break;
+ default:
+ FAIL() << "Missing digest";
+ }
+
+ switch (padding_mode) {
+ case KM_PAD_RSA_PKCS1_1_5_SIGN:
+ key_bits = digest_bits + 8 * (11 + 19);
+ break;
+ case KM_PAD_RSA_PSS:
+ key_bits = digest_bits + 22 * 8;
+ break;
+ default:
+ FAIL() << "Missing padding";
+ break;
+ }
+ }
+
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(key_bits, 3)
+ .Digest(digest)
+ .Padding(padding_mode));
+ string message(message_len, 'a');
+ string signature;
+ SignMessage(message, &signature, digest, padding_mode);
+ VerifyMessage(message, signature, digest, padding_mode);
+ ++trial_count;
+ }
+ }
+
+ if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+ EXPECT_EQ(trial_count * 4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, EcdsaSuccess) {
+ ASSERT_EQ(KM_ERROR_OK,
+ GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(KM_DIGEST_NONE)));
+ string message = "12345678901234567890123456789012";
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK,
+ GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(KM_DIGEST_NONE)));
+ string message = "12345678901234567890";
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK,
+ GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(521).Digest(KM_DIGEST_NONE)));
+
+ string message(66, 'a');
+ string signature;
+ SignMessage(message, &signature, KM_DIGEST_NONE);
+ VerifyMessage(message, signature, KM_DIGEST_NONE);
+
+ // 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(256)
+ .Digest(KM_DIGEST_SHA_2_256)
+ .Digest(KM_DIGEST_NONE)));
+ string message = "12345678901234567890123456789012";
+ string signature;
+ 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);
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params));
+
+ string result;
+ size_t input_consumed;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+ EXPECT_EQ(message.size(), input_consumed);
+ EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result));
+}
+
+TEST_P(VerificationOperationsTest, EcdsaSha224Success) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(
+ KM_DIGEST_SHA_2_224)));
+
+ string message = "12345678901234567890123456789012";
+ string signature;
+ 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);
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params));
+
+ string result;
+ size_t input_consumed;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+ EXPECT_EQ(message.size(), input_consumed);
+ EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(signature, &result));
+}
+
+TEST_P(VerificationOperationsTest, EcdsaAllDigestsAndKeySizes) {
+ keymaster_digest_t digests[] = {
+ KM_DIGEST_SHA1, KM_DIGEST_SHA_2_224, KM_DIGEST_SHA_2_256,
+ KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512,
+ };
+ size_t key_sizes[] = {224, 256, 384, 521};
+
+ string message = "1234567890";
+ string signature;
+
+ for (auto key_size : key_sizes) {
+ AuthorizationSetBuilder builder;
+ builder.EcdsaSigningKey(key_size);
+ for (auto digest : digests)
+ builder.Digest(digest);
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(builder));
+
+ for (auto digest : digests) {
+ SignMessage(message, &signature, digest);
+ 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) {
+ if (GetParam()->minimal_digest_set())
+ // Can't emulate missing digests for HMAC.
+ return;
+
+ GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(KM_DIGEST_SHA1)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128));
+ string message = "123456789012345678901234567890123456789012345678";
+ string signature;
+ MacMessage(message, &signature, 160);
+ VerifyMac(message, signature);
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, HmacSha224Success) {
+ if (GetParam()->minimal_digest_set())
+ // Can't emulate missing digests for HMAC.
+ return;
+
+ GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(KM_DIGEST_SHA_2_224)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128));
+ string message = "123456789012345678901234567890123456789012345678";
+ string signature;
+ MacMessage(message, &signature, 224);
+ VerifyMac(message, signature);
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, HmacSha256Success) {
+ GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(KM_DIGEST_SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128));
+ string message = "123456789012345678901234567890123456789012345678";
+ string signature;
+ MacMessage(message, &signature, 256);
+ VerifyMac(message, signature);
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, HmacSha256TooShortMac) {
+ GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(KM_DIGEST_SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128));
+ string message = "123456789012345678901234567890123456789012345678";
+ string signature;
+ MacMessage(message, &signature, 256);
+
+ // Shorten to 128 bits, should still work.
+ signature.resize(128 / 8);
+ VerifyMac(message, signature);
+
+ // Drop one more byte.
+ signature.resize(signature.length() - 1);
+
+ AuthorizationSet begin_params(client_params());
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_VERIFY, begin_params));
+ string result;
+ size_t input_consumed;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+ EXPECT_EQ(KM_ERROR_INVALID_MAC_LENGTH, FinishOperation(signature, &result));
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, HmacSha384Success) {
+ if (GetParam()->minimal_digest_set())
+ // Can't emulate missing digests for HMAC.
+ return;
+
+ GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(KM_DIGEST_SHA_2_384)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128));
+ string message = "123456789012345678901234567890123456789012345678";
+ string signature;
+ MacMessage(message, &signature, 384);
+ VerifyMac(message, signature);
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(VerificationOperationsTest, HmacSha512Success) {
+ if (GetParam()->minimal_digest_set())
+ // Can't emulate missing digests for HMAC.
+ return;
+
+ GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(KM_DIGEST_SHA_2_512)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128));
+ string message = "123456789012345678901234567890123456789012345678";
+ string signature;
+ MacMessage(message, &signature, 512);
+ VerifyMac(message, signature);
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+typedef Keymaster2Test ExportKeyTest;
+INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, ExportKeyTest, test_params);
+
+TEST_P(ExportKeyTest, RsaSuccess) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(256, 3)
+ .Digest(KM_DIGEST_NONE)
+ .Padding(KM_PAD_NONE)));
+ string export_data;
+ ASSERT_EQ(KM_ERROR_OK, ExportKey(KM_KEY_FORMAT_X509, &export_data));
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK,
+ GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(224).Digest(KM_DIGEST_NONE)));
+ string export_data;
+ ASSERT_EQ(KM_ERROR_OK, ExportKey(KM_KEY_FORMAT_X509, &export_data));
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(256, 3)
+ .Digest(KM_DIGEST_NONE)
+ .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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(256, 3)
+ .Digest(KM_DIGEST_NONE)
+ .Padding(KM_PAD_NONE)));
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().AesEncryptionKey(128)));
+ string export_data;
+
+ 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");
+ ASSERT_EQ(633U, pk8_key.size());
+
+ ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder()
+ .RsaSigningKey(1024, 65537)
+ .Digest(KM_DIGEST_NONE)
+ .Padding(KM_PAD_NONE),
+ 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));
+
+ // 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(), 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");
+ ASSERT_EQ(633U, pk8_key.size());
+ ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH,
+ ImportKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048 /* Doesn't match key */, 3)
+ .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");
+ ASSERT_EQ(633U, pk8_key.size());
+ ASSERT_EQ(KM_ERROR_IMPORT_PARAMETER_MISMATCH,
+ ImportKey(AuthorizationSetBuilder()
+ .RsaSigningKey(256, 3 /* Doesnt' match key */)
+ .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");
+ ASSERT_EQ(138U, pk8_key.size());
+
+ ASSERT_EQ(KM_ERROR_OK,
+ ImportKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(KM_DIGEST_NONE),
+ 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));
+
+ // 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(), 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");
+ ASSERT_EQ(138U, pk8_key.size());
+
+ ASSERT_EQ(KM_ERROR_OK,
+ ImportKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(KM_DIGEST_NONE),
+ 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));
+
+ // 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(), 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");
+ 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) {
+ char key_data[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ string key(key_data, sizeof(key_data));
+ ASSERT_EQ(KM_ERROR_OK,
+ ImportKey(AuthorizationSetBuilder().AesEncryptionKey(128).EcbMode().Authorization(
+ TAG_PADDING, KM_PAD_PKCS7),
+ KM_KEY_FORMAT_RAW, key));
+
+ EXPECT_TRUE(contains(sw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED));
+ EXPECT_TRUE(contains(sw_enforced(), KM_TAG_CREATION_DATETIME));
+
+ string message = "Hello World!";
+ 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) {
+ char key_data[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ string key(key_data, sizeof(key_data));
+ ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder()
+ .HmacKey(sizeof(key_data) * 8)
+ .Digest(KM_DIGEST_SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, 256),
+ KM_KEY_FORMAT_RAW, key));
+
+ EXPECT_TRUE(contains(sw_enforced(), TAG_ORIGIN, KM_ORIGIN_IMPORTED));
+ EXPECT_TRUE(contains(sw_enforced(), KM_TAG_CREATION_DATETIME));
+
+ string message = "Hello World!";
+ string signature;
+ MacMessage(message, &signature, 256);
+ VerifyMac(message, signature);
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+typedef Keymaster2Test EncryptionOperationsTest;
+INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, EncryptionOperationsTest, test_params);
+
+TEST_P(EncryptionOperationsTest, RsaNoPaddingSuccess) {
+ ASSERT_EQ(KM_ERROR_OK,
+ GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(256, 3).Padding(KM_PAD_NONE)));
+
+ string message = "12345678901234567890123456789012";
+ string ciphertext1 = EncryptMessage(string(message), KM_PAD_NONE);
+ EXPECT_EQ(256U / 8, ciphertext1.size());
+
+ string ciphertext2 = EncryptMessage(string(message), KM_PAD_NONE);
+ EXPECT_EQ(256U / 8, ciphertext2.size());
+
+ // 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) {
+ ASSERT_EQ(KM_ERROR_OK,
+ GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(256, 3).Padding(KM_PAD_NONE)));
+
+ string message = "1";
+
+ string ciphertext = EncryptMessage(message, KM_PAD_NONE);
+ EXPECT_EQ(256U / 8, ciphertext.size());
+
+ string expected_plaintext = string(256 / 8 - 1, 0) + message;
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK,
+ GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(256, 3).Padding(KM_PAD_NONE)));
+
+ string message = "123456789012345678901234567890123";
+
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK,
+ GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(256, 3).Padding(KM_PAD_NONE)));
+
+ string exported;
+ ASSERT_EQ(KM_ERROR_OK, ExportKey(KM_KEY_FORMAT_X509, &exported));
+
+ const uint8_t* p = reinterpret_cast<const uint8_t*>(exported.data());
+ unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(
+ d2i_PUBKEY(nullptr /* alloc new */, &p, exported.size()));
+ unique_ptr<RSA, RSA_Delete> rsa(EVP_PKEY_get1_RSA(pkey.get()));
+
+ size_t modulus_len = BN_num_bytes(rsa->n);
+ ASSERT_EQ(256U / 8, modulus_len);
+ unique_ptr<uint8_t[]> modulus_buf(new uint8_t[modulus_len]);
+ BN_bn2bin(rsa->n, modulus_buf.get());
+
+ // The modulus is too big to encrypt.
+ string message(reinterpret_cast<const char*>(modulus_buf.get()), modulus_len);
+
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+
+ string result;
+ size_t input_consumed;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+ EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, FinishOperation(&result));
+
+ // One smaller than the modulus is okay.
+ BN_sub(rsa->n, rsa->n, BN_value_one());
+ modulus_len = BN_num_bytes(rsa->n);
+ ASSERT_EQ(256U / 8, modulus_len);
+ BN_bn2bin(rsa->n, modulus_buf.get());
+ 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, UpdateOperation(message, &result, &input_consumed));
+ EXPECT_EQ(KM_ERROR_OK, FinishOperation(&result));
+
+ if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+ EXPECT_EQ(4, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, RsaOaepSuccess) {
+ 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)));
+
+ string message = "Hello";
+ string ciphertext1 = EncryptMessage(string(message), KM_DIGEST_SHA_2_256, KM_PAD_RSA_OAEP);
+ EXPECT_EQ(key_size / 8, ciphertext1.size());
+
+ string ciphertext2 = EncryptMessage(string(message), KM_DIGEST_SHA_2_256, KM_PAD_RSA_OAEP);
+ EXPECT_EQ(key_size / 8, ciphertext2.size());
+
+ // 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, RsaOaepSha224Success) {
+ 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_224)));
+
+ string message = "Hello";
+ string ciphertext1 = EncryptMessage(string(message), 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_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);
+
+ if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+ EXPECT_EQ(3, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, RsaOaepRoundTrip) {
+ 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)));
+ string message = "Hello World!";
+ string ciphertext = EncryptMessage(string(message), 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_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, RsaOaepSha224RoundTrip) {
+ 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_224)));
+ string message = "Hello World!";
+ string ciphertext = EncryptMessage(string(message), KM_DIGEST_SHA_2_224, KM_PAD_RSA_OAEP);
+ EXPECT_EQ(key_size / 8, ciphertext.size());
+
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaEncryptionKey(512, 3)
+ .Padding(KM_PAD_RSA_OAEP)
+ .Digest(KM_DIGEST_NONE)));
+ 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_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, RsaOaepUnauthorizedDigest) {
+ if (GetParam()->minimal_digest_set())
+ // We don't have two supported digests, so we can't try authorizing one and using another.
+ return;
+
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaEncryptionKey(512, 3)
+ .Padding(KM_PAD_RSA_OAEP)
+ .Digest(KM_DIGEST_SHA_2_256)));
+ string message = "Hello World!";
+ // Works because encryption is a public key operation.
+ EncryptMessage(string(message), KM_DIGEST_SHA1, KM_PAD_RSA_OAEP);
+
+ AuthorizationSet begin_params(client_params());
+ 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) {
+ if (GetParam()->minimal_digest_set())
+ // We don't have two supported digests, so we can't try encrypting with one and decrypting
+ // with another.
+ return;
+
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaEncryptionKey(768, 3)
+ .Padding(KM_PAD_RSA_OAEP)
+ .Digest(KM_DIGEST_SHA_2_256)
+ .Digest(KM_DIGEST_SHA_2_384)));
+ string message = "Hello World!";
+ string ciphertext = EncryptMessage(string(message), KM_DIGEST_SHA_2_256, KM_PAD_RSA_OAEP);
+
+ string result;
+ size_t input_consumed;
+ 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_384);
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaEncryptionKey(512, 3)
+ .Padding(KM_PAD_RSA_OAEP)
+ .Digest(KM_DIGEST_SHA1)));
+ string message = "12345678901234567890123";
+ string result;
+ size_t input_consumed;
+
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_PADDING, KM_PAD_RSA_OAEP);
+ begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA1);
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+ 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) {
+ size_t key_size = 768;
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaEncryptionKey(768, 3)
+ .Padding(KM_PAD_RSA_OAEP)
+ .Digest(KM_DIGEST_SHA_2_256)));
+ string message = "Hello World!";
+ string ciphertext = EncryptMessage(string(message), KM_DIGEST_SHA_2_256, KM_PAD_RSA_OAEP);
+ EXPECT_EQ(key_size / 8, ciphertext.size());
+
+ // Corrupt the ciphertext
+ ciphertext[key_size / 8 / 2]++;
+
+ string result;
+ size_t input_consumed;
+ 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);
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(512, 3).Padding(
+ KM_PAD_RSA_PKCS1_1_5_ENCRYPT)));
+ string message = "Hello World!";
+ string ciphertext1 = EncryptMessage(message, KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
+ EXPECT_EQ(512U / 8, ciphertext1.size());
+
+ string ciphertext2 = EncryptMessage(message, KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
+ EXPECT_EQ(512U / 8, ciphertext2.size());
+
+ // 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(512, 3).Padding(
+ KM_PAD_RSA_PKCS1_1_5_ENCRYPT)));
+ string message = "Hello World!";
+ string ciphertext = EncryptMessage(message, KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
+ EXPECT_EQ(512U / 8, ciphertext.size());
+
+ 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) {
+ size_t key_size = 2048;
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaEncryptionKey(key_size, 3)
+ .Padding(KM_PAD_RSA_PKCS1_1_5_ENCRYPT)
+ .Padding(KM_PAD_RSA_OAEP)
+ .Digest(KM_DIGEST_NONE)
+ .Digest(KM_DIGEST_MD5)
+ .Digest(KM_DIGEST_SHA1)
+ .Digest(KM_DIGEST_SHA_2_224)
+ .Digest(KM_DIGEST_SHA_2_256)
+ .Digest(KM_DIGEST_SHA_2_384)
+ .Digest(KM_DIGEST_SHA_2_512)));
+
+ string message = "Hello World!";
+
+ keymaster_padding_t padding_modes[] = {KM_PAD_RSA_OAEP, KM_PAD_RSA_PKCS1_1_5_ENCRYPT};
+ keymaster_digest_t digests[] = {
+ KM_DIGEST_NONE, KM_DIGEST_MD5, KM_DIGEST_SHA1, KM_DIGEST_SHA_2_224,
+ KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512,
+ };
+
+ for (auto padding : padding_modes)
+ for (auto digest : digests) {
+ if (padding == KM_PAD_RSA_OAEP && digest == KM_DIGEST_NONE)
+ // OAEP requires a digest.
+ continue;
+
+ string ciphertext = EncryptMessage(message, digest, padding);
+ EXPECT_EQ(key_size / 8, ciphertext.size());
+
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(512, 3).Padding(
+ KM_PAD_RSA_PKCS1_1_5_ENCRYPT)));
+ string message = "123456789012345678901234567890123456789012345678901234";
+ string result;
+ size_t input_consumed;
+
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(512, 3).Padding(
+ KM_PAD_RSA_PKCS1_1_5_ENCRYPT)));
+ string message = "Hello World!";
+ string ciphertext = EncryptMessage(string(message), KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
+ EXPECT_EQ(512U / 8, ciphertext.size());
+
+ // Corrupt the ciphertext
+ ciphertext[512 / 8 / 2]++;
+
+ string result;
+ size_t input_consumed;
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK,
+ GenerateKey(AuthorizationSetBuilder().RsaSigningKey(256, 3).Padding(KM_PAD_NONE)));
+
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK,
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .HmacKey(128)
+ .Digest(KM_DIGEST_SHA_2_256)
+ .Padding(KM_PAD_NONE)
+ .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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB)
+ .Padding(KM_PAD_NONE)));
+ // Two-block message.
+ string message = "12345678901234567890123456789012";
+ string ciphertext1 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
+ EXPECT_EQ(message.size(), ciphertext1.size());
+
+ string ciphertext2 = EncryptMessage(string(message), KM_MODE_ECB, KM_PAD_NONE);
+ EXPECT_EQ(message.size(), ciphertext2.size());
+
+ // ECB is deterministic.
+ EXPECT_EQ(ciphertext1, ciphertext2);
+
+ string plaintext = DecryptMessage(ciphertext1, KM_MODE_ECB, KM_PAD_NONE);
+ EXPECT_EQ(message, plaintext);
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesEcbNotAuthorized) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC)
+ .Padding(KM_PAD_NONE)));
+ // Two-block message.
+ string message = "12345678901234567890123456789012";
+ AuthorizationSet begin_params(client_params());
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB)
+ .Padding(KM_PAD_NONE)));
+ // Message is slightly shorter than two blocks.
+ string message = "1234567890123456789012345678901";
+
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB);
+ begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+ string ciphertext;
+ size_t input_consumed;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &ciphertext, &input_consumed));
+ EXPECT_EQ(message.size(), input_consumed);
+ EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH, FinishOperation(&ciphertext));
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesEcbPkcs7Padding) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB)
+ .Authorization(TAG_PADDING, KM_PAD_PKCS7)));
+
+ // Try various message lengths; all should work.
+ for (size_t i = 0; i < 32; ++i) {
+ string message(i, 'a');
+ string ciphertext = EncryptMessage(message, KM_MODE_ECB, KM_PAD_PKCS7);
+ EXPECT_EQ(i + 16 - (i % 16), ciphertext.size());
+ string plaintext = DecryptMessage(ciphertext, KM_MODE_ECB, KM_PAD_PKCS7);
+ EXPECT_EQ(message, plaintext);
+ }
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesEcbNoPaddingKeyWithPkcs7Padding) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB)
+ .Authorization(TAG_PADDING, KM_PAD_NONE)));
+
+ // Try various message lengths; all should fail.
+ for (size_t i = 0; i < 32; ++i) {
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB);
+ begin_params.push_back(TAG_PADDING, KM_PAD_PKCS7);
+ EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PADDING_MODE,
+ BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+ }
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesEcbPkcs7PaddingCorrupted) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB)
+ .Authorization(TAG_PADDING, KM_PAD_PKCS7)));
+
+ string message = "a";
+ string ciphertext = EncryptMessage(message, KM_MODE_ECB, KM_PAD_PKCS7);
+ EXPECT_EQ(16U, ciphertext.size());
+ EXPECT_NE(ciphertext, message);
+ ++ciphertext[ciphertext.size() / 2];
+
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB);
+ begin_params.push_back(TAG_PADDING, KM_PAD_PKCS7);
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
+ string plaintext;
+ size_t input_consumed;
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_CTR)
+ .Padding(KM_PAD_NONE)));
+ string message = "123";
+ string iv1;
+ string ciphertext1 = EncryptMessage(message, KM_MODE_CTR, KM_PAD_NONE, &iv1);
+ EXPECT_EQ(message.size(), ciphertext1.size());
+ EXPECT_EQ(16U, iv1.size());
+
+ string iv2;
+ string ciphertext2 = EncryptMessage(message, KM_MODE_CTR, KM_PAD_NONE, &iv2);
+ EXPECT_EQ(message.size(), ciphertext2.size());
+ EXPECT_EQ(16U, iv2.size());
+
+ // IVs should be random, so ciphertexts should differ.
+ EXPECT_NE(iv1, iv2);
+ EXPECT_NE(ciphertext1, ciphertext2);
+
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_CTR)
+ .Padding(KM_PAD_NONE)));
+
+ int increment = 15;
+ string message(239, 'a');
+ AuthorizationSet input_params(client_params());
+ input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CTR);
+ input_params.push_back(TAG_PADDING, KM_PAD_NONE);
+ AuthorizationSet output_params;
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, input_params, &output_params));
+
+ string ciphertext;
+ size_t input_consumed;
+ for (size_t i = 0; i < message.size(); i += increment)
+ EXPECT_EQ(KM_ERROR_OK,
+ UpdateOperation(message.substr(i, increment), &ciphertext, &input_consumed));
+ EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
+ EXPECT_EQ(message.size(), ciphertext.size());
+
+ // Move TAG_NONCE into input_params
+ input_params.Reinitialize(output_params);
+ input_params.push_back(client_params());
+ input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CTR);
+ input_params.push_back(TAG_PADDING, KM_PAD_NONE);
+ output_params.Clear();
+
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, input_params, &output_params));
+ string plaintext;
+ for (size_t i = 0; i < ciphertext.size(); i += increment)
+ EXPECT_EQ(KM_ERROR_OK,
+ UpdateOperation(ciphertext.substr(i, increment), &plaintext, &input_consumed));
+ 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 {
+ const char* key;
+ const char* nonce;
+ const char* plaintext;
+ const char* ciphertext;
+};
+
+// These test vectors are taken from
+// http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf, section F.5.
+static const AesCtrSp80038aTestVector kAesCtrSp80038aTestVectors[] = {
+ // AES-128
+ {
+ "2b7e151628aed2a6abf7158809cf4f3c", "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+ "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
+ "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
+ "874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff"
+ "5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee",
+ },
+ // AES-192
+ {
+ "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b", "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+ "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
+ "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
+ "1abc932417521ca24f2b0459fe7e6e0b090339ec0aa6faefd5ccc2c6f4ce8e94"
+ "1e36b26bd1ebc670d1bd1d665620abf74f78a7f6d29809585a97daec58c6b050",
+ },
+ // AES-256
+ {
+ "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
+ "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+ "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
+ "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
+ "601ec313775789a5b7a7f504bbf3d228f443e3ca4d62b59aca84e990cacaf5c5"
+ "2b0930daa23de94ce87017ba2d84988ddfc9c58db67aada613c2dd08457941a6",
+ },
+};
+
+TEST_P(EncryptionOperationsTest, AesCtrSp80038aTestVector) {
+ for (size_t i = 0; i < 3; i++) {
+ const AesCtrSp80038aTestVector& test(kAesCtrSp80038aTestVectors[i]);
+ const string key = hex2str(test.key);
+ const string nonce = hex2str(test.nonce);
+ const string plaintext = hex2str(test.plaintext);
+ const string ciphertext = hex2str(test.ciphertext);
+ CheckAesCtrTestVector(key, nonce, plaintext, ciphertext);
+ }
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesCtrInvalidPaddingMode) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_CTR)
+ .Authorization(TAG_PADDING, KM_PAD_PKCS7)));
+ AuthorizationSet begin_params(client_params());
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_CTR)
+ .Authorization(TAG_CALLER_NONCE)
+ .Padding(KM_PAD_NONE)));
+
+ AuthorizationSet input_params(client_params());
+ input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CTR);
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC)
+ .Padding(KM_PAD_NONE)));
+ // Two-block message.
+ string message = "12345678901234567890123456789012";
+ string iv1;
+ string ciphertext1 = EncryptMessage(message, KM_MODE_CBC, KM_PAD_NONE, &iv1);
+ EXPECT_EQ(message.size(), ciphertext1.size());
+
+ string iv2;
+ string ciphertext2 = EncryptMessage(message, KM_MODE_CBC, KM_PAD_NONE, &iv2);
+ EXPECT_EQ(message.size(), ciphertext2.size());
+
+ // IVs should be random, so ciphertexts should differ.
+ EXPECT_NE(iv1, iv2);
+ EXPECT_NE(ciphertext1, ciphertext2);
+
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC)
+ .Authorization(TAG_CALLER_NONCE)
+ .Padding(KM_PAD_NONE)));
+ string message = "12345678901234567890123456789012";
+ string iv1;
+ // Don't specify nonce, should get a random one.
+ string ciphertext1 = EncryptMessage(message, KM_MODE_CBC, KM_PAD_NONE, &iv1);
+ EXPECT_EQ(message.size(), ciphertext1.size());
+ EXPECT_EQ(16U, iv1.size());
+
+ string plaintext = DecryptMessage(ciphertext1, KM_MODE_CBC, KM_PAD_NONE, iv1);
+ EXPECT_EQ(message, plaintext);
+
+ // Now specify a nonce, should also work.
+ AuthorizationSet input_params(client_params());
+ AuthorizationSet update_params;
+ AuthorizationSet output_params;
+ input_params.push_back(TAG_NONCE, "abcdefghijklmnop", 16);
+ input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC);
+ input_params.push_back(TAG_PADDING, KM_PAD_NONE);
+ string ciphertext2 =
+ ProcessMessage(KM_PURPOSE_ENCRYPT, message, input_params, update_params, &output_params);
+
+ // Decrypt with correct nonce.
+ plaintext = ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext2, input_params, update_params,
+ &output_params);
+ EXPECT_EQ(message, plaintext);
+
+ // Now try with wrong nonce.
+ input_params.Reinitialize(client_params());
+ input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC);
+ input_params.push_back(TAG_PADDING, KM_PAD_NONE);
+ input_params.push_back(TAG_NONCE, "aaaaaaaaaaaaaaaa", 16);
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC)
+ .Padding(KM_PAD_NONE)));
+
+ string message = "12345678901234567890123456789012";
+ string iv1;
+ // Don't specify nonce, should get a random one.
+ string ciphertext1 = EncryptMessage(message, KM_MODE_CBC, KM_PAD_NONE, &iv1);
+ EXPECT_EQ(message.size(), ciphertext1.size());
+ EXPECT_EQ(16U, iv1.size());
+
+ string plaintext = DecryptMessage(ciphertext1, KM_MODE_CBC, KM_PAD_NONE, iv1);
+ EXPECT_EQ(message, plaintext);
+
+ // Now specify a nonce, should fail.
+ AuthorizationSet input_params(client_params());
+ AuthorizationSet update_params;
+ AuthorizationSet output_params;
+ input_params.push_back(TAG_NONCE, "abcdefghijklmnop", 16);
+ input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC);
+ input_params.push_back(TAG_PADDING, KM_PAD_NONE);
+
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC)
+ .Padding(KM_PAD_NONE)));
+
+ int increment = 15;
+ string message(240, 'a');
+ AuthorizationSet input_params(client_params());
+ input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC);
+ input_params.push_back(TAG_PADDING, KM_PAD_NONE);
+ AuthorizationSet output_params;
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, input_params, &output_params));
+
+ string ciphertext;
+ size_t input_consumed;
+ for (size_t i = 0; i < message.size(); i += increment)
+ EXPECT_EQ(KM_ERROR_OK,
+ UpdateOperation(message.substr(i, increment), &ciphertext, &input_consumed));
+ EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
+ EXPECT_EQ(message.size(), ciphertext.size());
+
+ // Move TAG_NONCE into input_params
+ input_params.Reinitialize(output_params);
+ input_params.push_back(client_params());
+ input_params.push_back(TAG_BLOCK_MODE, KM_MODE_CBC);
+ input_params.push_back(TAG_PADDING, KM_PAD_NONE);
+ output_params.Clear();
+
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, input_params, &output_params));
+ string plaintext;
+ for (size_t i = 0; i < ciphertext.size(); i += increment)
+ EXPECT_EQ(KM_ERROR_OK,
+ UpdateOperation(ciphertext.substr(i, increment), &plaintext, &input_consumed));
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_CBC)
+ .Authorization(TAG_PADDING, KM_PAD_PKCS7)));
+
+ // Try various message lengths; all should work.
+ for (size_t i = 0; i < 32; ++i) {
+ string message(i, 'a');
+ string iv;
+ string ciphertext = EncryptMessage(message, KM_MODE_CBC, KM_PAD_PKCS7, &iv);
+ EXPECT_EQ(i + 16 - (i % 16), ciphertext.size());
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
+ .Authorization(TAG_PADDING, KM_PAD_NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+ string aad = "foobar";
+ string message = "123456789012345678901234567890123456";
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
+ begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+ begin_params.push_back(TAG_MAC_LENGTH, 128);
+
+ AuthorizationSet update_params;
+ update_params.push_back(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+ // Encrypt
+ AuthorizationSet begin_out_params;
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
+ string ciphertext;
+ size_t input_consumed;
+ AuthorizationSet update_out_params;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, &update_out_params, &ciphertext,
+ &input_consumed));
+ EXPECT_EQ(message.size(), input_consumed);
+ EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
+
+ // Grab nonce
+ EXPECT_NE(-1, begin_out_params.find(TAG_NONCE));
+ begin_params.push_back(begin_out_params);
+
+ // Decrypt.
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
+ string plaintext;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, ciphertext, &update_out_params,
+ &plaintext, &input_consumed));
+ EXPECT_EQ(ciphertext.size(), input_consumed);
+ EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext));
+
+ EXPECT_EQ(message, plaintext);
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesGcmTooShortTag) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
+ .Authorization(TAG_PADDING, KM_PAD_NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+ string aad = "foobar";
+ string message = "123456789012345678901234567890123456";
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
+ begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+ begin_params.push_back(TAG_MAC_LENGTH, 96);
+
+ AuthorizationSet update_params;
+ update_params.push_back(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
+ .Authorization(TAG_PADDING, KM_PAD_NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+ string aad = "foobar";
+ string message = "123456789012345678901234567890123456";
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
+ begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+ begin_params.push_back(TAG_MAC_LENGTH, 128);
+
+ AuthorizationSet update_params;
+ update_params.push_back(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+ // Encrypt
+ AuthorizationSet begin_out_params;
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
+ string ciphertext;
+ size_t input_consumed;
+ AuthorizationSet update_out_params;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, &update_out_params, &ciphertext,
+ &input_consumed));
+ EXPECT_EQ(message.size(), input_consumed);
+ EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
+
+ // Grab nonce
+ EXPECT_NE(-1, begin_out_params.find(TAG_NONCE));
+ begin_params.Reinitialize(client_params());
+ begin_params.push_back(begin_out_params);
+ begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
+ begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+ begin_params.push_back(TAG_MAC_LENGTH, 96);
+
+ // Decrypt.
+ EXPECT_EQ(KM_ERROR_INVALID_MAC_LENGTH, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesGcmCorruptKey) {
+ uint8_t nonce[] = {
+ 0xb7, 0x94, 0x37, 0xae, 0x08, 0xff, 0x35, 0x5d, 0x7d, 0x8a, 0x4d, 0x0f,
+ };
+ uint8_t ciphertext[] = {
+ 0xb3, 0xf6, 0x79, 0x9e, 0x8f, 0x93, 0x26, 0xf2, 0xdf, 0x1e, 0x80, 0xfc, 0xd2, 0xcb, 0x16,
+ 0xd7, 0x8c, 0x9d, 0xc7, 0xcc, 0x14, 0xbb, 0x67, 0x78, 0x62, 0xdc, 0x6c, 0x63, 0x9b, 0x3a,
+ 0x63, 0x38, 0xd2, 0x4b, 0x31, 0x2d, 0x39, 0x89, 0xe5, 0x92, 0x0b, 0x5d, 0xbf, 0xc9, 0x76,
+ 0x76, 0x5e, 0xfb, 0xfe, 0x57, 0xbb, 0x38, 0x59, 0x40, 0xa7, 0xa4, 0x3b, 0xdf, 0x05, 0xbd,
+ 0xda, 0xe3, 0xc9, 0xd6, 0xa2, 0xfb, 0xbd, 0xfc, 0xc0, 0xcb, 0xa0,
+ };
+ string ciphertext_str(reinterpret_cast<char*>(ciphertext), sizeof(ciphertext));
+
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
+ begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+ begin_params.push_back(TAG_MAC_LENGTH, 128);
+ begin_params.push_back(TAG_NONCE, nonce, sizeof(nonce));
+
+ string plaintext;
+ size_t input_consumed;
+
+ // Import correct key and decrypt
+ uint8_t good_key[] = {
+ 0xba, 0x76, 0x35, 0x4f, 0x0a, 0xed, 0x6e, 0x8d,
+ 0x91, 0xf4, 0x5c, 0x4f, 0xf5, 0xa0, 0x62, 0xdb,
+ };
+ string good_key_str(reinterpret_cast<char*>(good_key), sizeof(good_key));
+ ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
+ .Authorization(TAG_PADDING, KM_PAD_NONE)
+ .Authorization(TAG_CALLER_NONCE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128),
+ KM_KEY_FORMAT_RAW, good_key_str));
+ 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_OK, FinishOperation(&plaintext));
+
+ // Import bad key and decrypt
+ uint8_t bad_key[] = {
+ 0xbb, 0x76, 0x35, 0x4f, 0x0a, 0xed, 0x6e, 0x8d,
+ 0x91, 0xf4, 0x5c, 0x4f, 0xf5, 0xa0, 0x62, 0xdb,
+ };
+ string bad_key_str(reinterpret_cast<char*>(bad_key), sizeof(bad_key));
+ ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
+ .Authorization(TAG_PADDING, KM_PAD_NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128),
+ KM_KEY_FORMAT_RAW, bad_key_str));
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
+ .Authorization(TAG_PADDING, KM_PAD_NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+ string aad = "123456789012345678";
+ string empty_message;
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
+ begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+ begin_params.push_back(TAG_MAC_LENGTH, 128);
+
+ AuthorizationSet update_params;
+ update_params.push_back(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+ // Encrypt
+ AuthorizationSet begin_out_params;
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
+ string ciphertext;
+ size_t input_consumed;
+ AuthorizationSet update_out_params;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, empty_message, &update_out_params,
+ &ciphertext, &input_consumed));
+ EXPECT_EQ(0U, input_consumed);
+ EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
+
+ // Grab nonce
+ EXPECT_NE(-1, begin_out_params.find(TAG_NONCE));
+ begin_params.push_back(begin_out_params);
+
+ // Decrypt.
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
+ string plaintext;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, ciphertext, &update_out_params,
+ &plaintext, &input_consumed));
+ EXPECT_EQ(ciphertext.size(), input_consumed);
+ EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext));
+
+ EXPECT_EQ(empty_message, plaintext);
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesGcmIncremental) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
+ .Authorization(TAG_PADDING, KM_PAD_NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
+ begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+ begin_params.push_back(TAG_MAC_LENGTH, 128);
+
+ AuthorizationSet update_params;
+ update_params.push_back(TAG_ASSOCIATED_DATA, "b", 1);
+
+ // Encrypt
+ AuthorizationSet begin_out_params;
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
+ string ciphertext;
+ size_t input_consumed;
+ AuthorizationSet update_out_params;
+
+ // Send AAD, incrementally
+ for (int i = 0; i < 1000; ++i) {
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, "", &update_out_params, &ciphertext,
+ &input_consumed));
+ EXPECT_EQ(0U, input_consumed);
+ EXPECT_EQ(0U, ciphertext.size());
+ }
+
+ // Now send data, incrementally, no data.
+ AuthorizationSet empty_params;
+ for (int i = 0; i < 1000; ++i) {
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(empty_params, "a", &update_out_params, &ciphertext,
+ &input_consumed));
+ EXPECT_EQ(1U, input_consumed);
+ }
+ EXPECT_EQ(1000U, ciphertext.size());
+
+ // And finish.
+ EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
+ EXPECT_EQ(1016U, ciphertext.size());
+
+ // Grab nonce
+ EXPECT_NE(-1, begin_out_params.find(TAG_NONCE));
+ begin_params.push_back(begin_out_params);
+
+ // Decrypt.
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
+ string plaintext;
+
+ // Send AAD, incrementally, no data
+ for (int i = 0; i < 1000; ++i) {
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, "", &update_out_params, &plaintext,
+ &input_consumed));
+ EXPECT_EQ(0U, input_consumed);
+ EXPECT_EQ(0U, plaintext.size());
+ }
+
+ // Now send data, incrementally.
+ for (size_t i = 0; i < ciphertext.length(); ++i) {
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(empty_params, string(ciphertext.data() + i, 1),
+ &update_out_params, &plaintext, &input_consumed));
+ EXPECT_EQ(1U, input_consumed);
+ }
+ EXPECT_EQ(1000U, plaintext.size());
+ EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext));
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesGcmMultiPartAad) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
+ .Authorization(TAG_PADDING, KM_PAD_NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+ string message = "123456789012345678901234567890123456";
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
+ begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+ begin_params.push_back(TAG_MAC_LENGTH, 128);
+ AuthorizationSet begin_out_params;
+
+ AuthorizationSet update_params;
+ update_params.push_back(TAG_ASSOCIATED_DATA, "foo", 3);
+
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
+
+ // No data, AAD only.
+ string ciphertext;
+ size_t input_consumed;
+ AuthorizationSet update_out_params;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, "" /* message */, &update_out_params,
+ &ciphertext, &input_consumed));
+ EXPECT_EQ(0U, input_consumed);
+
+ // AAD and data.
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, &update_out_params, &ciphertext,
+ &input_consumed));
+ EXPECT_EQ(message.size(), input_consumed);
+ EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
+
+ // Grab nonce.
+ EXPECT_NE(-1, begin_out_params.find(TAG_NONCE));
+ begin_params.push_back(begin_out_params);
+
+ // Decrypt
+ update_params.Clear();
+ update_params.push_back(TAG_ASSOCIATED_DATA, "foofoo", 6);
+
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params));
+ string plaintext;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, ciphertext, &update_out_params,
+ &plaintext, &input_consumed));
+ EXPECT_EQ(ciphertext.size(), input_consumed);
+ EXPECT_EQ(KM_ERROR_OK, FinishOperation(&plaintext));
+
+ EXPECT_EQ(message, plaintext);
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesGcmBadAad) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
+ .Authorization(TAG_PADDING, KM_PAD_NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+ string message = "12345678901234567890123456789012";
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
+ begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+ begin_params.push_back(TAG_MAC_LENGTH, 128);
+
+ AuthorizationSet update_params;
+ update_params.push_back(TAG_ASSOCIATED_DATA, "foobar", 6);
+
+ AuthorizationSet finish_params;
+ AuthorizationSet finish_out_params;
+
+ // Encrypt
+ AuthorizationSet begin_out_params;
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
+ AuthorizationSet update_out_params;
+ string ciphertext;
+ size_t input_consumed;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, &update_out_params, &ciphertext,
+ &input_consumed));
+ EXPECT_EQ(message.size(), input_consumed);
+ EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
+
+ // Grab nonce
+ EXPECT_NE(-1, begin_out_params.find(TAG_NONCE));
+ begin_params.push_back(begin_out_params);
+
+ update_params.Clear();
+ update_params.push_back(TAG_ASSOCIATED_DATA, "barfoo" /* Wrong AAD */, 6);
+
+ // Decrypt.
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params, &begin_out_params));
+ string plaintext;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, ciphertext, &update_out_params,
+ &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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
+ .Authorization(TAG_PADDING, KM_PAD_NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+ string message = "12345678901234567890123456789012";
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
+ begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+ begin_params.push_back(TAG_MAC_LENGTH, 128);
+
+ AuthorizationSet update_params;
+ update_params.push_back(TAG_ASSOCIATED_DATA, "foobar", 6);
+
+ // Encrypt
+ AuthorizationSet begin_out_params;
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
+ AuthorizationSet update_out_params;
+ string ciphertext;
+ size_t input_consumed;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, &update_out_params, &ciphertext,
+ &input_consumed));
+ EXPECT_EQ(message.size(), input_consumed);
+ EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
+
+ begin_params.push_back(TAG_NONCE, "123456789012", 12);
+
+ // Decrypt
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params, &begin_out_params));
+ string plaintext;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, ciphertext, &update_out_params,
+ &plaintext, &input_consumed));
+ EXPECT_EQ(ciphertext.size(), input_consumed);
+ EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(&plaintext));
+
+ // With wrong nonce, should have gotten garbage plaintext.
+ EXPECT_NE(message, plaintext);
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(EncryptionOperationsTest, AesGcmCorruptTag) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
+ .Authorization(TAG_PADDING, KM_PAD_NONE)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+ string aad = "foobar";
+ string message = "123456789012345678901234567890123456";
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_GCM);
+ begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+ begin_params.push_back(TAG_MAC_LENGTH, 128);
+ AuthorizationSet begin_out_params;
+
+ AuthorizationSet update_params;
+ update_params.push_back(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+ // Encrypt
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params, &begin_out_params));
+ AuthorizationSet update_out_params;
+ string ciphertext;
+ size_t input_consumed;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, &update_out_params, &ciphertext,
+ &input_consumed));
+ EXPECT_EQ(message.size(), input_consumed);
+ EXPECT_EQ(KM_ERROR_OK, FinishOperation(&ciphertext));
+
+ // Corrupt tag
+ (*ciphertext.rbegin())++;
+
+ // Grab nonce.
+ EXPECT_NE(-1, begin_out_params.find(TAG_NONCE));
+ begin_params.push_back(begin_out_params);
+
+ // Decrypt.
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_DECRYPT, begin_params, &begin_out_params));
+ string plaintext;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, ciphertext, &update_out_params,
+ &plaintext, &input_consumed));
+ EXPECT_EQ(ciphertext.size(), input_consumed);
+ EXPECT_EQ(KM_ERROR_VERIFICATION_FAILED, FinishOperation(&plaintext));
+
+ EXPECT_EQ(message, plaintext);
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+typedef Keymaster2Test MaxOperationsTest;
+INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, MaxOperationsTest, test_params);
+
+TEST_P(MaxOperationsTest, TestLimit) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .EcbMode()
+ .Authorization(TAG_PADDING, KM_PAD_NONE)
+ .Authorization(TAG_MAX_USES_PER_BOOT, 3)));
+
+ string message = "1234567890123456";
+ string ciphertext1 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
+ string ciphertext2 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
+ string ciphertext3 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
+
+ // Fourth time should fail.
+ AuthorizationSet begin_params(client_params());
+ 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) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .EcbMode()
+ .Authorization(TAG_PADDING, KM_PAD_NONE)
+ .Authorization(TAG_MAX_USES_PER_BOOT, 3)));
+
+ string message = "1234567890123456";
+ string ciphertext1 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
+ string ciphertext2 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
+ string ciphertext3 = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
+
+ // Fourth time should fail.
+ AuthorizationSet begin_params(client_params());
+ 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;
+INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, AddEntropyTest, test_params);
+
+TEST_P(AddEntropyTest, AddEntropy) {
+ // There's no obvious way to test that entropy is actually added, but we can test that the API
+ // 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 Keymaster0AdapterTest;
+INSTANTIATE_TEST_CASE_P(
+ AndroidKeymasterTest, Keymaster0AdapterTest,
+ ::testing::Values(
+ InstanceCreatorPtr(new Keymaster0AdapterTestInstanceCreator(true /* support_ec */)),
+ InstanceCreatorPtr(new Keymaster0AdapterTestInstanceCreator(false /* support_ec */))));
+
+TEST_P(Keymaster0AdapterTest, OldSoftwareKeymaster1RsaBlob) {
+ // Load and use an old-style Keymaster1 software key blob. These blobs contain OCB-encrypted
+ // key data.
+ string km1_sw = read_file("km1_sw_rsa_512.blob");
+ EXPECT_EQ(486U, km1_sw.length());
+
+ uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km1_sw.length()));
+ memcpy(key_data, km1_sw.data(), km1_sw.length());
+ set_key_blob(key_data, km1_sw.length());
+
+ string message(64, 'a');
+ string signature;
+ SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(Keymaster0AdapterTest, UnversionedSoftwareKeymaster1RsaBlob) {
+ // Load and use an old-style Keymaster1 software key blob, without the version byte. These
+ // blobs contain OCB-encrypted key data.
+ string km1_sw = read_file("km1_sw_rsa_512_unversioned.blob");
+ EXPECT_EQ(477U, km1_sw.length());
+
+ uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km1_sw.length()));
+ memcpy(key_data, km1_sw.data(), km1_sw.length());
+ set_key_blob(key_data, km1_sw.length());
+
+ string message(64, 'a');
+ string signature;
+ SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(Keymaster0AdapterTest, OldSoftwareKeymaster1EcdsaBlob) {
+ // Load and use an old-style Keymaster1 software key blob. These blobs contain OCB-encrypted
+ // key data.
+ string km1_sw = read_file("km1_sw_ecdsa_256.blob");
+ EXPECT_EQ(270U, km1_sw.length());
+
+ uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km1_sw.length()));
+ memcpy(key_data, km1_sw.data(), km1_sw.length());
+ set_key_blob(key_data, km1_sw.length());
+
+ string message(32, static_cast<char>(0xFF));
+ string signature;
+ SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+struct Malloc_Delete {
+ void operator()(void* p) { free(p); }
+};
+
+TEST_P(Keymaster0AdapterTest, OldSoftwareKeymaster0RsaBlob) {
+ // Load and use an old softkeymaster blob. These blobs contain PKCS#8 key data.
+ string km0_sw = read_file("km0_sw_rsa_512.blob");
+ EXPECT_EQ(333U, km0_sw.length());
+
+ uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km0_sw.length()));
+ memcpy(key_data, km0_sw.data(), km0_sw.length());
+ set_key_blob(key_data, km0_sw.length());
+
+ string message(64, 'a');
+ string signature;
+ SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(Keymaster0AdapterTest, OldSwKeymaster0RsaBlobGetCharacteristics) {
+ // Load and use an old softkeymaster blob. These blobs contain PKCS#8 key data.
+ string km0_sw = read_file("km0_sw_rsa_512.blob");
+ EXPECT_EQ(333U, km0_sw.length());
+
+ uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km0_sw.length()));
+ memcpy(key_data, km0_sw.data(), km0_sw.length());
+ set_key_blob(key_data, km0_sw.length());
+
+ EXPECT_EQ(KM_ERROR_OK, GetCharacteristics());
+ EXPECT_TRUE(contains(sw_enforced(), TAG_ALGORITHM, KM_ALGORITHM_RSA));
+ EXPECT_TRUE(contains(sw_enforced(), TAG_KEY_SIZE, 512));
+ EXPECT_TRUE(contains(sw_enforced(), TAG_RSA_PUBLIC_EXPONENT, 3));
+ EXPECT_TRUE(contains(sw_enforced(), TAG_DIGEST, KM_DIGEST_NONE));
+ EXPECT_TRUE(contains(sw_enforced(), TAG_PADDING, KM_PAD_NONE));
+ EXPECT_TRUE(contains(sw_enforced(), TAG_PURPOSE, KM_PURPOSE_SIGN));
+ EXPECT_TRUE(contains(sw_enforced(), TAG_PURPOSE, KM_PURPOSE_VERIFY));
+ EXPECT_TRUE(sw_enforced().GetTagValue(TAG_ALL_USERS));
+ EXPECT_TRUE(sw_enforced().GetTagValue(TAG_NO_AUTH_REQUIRED));
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(Keymaster0AdapterTest, OldHwKeymaster0RsaBlob) {
+ // Load and use an old softkeymaster blob. These blobs contain PKCS#8 key data.
+ string km0_sw = read_file("km0_sw_rsa_512.blob");
+ EXPECT_EQ(333U, km0_sw.length());
+
+ // The keymaster0 wrapper swaps the old softkeymaster leading 'P' for a 'Q' to make the key not
+ // be recognized as a software key. Do the same here to pretend this is a hardware key.
+ EXPECT_EQ('P', km0_sw[0]);
+ km0_sw[0] = 'Q';
+
+ uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km0_sw.length()));
+ memcpy(key_data, km0_sw.data(), km0_sw.length());
+ set_key_blob(key_data, km0_sw.length());
+
+ string message(64, 'a');
+ string signature;
+ SignMessage(message, &signature, KM_DIGEST_NONE, KM_PAD_NONE);
+ VerifyMessage(message, signature, KM_DIGEST_NONE, KM_PAD_NONE);
+
+ EXPECT_EQ(5, GetParam()->keymaster0_calls());
+}
+
+TEST_P(Keymaster0AdapterTest, OldHwKeymaster0RsaBlobGetCharacteristics) {
+ // Load and use an old softkeymaster blob. These blobs contain PKCS#8 key data.
+ string km0_sw = read_file("km0_sw_rsa_512.blob");
+ EXPECT_EQ(333U, km0_sw.length());
+
+ // The keymaster0 wrapper swaps the old softkeymaster leading 'P' for a 'Q' to make the key not
+ // be recognized as a software key. Do the same here to pretend this is a hardware key.
+ EXPECT_EQ('P', km0_sw[0]);
+ km0_sw[0] = 'Q';
+
+ uint8_t* key_data = reinterpret_cast<uint8_t*>(malloc(km0_sw.length()));
+ memcpy(key_data, km0_sw.data(), km0_sw.length());
+ set_key_blob(key_data, km0_sw.length());
+
+ EXPECT_EQ(KM_ERROR_OK, GetCharacteristics());
+ EXPECT_TRUE(contains(hw_enforced(), TAG_ALGORITHM, KM_ALGORITHM_RSA));
+ EXPECT_TRUE(contains(hw_enforced(), TAG_KEY_SIZE, 512));
+ EXPECT_TRUE(contains(hw_enforced(), TAG_RSA_PUBLIC_EXPONENT, 3));
+ EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_NONE));
+ EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_MD5));
+ EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_SHA1));
+ EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_SHA_2_224));
+ EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_SHA_2_256));
+ EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_SHA_2_384));
+ EXPECT_TRUE(contains(hw_enforced(), TAG_DIGEST, KM_DIGEST_SHA_2_512));
+ EXPECT_TRUE(contains(hw_enforced(), TAG_PADDING, KM_PAD_NONE));
+ EXPECT_TRUE(contains(hw_enforced(), TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_ENCRYPT));
+ EXPECT_TRUE(contains(hw_enforced(), TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN));
+ EXPECT_TRUE(contains(hw_enforced(), TAG_PADDING, KM_PAD_RSA_OAEP));
+ EXPECT_TRUE(contains(hw_enforced(), TAG_PADDING, KM_PAD_RSA_PSS));
+ EXPECT_EQ(15U, hw_enforced().size());
+
+ EXPECT_TRUE(contains(sw_enforced(), TAG_PURPOSE, KM_PURPOSE_SIGN));
+ EXPECT_TRUE(contains(sw_enforced(), TAG_PURPOSE, KM_PURPOSE_VERIFY));
+ EXPECT_TRUE(sw_enforced().GetTagValue(TAG_ALL_USERS));
+ EXPECT_TRUE(sw_enforced().GetTagValue(TAG_NO_AUTH_REQUIRED));
+
+ EXPECT_FALSE(contains(sw_enforced(), TAG_ALGORITHM, KM_ALGORITHM_RSA));
+ EXPECT_FALSE(contains(sw_enforced(), TAG_KEY_SIZE, 512));
+ EXPECT_FALSE(contains(sw_enforced(), TAG_RSA_PUBLIC_EXPONENT, 3));
+ EXPECT_FALSE(contains(sw_enforced(), TAG_DIGEST, KM_DIGEST_NONE));
+ EXPECT_FALSE(contains(sw_enforced(), TAG_PADDING, KM_PAD_NONE));
+
+ EXPECT_EQ(1, GetParam()->keymaster0_calls());
+}
+
+typedef Keymaster2Test AttestationTest;
+INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, AttestationTest, test_params);
+
+static X509* parse_cert_blob(const keymaster_blob_t& blob) {
+ const uint8_t* p = blob.data;
+ return d2i_X509(nullptr, &p, blob.data_length);
+}
+
+static bool verify_chain(const keymaster_cert_chain_t& chain) {
+ for (size_t i = 0; i < chain.entry_count - 1; ++i) {
+ keymaster_blob_t& key_cert_blob = chain.entries[i];
+ keymaster_blob_t& signing_cert_blob = chain.entries[i + 1];
+
+ 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;
+
+ EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get()));
+ EXPECT_TRUE(!!signing_pubkey.get());
+ if (!signing_pubkey.get())
+ return false;
+
+ EXPECT_EQ(1, X509_verify(key_cert.get(), signing_pubkey.get()))
+ << "Verification of certificate " << i << " failed";
+ }
+
+ return true;
+}
+
+// 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 */));
+ EXPECT_TRUE(!!oid.get());
+ if (!oid.get())
+ return nullptr;
+
+ int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
+ EXPECT_NE(-1, location);
+ 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;
+
+ ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
+ EXPECT_TRUE(!!attest_rec);
+ return attest_rec;
+}
+
+static bool verify_attestation_record(AuthorizationSet expected_sw_enforced,
+ AuthorizationSet expected_tee_enforced,
+ const keymaster_blob_t& attestation_cert) {
+
+ X509_Ptr cert(parse_cert_blob(attestation_cert));
+ EXPECT_TRUE(!!cert.get());
+ if (!cert.get())
+ return false;
+
+ ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get());
+ EXPECT_TRUE(!!attest_rec);
+ if (!attest_rec)
+ return false;
+
+ AuthorizationSet att_sw_enforced;
+ AuthorizationSet att_tee_enforced;
+ EXPECT_EQ(KM_ERROR_OK, parse_attestation_record(attest_rec->data, attest_rec->length,
+ &att_sw_enforced, &att_tee_enforced));
+
+ // Add TAG_USER_ID to the attestation sw-enforced list, because user IDs are not included in
+ // attestations, since they're meaningless off-device.
+ uint32_t user_id;
+ if (expected_sw_enforced.GetTagValue(TAG_USER_ID, &user_id))
+ att_sw_enforced.push_back(TAG_USER_ID, user_id);
+ if (expected_tee_enforced.GetTagValue(TAG_USER_ID, &user_id))
+ att_tee_enforced.push_back(TAG_USER_ID, user_id);
+
+ att_sw_enforced.Sort();
+ expected_sw_enforced.Sort();
+ EXPECT_EQ(expected_sw_enforced, att_sw_enforced);
+
+ att_tee_enforced.Sort();
+ expected_tee_enforced.Sort();
+ EXPECT_EQ(expected_tee_enforced, att_tee_enforced);
+
+ return true;
+}
+
+TEST_P(AttestationTest, RsaSignedWithRsa) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(256, 3)
+ .Digest(KM_DIGEST_NONE)
+ .Padding(KM_PAD_NONE)));
+
+ keymaster_cert_chain_t cert_chain;
+ EXPECT_EQ(KM_ERROR_OK, AttestKey(KM_ALGORITHM_RSA, &cert_chain));
+ EXPECT_EQ(3U, cert_chain.entry_count);
+ EXPECT_TRUE(verify_chain(cert_chain));
+ EXPECT_TRUE(verify_attestation_record(sw_enforced(), hw_enforced(), cert_chain.entries[0]));
+
+ keymaster_free_cert_chain(&cert_chain);
+}
+
+TEST_P(AttestationTest, RsaSignedWithEc) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(256, 3)
+ .Digest(KM_DIGEST_NONE)
+ .Padding(KM_PAD_NONE)));
+
+ keymaster_cert_chain_t cert_chain;
+ EXPECT_EQ(KM_ERROR_OK, AttestKey(KM_ALGORITHM_EC, &cert_chain));
+ EXPECT_EQ(3U, cert_chain.entry_count);
+ EXPECT_TRUE(verify_chain(cert_chain));
+ EXPECT_TRUE(verify_attestation_record(sw_enforced(), hw_enforced(), cert_chain.entries[0]));
+
+ keymaster_free_cert_chain(&cert_chain);
+}
+
+TEST(SoftKeymasterWrapperTest, CheckKeymaster2Device) {
+ // Make a good fake device, and wrap it.
+ SoftKeymasterDevice* good_fake(new SoftKeymasterDevice(new TestKeymasterContext));
+
+ // Wrap it and check it.
+ SoftKeymasterDevice* good_fake_wrapper(new SoftKeymasterDevice(new TestKeymasterContext));
+ good_fake_wrapper->SetHardwareDevice(good_fake->keymaster_device());
+ EXPECT_TRUE(good_fake_wrapper->Keymaster1DeviceIsGood());
+
+ // Close and clean up wrapper and wrapped
+ good_fake_wrapper->keymaster_device()->common.close(good_fake_wrapper->hw_device());
+
+ // 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());
+
+ // Wrap it and check it.
+ SoftKeymasterDevice* sha256_only_fake_wrapper(
+ (new SoftKeymasterDevice(new TestKeymasterContext)));
+ sha256_only_fake_wrapper->SetHardwareDevice(sha256_only_fake);
+ EXPECT_FALSE(sha256_only_fake_wrapper->Keymaster1DeviceIsGood());
+
+ // Close and clean up wrapper and wrapped
+ sha256_only_fake_wrapper->keymaster_device()->common.close(
+ sha256_only_fake_wrapper->hw_device());
+}
+
+} // namespace test
+} // namespace keymaster
diff --git a/keymaster/android_keymaster_test_utils.cpp b/keymaster/android_keymaster_test_utils.cpp
new file mode 100644
index 0000000..346421a
--- /dev/null
+++ b/keymaster/android_keymaster_test_utils.cpp
@@ -0,0 +1,890 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "android_keymaster_test_utils.h"
+
+#include <algorithm>
+
+#include <openssl/rand.h>
+
+#include <keymaster/android_keymaster_messages.h>
+#include <keymaster/android_keymaster_utils.h>
+
+using std::copy_if;
+using std::find_if;
+using std::is_permutation;
+using std::ostream;
+using std::string;
+using std::vector;
+
+#ifndef KEYMASTER_NAME_TAGS
+#error Keymaster test code requires that KEYMASTER_NAME_TAGS is defined
+#endif
+
+std::ostream& operator<<(std::ostream& os, const keymaster_key_param_t& param) {
+ os << "Tag: " << keymaster::StringifyTag(param.tag);
+ switch (keymaster_tag_get_type(param.tag)) {
+ case KM_INVALID:
+ os << " Invalid";
+ break;
+ case KM_UINT_REP:
+ os << " (Rep)";
+ /* Falls through */
+ case KM_UINT:
+ os << " Int: " << param.integer;
+ break;
+ case KM_ENUM_REP:
+ os << " (Rep)";
+ /* Falls through */
+ case KM_ENUM:
+ os << " Enum: " << param.enumerated;
+ break;
+ case KM_ULONG_REP:
+ os << " (Rep)";
+ /* Falls through */
+ case KM_ULONG:
+ os << " Long: " << param.long_integer;
+ break;
+ case KM_DATE:
+ os << " Date: " << param.date_time;
+ break;
+ case KM_BOOL:
+ os << " Bool: " << param.boolean;
+ break;
+ case KM_BIGNUM:
+ os << " Bignum: ";
+ if (!param.blob.data)
+ os << "(null)";
+ else
+ for (size_t i = 0; i < param.blob.data_length; ++i)
+ os << std::hex << std::setw(2) << static_cast<int>(param.blob.data[i]) << std::dec;
+ break;
+ case KM_BYTES:
+ os << " Bytes: ";
+ if (!param.blob.data)
+ os << "(null)";
+ else
+ for (size_t i = 0; i < param.blob.data_length; ++i)
+ os << std::hex << std::setw(2) << static_cast<int>(param.blob.data[i]) << std::dec;
+ break;
+ }
+ return os;
+}
+
+bool operator==(const keymaster_key_param_t& a, const keymaster_key_param_t& b) {
+ if (a.tag != b.tag) {
+ return false;
+ }
+
+ switch (keymaster_tag_get_type(a.tag)) {
+ case KM_INVALID:
+ return true;
+ case KM_UINT_REP:
+ case KM_UINT:
+ return a.integer == b.integer;
+ case KM_ENUM_REP:
+ case KM_ENUM:
+ return a.enumerated == b.enumerated;
+ case KM_ULONG:
+ case KM_ULONG_REP:
+ return a.long_integer == b.long_integer;
+ case KM_DATE:
+ return a.date_time == b.date_time;
+ case KM_BOOL:
+ return a.boolean == b.boolean;
+ case KM_BIGNUM:
+ case KM_BYTES:
+ if ((a.blob.data == NULL || b.blob.data == NULL) && a.blob.data != b.blob.data)
+ return false;
+ return a.blob.data_length == b.blob.data_length &&
+ (memcmp(a.blob.data, b.blob.data, a.blob.data_length) == 0);
+ }
+
+ return false;
+}
+
+static char hex_value[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // '0'..'9'
+ 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'A'..'F'
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, // 'a'..'f'
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+string hex2str(string a) {
+ string b;
+ size_t num = a.size() / 2;
+ b.resize(num);
+ for (size_t i = 0; i < num; i++) {
+ b[i] = (hex_value[a[i * 2] & 0xFF] << 4) + (hex_value[a[i * 2 + 1] & 0xFF]);
+ }
+ return b;
+}
+
+namespace keymaster {
+
+bool operator==(const AuthorizationSet& a, const AuthorizationSet& b) {
+ if (a.size() != b.size())
+ return false;
+
+ for (size_t i = 0; i < a.size(); ++i)
+ if (!(a[i] == b[i]))
+ return false;
+ return true;
+}
+
+bool operator!=(const AuthorizationSet& a, const AuthorizationSet& b) {
+ return !(a == b);
+}
+
+std::ostream& operator<<(std::ostream& os, const AuthorizationSet& set) {
+ if (set.size() == 0)
+ os << "(Empty)" << std::endl;
+ else {
+ os << "\n";
+ for (size_t i = 0; i < set.size(); ++i)
+ os << set[i] << std::endl;
+ }
+ return os;
+}
+
+namespace test {
+
+Keymaster2Test::Keymaster2Test() : op_handle_(OP_HANDLE_SENTINEL) {
+ memset(&characteristics_, 0, sizeof(characteristics_));
+ blob_.key_material = nullptr;
+ RAND_seed("foobar", 6);
+ blob_.key_material = 0;
+ device_ = GetParam()->CreateDevice();
+}
+
+Keymaster2Test::~Keymaster2Test() {
+ FreeCharacteristics();
+ FreeKeyBlob();
+ device_->common.close(reinterpret_cast<hw_device_t*>(device_));
+}
+
+keymaster2_device_t* Keymaster2Test::device() {
+ return device_;
+}
+
+keymaster_error_t Keymaster2Test::GenerateKey(const AuthorizationSetBuilder& builder) {
+ AuthorizationSet params(builder.build());
+ params.push_back(UserAuthParams());
+ params.push_back(ClientParams());
+
+ FreeKeyBlob();
+ FreeCharacteristics();
+ return device()->generate_key(device(), ¶ms, &blob_, &characteristics_);
+}
+
+keymaster_error_t Keymaster2Test::DeleteKey() {
+ return device()->delete_key(device(), &blob_);
+}
+
+keymaster_error_t Keymaster2Test::ImportKey(const AuthorizationSetBuilder& builder,
+ keymaster_key_format_t format,
+ const string& key_material) {
+ AuthorizationSet params(builder.build());
+ params.push_back(UserAuthParams());
+ params.push_back(ClientParams());
+
+ FreeKeyBlob();
+ FreeCharacteristics();
+ keymaster_blob_t key = {reinterpret_cast<const uint8_t*>(key_material.c_str()),
+ key_material.length()};
+ return device()->import_key(device(), ¶ms, format, &key, &blob_, &characteristics_);
+}
+
+AuthorizationSet Keymaster2Test::UserAuthParams() {
+ AuthorizationSet set;
+ set.push_back(TAG_USER_ID, 7);
+ set.push_back(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD);
+ set.push_back(TAG_AUTH_TIMEOUT, 300);
+ return set;
+}
+
+AuthorizationSet Keymaster2Test::ClientParams() {
+ AuthorizationSet set;
+ set.push_back(TAG_APPLICATION_ID, "app_id", 6);
+ return set;
+}
+
+keymaster_error_t Keymaster2Test::BeginOperation(keymaster_purpose_t purpose) {
+ AuthorizationSet in_params(client_params());
+ keymaster_key_param_set_t out_params;
+ keymaster_error_t error =
+ device()->begin(device(), purpose, &blob_, &in_params, &out_params, &op_handle_);
+ EXPECT_EQ(0U, out_params.length);
+ EXPECT_TRUE(out_params.params == nullptr);
+ return error;
+}
+
+keymaster_error_t Keymaster2Test::BeginOperation(keymaster_purpose_t purpose,
+ const AuthorizationSet& input_set,
+ AuthorizationSet* output_set) {
+ keymaster_key_param_set_t out_params;
+ keymaster_error_t error =
+ device()->begin(device(), purpose, &blob_, &input_set, &out_params, &op_handle_);
+ if (error == KM_ERROR_OK) {
+ if (output_set) {
+ output_set->Reinitialize(out_params);
+ } else {
+ EXPECT_EQ(0U, out_params.length);
+ EXPECT_TRUE(out_params.params == nullptr);
+ }
+ keymaster_free_param_set(&out_params);
+ }
+ return error;
+}
+
+keymaster_error_t Keymaster2Test::UpdateOperation(const string& message, string* output,
+ size_t* input_consumed) {
+ EXPECT_NE(op_handle_, OP_HANDLE_SENTINEL);
+ keymaster_blob_t input = {reinterpret_cast<const uint8_t*>(message.c_str()), message.length()};
+ keymaster_blob_t out_tmp;
+ keymaster_key_param_set_t out_params;
+ keymaster_error_t error = device()->update(device(), op_handle_, nullptr /* params */, &input,
+ input_consumed, &out_params, &out_tmp);
+ if (error == KM_ERROR_OK && out_tmp.data)
+ output->append(reinterpret_cast<const char*>(out_tmp.data), out_tmp.data_length);
+ free(const_cast<uint8_t*>(out_tmp.data));
+ return error;
+}
+
+keymaster_error_t Keymaster2Test::UpdateOperation(const AuthorizationSet& additional_params,
+ const string& message,
+ AuthorizationSet* output_params, string* output,
+ size_t* input_consumed) {
+ EXPECT_NE(op_handle_, OP_HANDLE_SENTINEL);
+ keymaster_blob_t input = {reinterpret_cast<const uint8_t*>(message.c_str()), message.length()};
+ keymaster_blob_t out_tmp;
+ keymaster_key_param_set_t out_params;
+ keymaster_error_t error = device()->update(device(), op_handle_, &additional_params, &input,
+ input_consumed, &out_params, &out_tmp);
+ 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);
+ keymaster_free_param_set(&out_params);
+ return error;
+}
+
+keymaster_error_t Keymaster2Test::FinishOperation(string* output) {
+ return FinishOperation("", output);
+}
+
+keymaster_error_t Keymaster2Test::FinishOperation(const string& signature, string* output) {
+ AuthorizationSet additional_params;
+ AuthorizationSet output_params;
+ return FinishOperation(additional_params, signature, &output_params, output);
+}
+
+keymaster_error_t Keymaster2Test::FinishOperation(const AuthorizationSet& additional_params,
+ const string& signature,
+ AuthorizationSet* output_params, string* output) {
+ keymaster_blob_t sig = {reinterpret_cast<const uint8_t*>(signature.c_str()),
+ signature.length()};
+ keymaster_blob_t out_tmp;
+ keymaster_key_param_set_t out_params;
+ keymaster_error_t error = device()->finish(device(), op_handle_, &additional_params,
+ nullptr /* input */, &sig, &out_params, &out_tmp);
+ if (error != KM_ERROR_OK) {
+ EXPECT_TRUE(out_tmp.data == nullptr);
+ EXPECT_TRUE(out_params.params == nullptr);
+ return error;
+ }
+
+ 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);
+ keymaster_free_param_set(&out_params);
+ return error;
+}
+
+keymaster_error_t Keymaster2Test::AbortOperation() {
+ return device()->abort(device(), op_handle_);
+}
+
+keymaster_error_t Keymaster2Test::AttestKey(keymaster_algorithm_t algorithm,
+ keymaster_cert_chain_t* cert_chain) {
+ AuthorizationSet attest_params(
+ AuthorizationSetBuilder().Authorization(TAG_ALGORITHM, algorithm));
+ attest_params.push_back(UserAuthParams());
+ attest_params.push_back(ClientParams());
+ return device()->attest_key(device(), &blob_, &attest_params, cert_chain);
+}
+
+string Keymaster2Test::ProcessMessage(keymaster_purpose_t purpose, const string& message) {
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose, client_params(), NULL /* output_params */));
+
+ string result;
+ size_t input_consumed;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+ EXPECT_EQ(message.size(), input_consumed);
+ EXPECT_EQ(KM_ERROR_OK, FinishOperation(&result));
+ return result;
+}
+
+string Keymaster2Test::ProcessMessage(keymaster_purpose_t purpose, const string& message,
+ const AuthorizationSet& begin_params,
+ const AuthorizationSet& update_params,
+ AuthorizationSet* begin_out_params) {
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose, begin_params, begin_out_params));
+
+ string result;
+ size_t input_consumed;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, nullptr /* output_params */,
+ &result, &input_consumed));
+ EXPECT_EQ(message.size(), input_consumed);
+ EXPECT_EQ(KM_ERROR_OK, FinishOperation(update_params, "", &result));
+ return result;
+}
+
+string Keymaster2Test::ProcessMessage(keymaster_purpose_t purpose, const string& message,
+ const string& signature, const AuthorizationSet& begin_params,
+ const AuthorizationSet& update_params,
+ AuthorizationSet* output_params) {
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose, begin_params, output_params));
+
+ string result;
+ size_t input_consumed;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(update_params, message, nullptr /* output_params */,
+ &result, &input_consumed));
+ EXPECT_EQ(message.size(), input_consumed);
+ EXPECT_EQ(KM_ERROR_OK, FinishOperation(update_params, signature, &result));
+ return result;
+}
+
+string Keymaster2Test::ProcessMessage(keymaster_purpose_t purpose, const string& message,
+ const string& signature) {
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose, client_params(), NULL /* output_params */));
+
+ string result;
+ size_t input_consumed;
+ EXPECT_EQ(KM_ERROR_OK, UpdateOperation(message, &result, &input_consumed));
+ EXPECT_EQ(message.size(), input_consumed);
+ EXPECT_EQ(KM_ERROR_OK, FinishOperation(signature, &result));
+ return result;
+}
+
+void Keymaster2Test::SignMessage(const string& message, string* signature,
+ keymaster_digest_t digest) {
+ SCOPED_TRACE("SignMessage");
+ AuthorizationSet input_params(AuthorizationSet(client_params_, array_length(client_params_)));
+ input_params.push_back(TAG_DIGEST, digest);
+ AuthorizationSet update_params;
+ AuthorizationSet output_params;
+ *signature =
+ ProcessMessage(KM_PURPOSE_SIGN, message, input_params, update_params, &output_params);
+ EXPECT_GT(signature->size(), 0U);
+}
+
+void Keymaster2Test::SignMessage(const string& message, string* signature,
+ keymaster_digest_t digest, keymaster_padding_t padding) {
+ SCOPED_TRACE("SignMessage");
+ AuthorizationSet input_params(AuthorizationSet(client_params_, array_length(client_params_)));
+ input_params.push_back(TAG_DIGEST, digest);
+ input_params.push_back(TAG_PADDING, padding);
+ AuthorizationSet update_params;
+ AuthorizationSet output_params;
+ *signature =
+ ProcessMessage(KM_PURPOSE_SIGN, message, input_params, update_params, &output_params);
+ EXPECT_GT(signature->size(), 0U);
+}
+
+void Keymaster2Test::MacMessage(const string& message, string* signature, size_t mac_length) {
+ SCOPED_TRACE("SignMessage");
+ AuthorizationSet input_params(AuthorizationSet(client_params_, array_length(client_params_)));
+ input_params.push_back(TAG_MAC_LENGTH, mac_length);
+ AuthorizationSet update_params;
+ AuthorizationSet output_params;
+ *signature =
+ ProcessMessage(KM_PURPOSE_SIGN, message, input_params, update_params, &output_params);
+ EXPECT_GT(signature->size(), 0U);
+}
+
+void Keymaster2Test::VerifyMessage(const string& message, const string& signature,
+ keymaster_digest_t digest) {
+ SCOPED_TRACE("VerifyMessage");
+ AuthorizationSet input_params(client_params());
+ input_params.push_back(TAG_DIGEST, digest);
+ AuthorizationSet update_params;
+ AuthorizationSet output_params;
+ ProcessMessage(KM_PURPOSE_VERIFY, message, signature, input_params, update_params,
+ &output_params);
+}
+
+void Keymaster2Test::VerifyMessage(const string& message, const string& signature,
+ keymaster_digest_t digest, keymaster_padding_t padding) {
+ SCOPED_TRACE("VerifyMessage");
+ AuthorizationSet input_params(client_params());
+ input_params.push_back(TAG_DIGEST, digest);
+ input_params.push_back(TAG_PADDING, padding);
+ AuthorizationSet update_params;
+ AuthorizationSet output_params;
+ ProcessMessage(KM_PURPOSE_VERIFY, message, signature, input_params, update_params,
+ &output_params);
+}
+
+void Keymaster2Test::VerifyMac(const string& message, const string& signature) {
+ SCOPED_TRACE("VerifyMac");
+ ProcessMessage(KM_PURPOSE_VERIFY, message, signature);
+}
+
+string Keymaster2Test::EncryptMessage(const string& message, keymaster_padding_t padding,
+ string* generated_nonce) {
+ SCOPED_TRACE("EncryptMessage");
+ AuthorizationSet begin_params(client_params()), output_params;
+ begin_params.push_back(TAG_PADDING, padding);
+ AuthorizationSet update_params;
+ 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 string& message, keymaster_digest_t digest,
+ keymaster_padding_t padding, string* generated_nonce) {
+ AuthorizationSet update_params;
+ return EncryptMessage(update_params, message, 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;
+ return EncryptMessage(update_params, message, block_mode, padding, generated_nonce);
+}
+
+string Keymaster2Test::EncryptMessage(const AuthorizationSet& update_params, const string& message,
+ keymaster_digest_t 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);
+ 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_block_mode_t block_mode,
+ 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_BLOCK_MODE, block_mode);
+ 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::EncryptMessageWithParams(const string& message,
+ const AuthorizationSet& begin_params,
+ const AuthorizationSet& update_params,
+ AuthorizationSet* output_params) {
+ SCOPED_TRACE("EncryptMessageWithParams");
+ return ProcessMessage(KM_PURPOSE_ENCRYPT, message, begin_params, update_params, output_params);
+}
+
+string Keymaster2Test::DecryptMessage(const string& ciphertext, keymaster_padding_t padding) {
+ SCOPED_TRACE("DecryptMessage");
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_PADDING, padding);
+ AuthorizationSet update_params;
+ return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext, begin_params, update_params);
+}
+
+string Keymaster2Test::DecryptMessage(const string& ciphertext, keymaster_digest_t 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);
+ AuthorizationSet update_params;
+ return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext, begin_params, update_params);
+}
+
+string Keymaster2Test::DecryptMessage(const string& ciphertext, keymaster_block_mode_t block_mode,
+ keymaster_padding_t padding) {
+ SCOPED_TRACE("DecryptMessage");
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_PADDING, padding);
+ begin_params.push_back(TAG_BLOCK_MODE, block_mode);
+ AuthorizationSet update_params;
+ return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext, begin_params, update_params);
+}
+
+string Keymaster2Test::DecryptMessage(const string& ciphertext, keymaster_digest_t digest,
+ keymaster_padding_t padding, const string& nonce) {
+ 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_NONCE, nonce.data(), nonce.size());
+ AuthorizationSet update_params;
+ return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext, begin_params, update_params);
+}
+
+string Keymaster2Test::DecryptMessage(const string& ciphertext, keymaster_block_mode_t block_mode,
+ keymaster_padding_t padding, const string& nonce) {
+ SCOPED_TRACE("DecryptMessage");
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_PADDING, padding);
+ begin_params.push_back(TAG_BLOCK_MODE, block_mode);
+ begin_params.push_back(TAG_NONCE, nonce.data(), nonce.size());
+ 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) {
+ 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_NONCE, nonce.data(), nonce.size());
+ return ProcessMessage(KM_PURPOSE_DECRYPT, ciphertext, begin_params, update_params);
+}
+
+keymaster_error_t Keymaster2Test::GetCharacteristics() {
+ FreeCharacteristics();
+ return device()->get_key_characteristics(device(), &blob_, &client_id_, NULL /* app_data */,
+ &characteristics_);
+}
+
+keymaster_error_t Keymaster2Test::ExportKey(keymaster_key_format_t format, string* export_data) {
+ keymaster_blob_t export_tmp;
+ keymaster_error_t error = device()->export_key(device(), format, &blob_, &client_id_,
+ NULL /* app_data */, &export_tmp);
+
+ 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);
+ return error;
+}
+
+void Keymaster2Test::CheckHmacTestVector(const string& key, const string& message, keymaster_digest_t digest,
+ string expected_mac) {
+ ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder()
+ .HmacKey(key.size() * 8)
+ .Authorization(TAG_MIN_MAC_LENGTH, expected_mac.size() * 8)
+ .Digest(digest),
+ KM_KEY_FORMAT_RAW, key));
+ string signature;
+ MacMessage(message, &signature, expected_mac.size() * 8);
+ EXPECT_EQ(expected_mac, signature) << "Test vector didn't match for digest " << (int)digest;
+}
+
+void Keymaster2Test::CheckAesCtrTestVector(const string& key, const string& nonce,
+ const string& message,
+ const string& expected_ciphertext) {
+ ASSERT_EQ(KM_ERROR_OK, ImportKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(key.size() * 8)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_CTR)
+ .Authorization(TAG_CALLER_NONCE)
+ .Padding(KM_PAD_NONE),
+ KM_KEY_FORMAT_RAW, key));
+
+ AuthorizationSet begin_params(client_params()), update_params, output_params;
+ begin_params.push_back(TAG_NONCE, nonce.data(), nonce.size());
+ begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_CTR);
+ begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+ string ciphertext =
+ EncryptMessageWithParams(message, begin_params, update_params, &output_params);
+ EXPECT_EQ(expected_ciphertext, ciphertext);
+}
+
+AuthorizationSet Keymaster2Test::hw_enforced() {
+ return AuthorizationSet(characteristics_.hw_enforced);
+}
+
+AuthorizationSet Keymaster2Test::sw_enforced() {
+ return AuthorizationSet(characteristics_.sw_enforced);
+}
+
+void Keymaster2Test::FreeCharacteristics() {
+ keymaster_free_characteristics(&characteristics_);
+}
+
+void Keymaster2Test::FreeKeyBlob() {
+ free(const_cast<uint8_t*>(blob_.key_material));
+ blob_.key_material = NULL;
+}
+
+void Keymaster2Test::corrupt_key_blob() {
+ assert(blob_.key_material);
+ uint8_t* tmp = const_cast<uint8_t*>(blob_.key_material);
+ ++tmp[blob_.key_material_size / 2];
+}
+
+class Sha256OnlyWrapper {
+ public:
+ explicit Sha256OnlyWrapper(const keymaster1_device_t* wrapped_device) : wrapped_device_(wrapped_device) {
+
+ new_module = *wrapped_device_->common.module;
+ new_module_name = std::string("SHA 256-only ") + wrapped_device_->common.module->name;
+ new_module.name = new_module_name.c_str();
+
+ memset(&device_, 0, sizeof(device_));
+ device_.common.module = &new_module;
+
+ device_.common.close = close_device;
+ device_.get_supported_algorithms = get_supported_algorithms;
+ device_.get_supported_block_modes = get_supported_block_modes;
+ device_.get_supported_padding_modes = get_supported_padding_modes;
+ device_.get_supported_digests = get_supported_digests;
+ device_.get_supported_import_formats = get_supported_import_formats;
+ device_.get_supported_export_formats = get_supported_export_formats;
+ device_.add_rng_entropy = add_rng_entropy;
+ device_.generate_key = generate_key;
+ device_.get_key_characteristics = get_key_characteristics;
+ device_.import_key = import_key;
+ device_.export_key = export_key;
+ device_.begin = begin;
+ device_.update = update;
+ device_.finish = finish;
+ device_.abort = abort;
+ }
+
+ keymaster1_device_t* keymaster_device() { return &device_; }
+
+ static bool is_supported(keymaster_digest_t digest) {
+ return digest == KM_DIGEST_NONE || digest == KM_DIGEST_SHA_2_256;
+ }
+
+ static bool all_digests_supported(const keymaster_key_param_set_t* params) {
+ for (size_t i = 0; i < params->length; ++i)
+ if (params->params[i].tag == TAG_DIGEST)
+ if (!is_supported(static_cast<keymaster_digest_t>(params->params[i].enumerated)))
+ return false;
+ return true;
+ }
+
+ static const keymaster_key_param_t*
+ get_algorithm_param(const keymaster_key_param_set_t* params) {
+ keymaster_key_param_t* end = params->params + params->length;
+ 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;
+ return alg_ptr;
+ }
+
+ static int close_device(hw_device_t* dev) {
+ Sha256OnlyWrapper* wrapper = reinterpret_cast<Sha256OnlyWrapper*>(dev);
+ const keymaster1_device_t* wrapped_device = wrapper->wrapped_device_;
+ delete wrapper;
+ return wrapped_device->common.close(const_cast<hw_device_t*>(&wrapped_device->common));
+ }
+
+ static const keymaster1_device_t* unwrap(const keymaster1_device_t* dev) {
+ return reinterpret_cast<const Sha256OnlyWrapper*>(dev)->wrapped_device_;
+ }
+
+ static keymaster_error_t get_supported_algorithms(const struct keymaster1_device* dev,
+ keymaster_algorithm_t** algorithms,
+ size_t* algorithms_length) {
+ return unwrap(dev)->get_supported_algorithms(unwrap(dev), algorithms, algorithms_length);
+ }
+ static keymaster_error_t get_supported_block_modes(const struct keymaster1_device* dev,
+ keymaster_algorithm_t algorithm,
+ keymaster_purpose_t purpose,
+ keymaster_block_mode_t** modes,
+ size_t* modes_length) {
+ return unwrap(dev)->get_supported_block_modes(unwrap(dev), algorithm, purpose, modes,
+ modes_length);
+ }
+ static keymaster_error_t get_supported_padding_modes(const struct keymaster1_device* dev,
+ keymaster_algorithm_t algorithm,
+ keymaster_purpose_t purpose,
+ keymaster_padding_t** modes,
+ size_t* modes_length) {
+ return unwrap(dev)->get_supported_padding_modes(unwrap(dev), algorithm, purpose, modes,
+ modes_length);
+ }
+
+ static keymaster_error_t get_supported_digests(const keymaster1_device_t* dev,
+ keymaster_algorithm_t algorithm,
+ keymaster_purpose_t purpose,
+ keymaster_digest_t** digests,
+ 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;
+
+ std::vector<keymaster_digest_t> filtered_digests;
+ std::copy_if(*digests, *digests + *digests_length, std::back_inserter(filtered_digests),
+ [](keymaster_digest_t digest) { return is_supported(digest); });
+
+ free(*digests);
+ *digests_length = filtered_digests.size();
+ *digests = reinterpret_cast<keymaster_digest_t*>(
+ malloc(*digests_length * sizeof(keymaster_digest_t)));
+ std::copy(filtered_digests.begin(), filtered_digests.end(), *digests);
+
+ return KM_ERROR_OK;
+ }
+
+ static keymaster_error_t get_supported_import_formats(const struct keymaster1_device* dev,
+ keymaster_algorithm_t algorithm,
+ keymaster_key_format_t** formats,
+ size_t* formats_length) {
+ return unwrap(dev)->get_supported_import_formats(unwrap(dev), algorithm, formats,
+ formats_length);
+ }
+ static keymaster_error_t get_supported_export_formats(const struct keymaster1_device* dev,
+ keymaster_algorithm_t algorithm,
+ keymaster_key_format_t** formats,
+ size_t* formats_length) {
+ return unwrap(dev)->get_supported_export_formats(unwrap(dev), algorithm, formats,
+ formats_length);
+ }
+ static keymaster_error_t add_rng_entropy(const struct keymaster1_device* dev,
+ const uint8_t* data, size_t data_length) {
+ return unwrap(dev)->add_rng_entropy(unwrap(dev), data, data_length);
+ }
+
+ static keymaster_error_t 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) {
+ auto alg_ptr = get_algorithm_param(params);
+ if (!alg_ptr)
+ return KM_ERROR_UNSUPPORTED_ALGORITHM;
+ if (alg_ptr->enumerated == KM_ALGORITHM_HMAC && !all_digests_supported(params))
+ return KM_ERROR_UNSUPPORTED_DIGEST;
+
+ return unwrap(dev)->generate_key(unwrap(dev), params, key_blob, characteristics);
+ }
+
+ static keymaster_error_t
+ get_key_characteristics(const struct keymaster1_device* 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) {
+ return unwrap(dev)->get_key_characteristics(unwrap(dev), key_blob, client_id, app_data,
+ characteristics);
+ }
+
+ static keymaster_error_t
+ import_key(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) {
+ auto alg_ptr = get_algorithm_param(params);
+ if (!alg_ptr)
+ return KM_ERROR_UNSUPPORTED_ALGORITHM;
+ if (alg_ptr->enumerated == KM_ALGORITHM_HMAC && !all_digests_supported(params))
+ return KM_ERROR_UNSUPPORTED_DIGEST;
+
+ return unwrap(dev)->import_key(unwrap(dev), params, key_format, key_data, key_blob,
+ characteristics);
+ }
+
+ static keymaster_error_t export_key(const struct keymaster1_device* dev, //
+ keymaster_key_format_t export_format,
+ const keymaster_key_blob_t* key_to_export,
+ const keymaster_blob_t* client_id,
+ const keymaster_blob_t* app_data,
+ keymaster_blob_t* export_data) {
+ return unwrap(dev)->export_key(unwrap(dev), export_format, key_to_export, client_id,
+ app_data, export_data);
+ }
+
+ static keymaster_error_t begin(const keymaster1_device_t* dev, //
+ keymaster_purpose_t purpose, const keymaster_key_blob_t* key,
+ 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;
+ return unwrap(dev)->begin(unwrap(dev), purpose, key, in_params, out_params,
+ operation_handle);
+ }
+
+ static keymaster_error_t update(const keymaster1_device_t* dev,
+ keymaster_operation_handle_t operation_handle,
+ const keymaster_key_param_set_t* in_params,
+ const keymaster_blob_t* input, size_t* input_consumed,
+ keymaster_key_param_set_t* out_params,
+ keymaster_blob_t* output) {
+ return unwrap(dev)->update(unwrap(dev), operation_handle, in_params, input, input_consumed,
+ out_params, output);
+ }
+
+ static keymaster_error_t finish(const struct keymaster1_device* dev, //
+ keymaster_operation_handle_t operation_handle,
+ const keymaster_key_param_set_t* in_params,
+ const keymaster_blob_t* signature,
+ keymaster_key_param_set_t* out_params,
+ keymaster_blob_t* output) {
+ return unwrap(dev)->finish(unwrap(dev), operation_handle, in_params, signature, out_params,
+ output);
+ }
+
+ static keymaster_error_t abort(const struct keymaster1_device* dev,
+ keymaster_operation_handle_t operation_handle) {
+ return unwrap(dev)->abort(unwrap(dev), operation_handle);
+ }
+
+ private:
+ keymaster1_device_t device_;
+ const keymaster1_device_t* wrapped_device_;
+ hw_module_t new_module;
+ string new_module_name;
+};
+
+keymaster1_device_t* make_device_sha256_only(keymaster1_device_t* device) {
+ return (new Sha256OnlyWrapper(device))->keymaster_device();
+}
+
+} // namespace test
+} // namespace keymaster
diff --git a/keymaster/android_keymaster_test_utils.h b/keymaster/android_keymaster_test_utils.h
new file mode 100644
index 0000000..7a4d35e
--- /dev/null
+++ b/keymaster/android_keymaster_test_utils.h
@@ -0,0 +1,464 @@
+/*
+ * Copyright 2014 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_ANDROID_KEYMASTER_TEST_UTILS_H_
+#define SYSTEM_KEYMASTER_ANDROID_KEYMASTER_TEST_UTILS_H_
+
+/*
+ * Utilities used to help with testing. Not used in production code.
+ */
+
+#include <stdarg.h>
+
+#include <algorithm>
+#include <memory>
+#include <ostream>
+#include <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <hardware/keymaster0.h>
+#include <hardware/keymaster1.h>
+#include <hardware/keymaster2.h>
+#include <hardware/keymaster_defs.h>
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/authorization_set.h>
+#include <keymaster/logger.h>
+
+std::ostream& operator<<(std::ostream& os, const keymaster_key_param_t& param);
+bool operator==(const keymaster_key_param_t& a, const keymaster_key_param_t& b);
+std::string hex2str(std::string);
+
+namespace keymaster {
+
+bool operator==(const AuthorizationSet& a, const AuthorizationSet& b);
+bool operator!=(const AuthorizationSet& a, const AuthorizationSet& b);
+
+std::ostream& operator<<(std::ostream& os, const AuthorizationSet& set);
+
+namespace test {
+
+template <keymaster_tag_t Tag, typename KeymasterEnum>
+bool contains(const AuthorizationSet& set, TypedEnumTag<KM_ENUM, Tag, KeymasterEnum> tag,
+ KeymasterEnum val) {
+ int pos = set.find(tag);
+ return pos != -1 && set[pos].enumerated == val;
+}
+
+template <keymaster_tag_t Tag, typename KeymasterEnum>
+bool contains(const AuthorizationSet& set, TypedEnumTag<KM_ENUM_REP, Tag, KeymasterEnum> tag,
+ KeymasterEnum val) {
+ int pos = -1;
+ while ((pos = set.find(tag, pos)) != -1)
+ if (set[pos].enumerated == val)
+ return true;
+ return false;
+}
+
+template <keymaster_tag_t Tag>
+bool contains(const AuthorizationSet& set, TypedTag<KM_UINT, Tag> tag, uint32_t val) {
+ int pos = set.find(tag);
+ return pos != -1 && set[pos].integer == val;
+}
+
+template <keymaster_tag_t Tag>
+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;
+ return false;
+}
+
+template <keymaster_tag_t Tag>
+bool contains(const AuthorizationSet& set, TypedTag<KM_ULONG, Tag> tag, uint64_t val) {
+ int pos = set.find(tag);
+ return pos != -1 && set[pos].long_integer == val;
+}
+
+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;
+}
+
+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;
+}
+
+inline bool contains(const AuthorizationSet& set, keymaster_tag_t tag) {
+ return set.find(tag) != -1;
+}
+
+class StdoutLogger : public Logger {
+ public:
+ StdoutLogger() { set_instance(this); }
+
+ int log_msg(LogLevel level, const char* fmt, va_list args) const {
+ int output_len = 0;
+ switch (level) {
+ case DEBUG_LVL:
+ output_len = printf("DEBUG: ");
+ break;
+ case INFO_LVL:
+ output_len = printf("INFO: ");
+ break;
+ case WARNING_LVL:
+ output_len = printf("WARNING: ");
+ break;
+ case ERROR_LVL:
+ output_len = printf("ERROR: ");
+ break;
+ case SEVERE_LVL:
+ output_len = printf("SEVERE: ");
+ break;
+ }
+
+ output_len += vprintf(fmt, args);
+ output_len += printf("\n");
+ return output_len;
+ }
+};
+
+inline std::string make_string(const uint8_t* data, size_t length) {
+ return std::string(reinterpret_cast<const char*>(data), length);
+}
+
+template <size_t N> std::string make_string(const uint8_t (&a)[N]) {
+ return make_string(a, N);
+}
+
+/**
+ * Keymaster2TestInstance is used to parameterize Keymaster2Tests. Its main function is to create a
+ * keymaster2_device_t to which test calls can be directed. It also provides a place to specify
+ * various bits of alternative behavior, in cases where different devices are expected to behave
+ * differently (any such cases are a potential bug, but sometimes they may make sense).
+ */
+class Keymaster2TestInstanceCreator {
+ public:
+ 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; }
+};
+
+// Use a shared_ptr because it's copyable.
+typedef std::shared_ptr<Keymaster2TestInstanceCreator> InstanceCreatorPtr;
+
+const uint64_t OP_HANDLE_SENTINEL = 0xFFFFFFFFFFFFFFFF;
+class Keymaster2Test : public testing::TestWithParam<InstanceCreatorPtr> {
+ protected:
+ Keymaster2Test();
+ ~Keymaster2Test();
+
+ keymaster2_device_t* device();
+
+ keymaster_error_t GenerateKey(const AuthorizationSetBuilder& builder);
+
+ keymaster_error_t DeleteKey();
+
+ keymaster_error_t ImportKey(const AuthorizationSetBuilder& builder,
+ keymaster_key_format_t format, const std::string& key_material);
+
+ keymaster_error_t ExportKey(keymaster_key_format_t format, std::string* export_data);
+
+ keymaster_error_t GetCharacteristics();
+
+ keymaster_error_t BeginOperation(keymaster_purpose_t purpose);
+ keymaster_error_t BeginOperation(keymaster_purpose_t purpose, const AuthorizationSet& input_set,
+ AuthorizationSet* output_set = NULL);
+
+ keymaster_error_t UpdateOperation(const std::string& message, std::string* output,
+ size_t* input_consumed);
+ keymaster_error_t UpdateOperation(const AuthorizationSet& additional_params,
+ const std::string& message, AuthorizationSet* output_params,
+ std::string* output, size_t* input_consumed);
+
+ keymaster_error_t FinishOperation(std::string* output);
+ keymaster_error_t FinishOperation(const std::string& signature, std::string* output);
+ keymaster_error_t FinishOperation(const AuthorizationSet& additional_params,
+ const std::string& signature, std::string* output) {
+ return FinishOperation(additional_params, signature, nullptr /* output_params */, output);
+ }
+ keymaster_error_t FinishOperation(const AuthorizationSet& additional_params,
+ const std::string& signature, AuthorizationSet* output_params,
+ std::string* output);
+
+ keymaster_error_t AbortOperation();
+
+ keymaster_error_t AttestKey(keymaster_algorithm_t algorithm, keymaster_cert_chain_t* chain);
+
+ keymaster_error_t GetVersion(uint8_t* major, uint8_t* minor, uint8_t* subminor);
+
+ std::string ProcessMessage(keymaster_purpose_t purpose, const std::string& message);
+ std::string ProcessMessage(keymaster_purpose_t purpose, const std::string& message,
+ const AuthorizationSet& begin_params,
+ const AuthorizationSet& update_params,
+ AuthorizationSet* output_params = NULL);
+ std::string ProcessMessage(keymaster_purpose_t purpose, const std::string& message,
+ const std::string& signature, const AuthorizationSet& begin_params,
+ const AuthorizationSet& update_params,
+ AuthorizationSet* output_params = NULL);
+ std::string ProcessMessage(keymaster_purpose_t purpose, const std::string& message,
+ const std::string& signature);
+
+ void SignMessage(const std::string& message, std::string* signature, keymaster_digest_t digest);
+ void SignMessage(const std::string& message, std::string* signature, keymaster_digest_t digest,
+ keymaster_padding_t padding);
+ void MacMessage(const std::string& message, std::string* signature, size_t mac_length);
+
+ void VerifyMessage(const std::string& message, const std::string& signature,
+ keymaster_digest_t digest);
+ void VerifyMessage(const std::string& message, const std::string& signature,
+ keymaster_digest_t digest, keymaster_padding_t padding);
+ void VerifyMac(const std::string& message, const std::string& signature);
+
+ std::string EncryptMessage(const std::string& message, keymaster_padding_t padding,
+ std::string* generated_nonce = NULL);
+ std::string EncryptMessage(const std::string& message, keymaster_digest_t digest,
+ keymaster_padding_t padding, std::string* generated_nonce = NULL);
+ std::string EncryptMessage(const std::string& message, keymaster_block_mode_t block_mode,
+ keymaster_padding_t padding, std::string* generated_nonce = NULL);
+ std::string EncryptMessage(const AuthorizationSet& update_params, const std::string& message,
+ keymaster_digest_t digest, keymaster_padding_t padding,
+ std::string* generated_nonce = NULL);
+ std::string EncryptMessage(const AuthorizationSet& update_params, const std::string& message,
+ keymaster_block_mode_t block_mode, keymaster_padding_t padding,
+ std::string* generated_nonce = NULL);
+ std::string EncryptMessageWithParams(const std::string& message,
+ const AuthorizationSet& begin_params,
+ const AuthorizationSet& update_params,
+ AuthorizationSet* output_params);
+
+ std::string DecryptMessage(const std::string& ciphertext, keymaster_padding_t padding);
+ std::string DecryptMessage(const std::string& ciphertext, keymaster_digest_t digest,
+ keymaster_padding_t padding);
+ std::string DecryptMessage(const std::string& ciphertext, keymaster_block_mode_t block_mode,
+ 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_block_mode_t block_mode,
+ keymaster_padding_t padding, const std::string& nonce);
+ std::string DecryptMessage(const AuthorizationSet& update_params, const std::string& ciphertext,
+ keymaster_digest_t digest, keymaster_padding_t padding,
+ const std::string& nonce);
+ std::string DecryptMessage(const AuthorizationSet& update_params, const std::string& ciphertext,
+ keymaster_block_mode_t block_mode, keymaster_padding_t padding,
+ const std::string& nonce);
+
+ void CheckHmacTestVector(const std::string& key, const std::string& message, keymaster_digest_t digest,
+ std::string expected_mac);
+ void CheckAesOcbTestVector(const std::string& key, const std::string& nonce,
+ const std::string& associated_data, const std::string& message,
+ const std::string& expected_ciphertext);
+ void CheckAesCtrTestVector(const std::string& key, const std::string& nonce,
+ const std::string& message, const std::string& expected_ciphertext);
+ AuthorizationSet UserAuthParams();
+ AuthorizationSet ClientParams();
+
+ template <typename T>
+ bool ResponseContains(const std::vector<T>& expected, const T* values, size_t len) {
+ return expected.size() == len &&
+ std::is_permutation(values, values + len, expected.begin());
+ }
+
+ template <typename T> bool ResponseContains(T expected, const T* values, size_t len) {
+ return (len == 1 && *values == expected);
+ }
+
+ AuthorizationSet hw_enforced();
+ AuthorizationSet sw_enforced();
+
+ void FreeCharacteristics();
+ void FreeKeyBlob();
+
+ void corrupt_key_blob();
+
+ void set_key_blob(const uint8_t* key, size_t key_length) {
+ FreeKeyBlob();
+ blob_.key_material = key;
+ blob_.key_material_size = key_length;
+ }
+
+ AuthorizationSet client_params() {
+ return AuthorizationSet(client_params_, sizeof(client_params_) / sizeof(client_params_[0]));
+ }
+
+ private:
+ keymaster2_device_t* device_;
+ keymaster_blob_t client_id_ = {.data = reinterpret_cast<const uint8_t*>("app_id"),
+ .data_length = 6};
+ keymaster_key_param_t client_params_[1] = {
+ Authorization(TAG_APPLICATION_ID, client_id_.data, client_id_.data_length)};
+
+ uint64_t op_handle_;
+
+ keymaster_key_blob_t blob_;
+ 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.
+ */
+keymaster1_device_t* make_device_sha256_only(keymaster1_device_t* device);
+
+} // namespace test
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_ANDROID_KEYMASTER_TEST_UTILS_H_
diff --git a/keymaster/android_keymaster_utils.cpp b/keymaster/android_keymaster_utils.cpp
new file mode 100644
index 0000000..053e72a
--- /dev/null
+++ b/keymaster/android_keymaster_utils.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2014 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/android_keymaster_utils.h>
+
+#include <new>
+
+namespace keymaster {
+
+// Keymaster never manages enormous buffers, so anything particularly large is bad data or the
+// result of a bug. We arbitrarily set a 16 MiB limit.
+const size_t kMaxDupBufferSize = 16 * 1024 * 1024;
+
+uint8_t* dup_buffer(const void* buf, size_t size) {
+ if (size >= kMaxDupBufferSize)
+ return nullptr;
+ uint8_t* retval = new (std::nothrow) uint8_t[size];
+ if (retval)
+ memcpy(retval, buf, size);
+ return retval;
+}
+
+int memcmp_s(const void* p1, const void* p2, size_t length) {
+ const uint8_t* s1 = static_cast<const uint8_t*>(p1);
+ const uint8_t* s2 = static_cast<const uint8_t*>(p2);
+ uint8_t result = 0;
+ while (length-- > 0)
+ result |= *s1++ ^ *s2++;
+ return result == 0 ? 0 : 1;
+}
+
+} // namespace keymaster
diff --git a/keymaster/asymmetric_key.cpp b/keymaster/asymmetric_key.cpp
new file mode 100644
index 0000000..02a7f15
--- /dev/null
+++ b/keymaster/asymmetric_key.cpp
@@ -0,0 +1,245 @@
+/*
+ * Copyright 2014 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 "asymmetric_key.h"
+
+#include <new>
+
+#include <openssl/asn1.h>
+#include <openssl/stack.h>
+#include <openssl/x509.h>
+
+#include "attestation_record.h"
+#include "openssl_err.h"
+#include "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 (material == NULL || size == NULL)
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+ EVP_PKEY_Ptr pkey(EVP_PKEY_new());
+ if (!InternalToEvp(pkey.get()))
+ return TranslateLastOpenSslError();
+
+ int key_data_length = i2d_PUBKEY(pkey.get(), NULL);
+ if (key_data_length <= 0)
+ return TranslateLastOpenSslError();
+
+ material->reset(new (std::nothrow) uint8_t[key_data_length]);
+ if (material->get() == NULL)
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ uint8_t* tmp = material->get();
+ if (i2d_PUBKEY(pkey.get(), &tmp) != key_data_length) {
+ material->reset();
+ return TranslateLastOpenSslError();
+ }
+
+ *size = key_data_length;
+ return KM_ERROR_OK;
+}
+
+static keymaster_error_t build_attestation_extension(const AuthorizationSet& tee_enforced,
+ const AuthorizationSet& sw_enforced,
+ X509_EXTENSION_Ptr* extension) {
+ ASN1_OBJECT_Ptr oid(
+ OBJ_txt2obj(kAttestionRecordOid, 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(sw_enforced, tee_enforced, &attest_bytes, &attest_bytes_len);
+ 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))
+ 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;
+}
+
+static 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;
+}
+
+static bool add_attestation_extension(const AuthorizationSet& tee_enforced,
+ const AuthorizationSet& sw_enforced, X509* certificate,
+ keymaster_error_t* error) {
+ X509_EXTENSION_Ptr attest_extension;
+ *error = build_attestation_extension(tee_enforced, sw_enforced, &attest_extension);
+ if (*error != KM_ERROR_OK)
+ return false;
+
+ if (!X509_add_ext(certificate, attest_extension.get() /* Don't release; copied */,
+ -1 /* insert at end */)) {
+ *error = TranslateLastOpenSslError();
+ return false;
+ }
+
+ return true;
+}
+
+static keymaster_error_t get_certificate_blob(X509* certificate, keymaster_blob_t* blob) {
+ int len = i2d_X509(certificate, nullptr);
+ if (len < 0)
+ return TranslateLastOpenSslError();
+
+ uint8_t* data = new uint8_t[len];
+ if (!data)
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ uint8_t* p = data;
+ i2d_X509(certificate, &p);
+
+ blob->data_length = len;
+ blob->data = data;
+
+ return KM_ERROR_OK;
+}
+
+static bool allocate_cert_chain(size_t entry_count, keymaster_cert_chain_t* chain,
+ keymaster_error_t* error) {
+ if (chain->entries) {
+ for (size_t i = 0; i < chain->entry_count; ++i)
+ delete[] chain->entries[i].data;
+ delete[] chain->entries;
+ }
+
+ chain->entry_count = entry_count;
+ chain->entries = new keymaster_blob_t[entry_count];
+ if (!chain->entries) {
+ *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return false;
+ }
+ return true;
+}
+
+// Copies the intermediate and root certificates into chain, leaving the first slot for the leaf
+// certificate.
+static bool copy_attestation_chain(const KeymasterContext& context,
+ keymaster_algorithm_t sign_algorithm,
+ keymaster_cert_chain_t* chain, keymaster_error_t* error) {
+
+ UniquePtr<keymaster_cert_chain_t, CertificateChainDelete> attest_key_chain(
+ context.AttestationChain(sign_algorithm, error));
+ if (!attest_key_chain.get())
+ return false;
+
+ if (!allocate_cert_chain(attest_key_chain->entry_count + 1, chain, error))
+ return false;
+
+ chain->entries[0].data = nullptr; // Leave empty for the leaf certificate.
+ chain->entries[0].data_length = 0;
+
+ for (size_t i = 0; i < attest_key_chain->entry_count; ++i) {
+ chain->entries[i + 1] = attest_key_chain->entries[i];
+ attest_key_chain->entries[i].data = nullptr;
+ }
+
+ return true;
+}
+
+keymaster_error_t AsymmetricKey::GenerateAttestation(const KeymasterContext& context,
+ const AuthorizationSet& attest_params,
+ const AuthorizationSet& tee_enforced,
+ const AuthorizationSet& sw_enforced,
+ keymaster_cert_chain_t* cert_chain) const {
+
+ keymaster_algorithm_t sign_algorithm;
+ if (!attest_params.GetTagValue(TAG_ALGORITHM, &sign_algorithm) ||
+ (sign_algorithm != KM_ALGORITHM_RSA && sign_algorithm != KM_ALGORITHM_EC))
+ return KM_ERROR_INCOMPATIBLE_ALGORITHM;
+
+ EVP_PKEY_Ptr pkey(EVP_PKEY_new());
+ if (!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(),
+ 10000 /* TODO(swillden): Figure out what should go in serial number; probably a random
+ * value */) ||
+ !X509_set_serialNumber(certificate.get(), serialNumber.get() /* Don't release; copied */))
+ return TranslateLastOpenSslError();
+
+ // TODO(swillden): Find useful values (if possible) for issuerName and subjectName.
+ X509_NAME_Ptr issuerName(X509_NAME_new());
+ if (!issuerName.get() ||
+ !X509_set_subject_name(certificate.get(), issuerName.get() /* Don't release; copied */))
+ return TranslateLastOpenSslError();
+
+ X509_NAME_Ptr subjectName(X509_NAME_new());
+ if (!subjectName.get() ||
+ !X509_set_subject_name(certificate.get(), subjectName.get() /* Don't release; copied */))
+ return TranslateLastOpenSslError();
+
+ // TODO(swillden): Use key activity and expiration dates for notBefore and notAfter.
+ ASN1_TIME_Ptr notBefore(ASN1_TIME_new());
+ if (!notBefore.get() || !ASN1_TIME_set(notBefore.get(), 0) ||
+ !X509_set_notBefore(certificate.get(), notBefore.get() /* Don't release; copied */))
+ return TranslateLastOpenSslError();
+
+ ASN1_TIME_Ptr notAfter(ASN1_TIME_new());
+ if (!notAfter.get() || !ASN1_TIME_set(notAfter.get(), 10000) ||
+ !X509_set_notAfter(certificate.get(), notAfter.get() /* Don't release; copied */))
+ return TranslateLastOpenSslError();
+
+ keymaster_error_t error = KM_ERROR_OK;
+ EVP_PKEY_Ptr sign_key(context.AttestationKey(sign_algorithm, &error));
+
+ if (!sign_key.get() || //
+ !add_public_key(pkey.get(), certificate.get(), &error) ||
+ !add_attestation_extension(tee_enforced, sw_enforced, certificate.get(), &error))
+ return error;
+
+ if (!X509_sign(certificate.get(), sign_key.get(), EVP_sha256()))
+ return TranslateLastOpenSslError();
+
+ if (!copy_attestation_chain(context, sign_algorithm, cert_chain, &error))
+ return error;
+
+ return get_certificate_blob(certificate.get(), &cert_chain->entries[0]);
+}
+
+} // namespace keymaster
diff --git a/keymaster/asymmetric_key.h b/keymaster/asymmetric_key.h
new file mode 100644
index 0000000..99ee585
--- /dev/null
+++ b/keymaster/asymmetric_key.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2014 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_ASYMMETRIC_KEY_H
+#define SYSTEM_KEYMASTER_ASYMMETRIC_KEY_H
+
+#include <openssl/evp.h>
+
+#include "key.h"
+
+namespace keymaster {
+
+class AsymmetricKey : public Key {
+ public:
+ AsymmetricKey(const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+ keymaster_error_t* error)
+ : Key(hw_enforced, sw_enforced, error) {}
+
+ keymaster_error_t formatted_key_material(keymaster_key_format_t format,
+ UniquePtr<uint8_t[]>* material,
+ size_t* size) const override;
+
+ keymaster_error_t GenerateAttestation(const KeymasterContext& context,
+ const AuthorizationSet& attest_params,
+ const AuthorizationSet& tee_enforced,
+ const AuthorizationSet& sw_enforced,
+ keymaster_cert_chain_t* certificate_chain) const override;
+
+ virtual bool InternalToEvp(EVP_PKEY* pkey) const = 0;
+ virtual bool EvpToInternal(const EVP_PKEY* pkey) = 0;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_ASYMMETRIC_KEY_H
diff --git a/keymaster/asymmetric_key_factory.cpp b/keymaster/asymmetric_key_factory.cpp
new file mode 100644
index 0000000..b06d0d8
--- /dev/null
+++ b/keymaster/asymmetric_key_factory.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2014 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/asymmetric_key_factory.h>
+
+#include <keymaster/android_keymaster_utils.h>
+
+#include "asymmetric_key.h"
+#include "openssl_err.h"
+#include "openssl_utils.h"
+
+namespace keymaster {
+
+static const keymaster_key_format_t supported_import_formats[] = {KM_KEY_FORMAT_PKCS8};
+const keymaster_key_format_t*
+AsymmetricKeyFactory::SupportedImportFormats(size_t* format_count) const {
+ *format_count = array_length(supported_import_formats);
+ return supported_import_formats;
+}
+
+static const keymaster_key_format_t supported_export_formats[] = {KM_KEY_FORMAT_X509};
+const keymaster_key_format_t*
+AsymmetricKeyFactory::SupportedExportFormats(size_t* format_count) const {
+ *format_count = array_length(supported_export_formats);
+ return supported_export_formats;
+}
+
+keymaster_error_t AsymmetricKeyFactory::LoadKey(const KeymasterKeyBlob& key_material,
+ const AuthorizationSet& /* additional_params */,
+ const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ UniquePtr<Key>* key) const {
+ UniquePtr<AsymmetricKey> asymmetric_key;
+ keymaster_error_t error = CreateEmptyKey(hw_enforced, sw_enforced, &asymmetric_key);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ const uint8_t* tmp = key_material.key_material;
+ EVP_PKEY* pkey =
+ d2i_PrivateKey(evp_key_type(), NULL /* pkey */, &tmp, key_material.key_material_size);
+ if (!pkey)
+ return TranslateLastOpenSslError();
+ UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey_deleter(pkey);
+
+ if (!asymmetric_key->EvpToInternal(pkey))
+ error = TranslateLastOpenSslError();
+ else
+ key->reset(asymmetric_key.release());
+
+ return error;
+}
+
+} // namespace keymaster
diff --git a/keymaster/attestation_record.cpp b/keymaster/attestation_record.cpp
new file mode 100644
index 0000000..809f7c8
--- /dev/null
+++ b/keymaster/attestation_record.cpp
@@ -0,0 +1,654 @@
+/*
+ * 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.
+ */
+
+#include "attestation_record.h"
+
+#include <assert.h>
+
+#include <openssl/asn1t.h>
+
+#include "openssl_err.h"
+#include "openssl_utils.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_INTEGER* os_version;
+ ASN1_INTEGER* os_patchlevel;
+} 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, os_version, ASN1_INTEGER),
+ ASN1_SIMPLE(KM_ROOT_OF_TRUST, os_patchlevel, ASN1_INTEGER),
+} ASN1_SEQUENCE_END(KM_ROOT_OF_TRUST);
+IMPLEMENT_ASN1_FUNCTIONS(KM_ROOT_OF_TRUST);
+
+typedef struct km_auth_list {
+ ASN1_INTEGER_SET* purpose;
+ ASN1_INTEGER* algorithm;
+ ASN1_INTEGER* key_size;
+ ASN1_INTEGER_SET* 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_NULL* ecies_single_hash_mode;
+ ASN1_NULL* include_unique_id;
+ ASN1_INTEGER* blob_usage_requirement;
+ ASN1_NULL* bootloader_only;
+ ASN1_INTEGER* active_date_time;
+ ASN1_INTEGER* origination_expire_date_time;
+ ASN1_INTEGER* usage_expire_date_time;
+ ASN1_INTEGER* min_seconds_between_ops;
+ ASN1_INTEGER* max_uses_per_boot;
+ ASN1_NULL* no_auth_required;
+ ASN1_INTEGER* user_auth_type;
+ ASN1_INTEGER* auth_timeout;
+ ASN1_NULL* allow_while_on_body;
+ ASN1_NULL* all_applications;
+ ASN1_OCTET_STRING* application_id;
+ ASN1_OCTET_STRING* application_data;
+ 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* unique_id;
+} KM_AUTH_LIST;
+
+ASN1_SEQUENCE(KM_AUTH_LIST) = {
+ ASN1_IMP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.masked_tag()),
+ ASN1_IMP_SET_OF_OPT(KM_AUTH_LIST, block_mode, ASN1_INTEGER, TAG_BLOCK_MODE.masked_tag()),
+ ASN1_IMP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.masked_tag()),
+ ASN1_IMP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, caller_nonce, ASN1_NULL, TAG_CALLER_NONCE.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, min_mac_length, ASN1_INTEGER, TAG_MIN_MAC_LENGTH.masked_tag()),
+ ASN1_IMP_SET_OF_OPT(KM_AUTH_LIST, kdf, ASN1_INTEGER, TAG_KDF.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER,
+ TAG_RSA_PUBLIC_EXPONENT.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, ecies_single_hash_mode, ASN1_NULL,
+ TAG_ECIES_SINGLE_HASH_MODE.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, include_unique_id, ASN1_NULL, TAG_INCLUDE_UNIQUE_ID.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, blob_usage_requirement, ASN1_INTEGER,
+ TAG_BLOB_USAGE_REQUIREMENTS.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, bootloader_only, ASN1_NULL, TAG_BOOTLOADER_ONLY.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER,
+ TAG_ORIGINATION_EXPIRE_DATETIME.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER,
+ TAG_USAGE_EXPIRE_DATETIME.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, min_seconds_between_ops, ASN1_INTEGER,
+ TAG_MIN_SECONDS_BETWEEN_OPS.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, max_uses_per_boot, ASN1_INTEGER, TAG_MAX_USES_PER_BOOT.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, allow_while_on_body, ASN1_NULL,
+ TAG_ALLOW_WHILE_ON_BODY.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, all_applications, ASN1_NULL, TAG_ALL_APPLICATIONS.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, application_id, ASN1_OCTET_STRING, TAG_APPLICATION_ID.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, application_data, ASN1_OCTET_STRING,
+ TAG_APPLICATION_DATA.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER,
+ TAG_CREATION_DATETIME.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, rollback_resistant, ASN1_NULL, TAG_ROLLBACK_RESISTANT.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.masked_tag()),
+ ASN1_IMP_OPT(KM_AUTH_LIST, unique_id, ASN1_NULL, TAG_UNIQUE_ID.masked_tag()),
+} ASN1_SEQUENCE_END(KM_AUTH_LIST);
+IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST);
+
+typedef struct km_key_description {
+ KM_AUTH_LIST* software_enforced;
+ KM_AUTH_LIST* tee_enforced;
+} KM_KEY_DESCRIPTION;
+
+ASN1_SEQUENCE(KM_KEY_DESCRIPTION) = {
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, software_enforced, KM_AUTH_LIST),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, tee_enforced, KM_AUTH_LIST),
+} ASN1_SEQUENCE_END(KM_KEY_DESCRIPTION);
+IMPLEMENT_ASN1_FUNCTIONS(KM_KEY_DESCRIPTION);
+
+struct KM_AUTH_LIST_Delete {
+ void operator()(KM_AUTH_LIST* p) { KM_AUTH_LIST_free(p); }
+};
+
+struct KM_KEY_DESCRIPTION_Delete {
+ void operator()(KM_KEY_DESCRIPTION* p) { KM_KEY_DESCRIPTION_free(p); }
+};
+
+static uint32_t get_uint32_value(const keymaster_key_param_t& param) {
+ switch (keymaster_tag_get_type(param.tag)) {
+ case KM_ENUM:
+ case KM_ENUM_REP:
+ return param.enumerated;
+ case KM_UINT:
+ case KM_UINT_REP:
+ return param.integer;
+ default:
+ assert(false);
+ return 0xFFFFFFFF;
+ }
+}
+
+// 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);
+
+ if (dest_integer_set) {
+ if (!*dest_integer_set)
+ *dest_integer_set = sk_ASN1_INTEGER_new_null();
+ if (!*dest_integer_set)
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ 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)
+ ASN1_INTEGER_free(*dest_integer);
+ *dest_integer = value;
+ return KM_ERROR_OK;
+ }
+
+ assert(false); // Should never get here.
+ return KM_ERROR_OK;
+}
+
+// Put the contents of the keymaster AuthorizationSet auth_list in to the ASN.1 record structure,
+// record.
+static keymaster_error_t build_auth_list(const AuthorizationSet& auth_list, KM_AUTH_LIST* record) {
+
+ assert(record);
+
+ for (auto entry : auth_list) {
+
+ ASN1_INTEGER_SET** integer_set = nullptr;
+ ASN1_INTEGER** integer_ptr = nullptr;
+ ASN1_OCTET_STRING** string_ptr = nullptr;
+ ASN1_NULL** bool_ptr = nullptr;
+
+ switch (entry.tag) {
+
+ /* Ignored tags */
+ case KM_TAG_INVALID:
+ case KM_TAG_ASSOCIATED_DATA:
+ case KM_TAG_NONCE:
+ case KM_TAG_AUTH_TOKEN:
+ case KM_TAG_MAC_LENGTH:
+ case KM_TAG_ALL_USERS:
+ case KM_TAG_USER_ID:
+ case KM_TAG_USER_SECURE_ID:
+ case KM_TAG_EXPORTABLE:
+ case KM_TAG_RESET_SINCE_ID_ROTATION:
+ continue;
+
+ /* Non-repeating enumerations */
+ case KM_TAG_ALGORITHM:
+ integer_ptr = &record->algorithm;
+ break;
+ case KM_TAG_EC_CURVE:
+ integer_ptr = &record->ec_curve;
+ break;
+ case KM_TAG_BLOB_USAGE_REQUIREMENTS:
+ integer_ptr = &record->blob_usage_requirement;
+ break;
+ case KM_TAG_USER_AUTH_TYPE:
+ integer_ptr = &record->user_auth_type;
+ break;
+ case KM_TAG_ORIGIN:
+ integer_ptr = &record->origin;
+ break;
+
+ /* Repeating enumerations */
+ case KM_TAG_PURPOSE:
+ integer_set = &record->purpose;
+ break;
+ case KM_TAG_BLOCK_MODE:
+ integer_set = &record->block_mode;
+ break;
+ case KM_TAG_PADDING:
+ integer_set = &record->padding;
+ break;
+ case KM_TAG_DIGEST:
+ integer_set = &record->digest;
+ break;
+ case KM_TAG_KDF:
+ integer_set = &record->kdf;
+ break;
+
+ /* Non-repeating unsigned integers */
+ case KM_TAG_KEY_SIZE:
+ integer_ptr = &record->key_size;
+ break;
+ case KM_TAG_MIN_MAC_LENGTH:
+ integer_ptr = &record->min_mac_length;
+ break;
+ case KM_TAG_MIN_SECONDS_BETWEEN_OPS:
+ integer_ptr = &record->min_seconds_between_ops;
+ break;
+ case KM_TAG_MAX_USES_PER_BOOT:
+ integer_ptr = &record->max_uses_per_boot;
+ break;
+ case KM_TAG_AUTH_TIMEOUT:
+ integer_ptr = &record->auth_timeout;
+ break;
+
+ /* Non-repeating long unsigned integers */
+ case KM_TAG_RSA_PUBLIC_EXPONENT:
+ integer_ptr = &record->rsa_public_exponent;
+ break;
+
+ /* Dates */
+ case KM_TAG_ACTIVE_DATETIME:
+ integer_ptr = &record->active_date_time;
+ break;
+ case KM_TAG_ORIGINATION_EXPIRE_DATETIME:
+ integer_ptr = &record->origination_expire_date_time;
+ break;
+ case KM_TAG_USAGE_EXPIRE_DATETIME:
+ integer_ptr = &record->usage_expire_date_time;
+ break;
+ case KM_TAG_CREATION_DATETIME:
+ integer_ptr = &record->creation_date_time;
+ break;
+
+ /* Booleans */
+ case KM_TAG_CALLER_NONCE:
+ bool_ptr = &record->caller_nonce;
+ break;
+ case KM_TAG_ECIES_SINGLE_HASH_MODE:
+ bool_ptr = &record->ecies_single_hash_mode;
+ break;
+ case KM_TAG_BOOTLOADER_ONLY:
+ bool_ptr = &record->bootloader_only;
+ break;
+ case KM_TAG_NO_AUTH_REQUIRED:
+ bool_ptr = &record->no_auth_required;
+ break;
+ case KM_TAG_ALL_APPLICATIONS:
+ bool_ptr = &record->all_applications;
+ break;
+ case KM_TAG_ROLLBACK_RESISTANT:
+ bool_ptr = &record->rollback_resistant;
+ break;
+ case KM_TAG_INCLUDE_UNIQUE_ID:
+ bool_ptr = &record->include_unique_id;
+ break;
+ case KM_TAG_ALLOW_WHILE_ON_BODY:
+ bool_ptr = &record->allow_while_on_body;
+ break;
+
+ /* Byte arrays*/
+ case KM_TAG_APPLICATION_ID:
+ string_ptr = &record->application_id;
+ break;
+ case KM_TAG_APPLICATION_DATA:
+ string_ptr = &record->application_data;
+ break;
+ case KM_TAG_UNIQUE_ID:
+ string_ptr = &record->unique_id;
+ break;
+
+ /* Root of Trust components */
+ case KM_TAG_OS_VERSION:
+ case KM_TAG_OS_PATCHLEVEL:
+ case KM_TAG_ROOT_OF_TRUST:
+ if (!record->root_of_trust)
+ record->root_of_trust = KM_ROOT_OF_TRUST_new();
+ if (!record->root_of_trust)
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ switch (entry.tag) {
+ case KM_TAG_OS_VERSION:
+ integer_ptr = &record->root_of_trust->os_version;
+ break;
+ case KM_TAG_OS_PATCHLEVEL:
+ integer_ptr = &record->root_of_trust->os_patchlevel;
+ break;
+ case KM_TAG_ROOT_OF_TRUST:
+ string_ptr = &record->root_of_trust->verified_boot_key;
+ break;
+ default:
+ assert(false); // Can't get here.
+ }
+ break;
+ }
+
+ keymaster_tag_type_t type = keymaster_tag_get_type(entry.tag);
+ switch (type) {
+ case KM_ENUM:
+ 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));
+
+ UniquePtr<ASN1_INTEGER, ASN1_INTEGER_Delete> value(ASN1_INTEGER_new());
+ if (!value.get())
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ if (!ASN1_INTEGER_set(value.get(), get_uint32_value(entry)))
+ return TranslateLastOpenSslError();
+
+ insert_integer(value.release(), integer_ptr, integer_set);
+ break;
+ }
+
+ 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));
+
+ UniquePtr<BIGNUM, BIGNUM_Delete> exponent(BN_new());
+ if (!exponent.get())
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ if (type == KM_DATE) {
+ if (!BN_set_word(exponent.get(), entry.date_time))
+ return TranslateLastOpenSslError();
+ } else {
+ if (!BN_set_word(exponent.get(), entry.long_integer))
+ return TranslateLastOpenSslError();
+ }
+
+ UniquePtr<ASN1_INTEGER, ASN1_INTEGER_Delete> value(
+ BN_to_ASN1_INTEGER(exponent.get(), nullptr));
+ 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;
+ break;
+
+ /* Byte arrays*/
+ case KM_BYTES:
+ assert(string_ptr);
+ if (!*string_ptr)
+ *string_ptr = ASN1_OCTET_STRING_new();
+ if (!*string_ptr)
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ if (!ASN1_OCTET_STRING_set(*string_ptr, entry.blob.data, entry.blob.data_length))
+ return TranslateLastOpenSslError();
+ break;
+
+ default:
+ return KM_ERROR_UNIMPLEMENTED;
+ }
+ }
+
+ 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& sw_enforced,
+ const AuthorizationSet& tee_enforced,
+ UniquePtr<uint8_t[]>* asn1_key_desc,
+ size_t* asn1_key_desc_len) {
+ assert(asn1_key_desc && asn1_key_desc_len);
+
+ UniquePtr<KM_KEY_DESCRIPTION, KM_KEY_DESCRIPTION_Delete> key_desc(KM_KEY_DESCRIPTION_new());
+ if (!key_desc.get())
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ keymaster_error_t error;
+
+ error = build_auth_list(sw_enforced, key_desc->software_enforced);
+ if (error != KM_ERROR_OK)
+ return error;
+ error = build_auth_list(tee_enforced, key_desc->tee_enforced);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ int len = i2d_KM_KEY_DESCRIPTION(key_desc.get(), nullptr);
+ if (len < 0)
+ return TranslateLastOpenSslError();
+ *asn1_key_desc_len = len;
+ asn1_key_desc->reset(new 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();
+
+ return KM_ERROR_OK;
+}
+
+// Copy all enumerated values with the specified tag from stack to auth_list.
+static bool get_repeated_enums(const stack_st_ASN1_INTEGER* stack, keymaster_tag_t tag,
+ AuthorizationSet* auth_list) {
+ assert(keymaster_tag_get_type(tag) == KM_ENUM_REP);
+ 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)))))
+ return false;
+ }
+ return true;
+}
+
+// Add the specified integer tag/value pair to auth_list.
+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;
+ 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;
+ 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());
+ 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.
+static keymaster_error_t extract_auth_list(const KM_AUTH_LIST* record,
+ AuthorizationSet* auth_list) {
+ // Purpose
+ 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))
+ 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)))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ // Block mode
+ 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))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ // Padding
+ 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))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ // Min MAC length
+ if (record->min_mac_length &&
+ !auth_list->push_back(TAG_MIN_MAC_LENGTH, ASN1_INTEGER_get(record->min_mac_length)))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ // EC curve
+ 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))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ // ECIES single hash mode
+ if (record->ecies_single_hash_mode && !auth_list->push_back(TAG_ECIES_SINGLE_HASH_MODE))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ // Blob usage requirement
+ if (!get_enum(record->blob_usage_requirement, TAG_BLOB_USAGE_REQUIREMENTS, auth_list))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ // Bootloader only
+ if (record->bootloader_only && !auth_list->push_back(TAG_BOOTLOADER_ONLY))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ // Active date time
+ 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))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ // Usage Expire date time
+ if (!get_ulong(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ // Min seconds between ops
+ if (record->min_seconds_between_ops &&
+ !auth_list->push_back(TAG_MIN_SECONDS_BETWEEN_OPS,
+ ASN1_INTEGER_get(record->min_seconds_between_ops)))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ // Max uses per boot
+ if (record->max_uses_per_boot &&
+ !auth_list->push_back(TAG_MAX_USES_PER_BOOT, ASN1_INTEGER_get(record->max_uses_per_boot)))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ // 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))
+ 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)))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ // 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))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ // Application data
+ if (record->application_data &&
+ !auth_list->push_back(TAG_APPLICATION_DATA, record->application_data->data,
+ record->application_data->length))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ // Creation date time
+ 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))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ // 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 || !rot->os_version || !rot->os_patchlevel)
+ return KM_ERROR_INVALID_KEY_BLOB;
+
+ if (!auth_list->push_back(TAG_OS_VERSION, ASN1_INTEGER_get(rot->os_version)) ||
+ !auth_list->push_back(TAG_OS_PATCHLEVEL, ASN1_INTEGER_get(rot->os_patchlevel)) ||
+ !auth_list->push_back(TAG_ROOT_OF_TRUST, rot->verified_boot_key->data,
+ rot->verified_boot_key->length))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ }
+
+ return KM_ERROR_OK;
+}
+
+// Parse the DER-encoded attestation record, placing the results in software_enforced and
+// tee_enforced.
+keymaster_error_t parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
+ AuthorizationSet* software_enforced,
+ AuthorizationSet* tee_enforced) {
+ 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();
+
+ keymaster_error_t error = extract_auth_list(record->software_enforced, software_enforced);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ return extract_auth_list(record->tee_enforced, tee_enforced);
+}
+
+} // namepace keymaster
diff --git a/keymaster/attestation_record.h b/keymaster/attestation_record.h
new file mode 100644
index 0000000..3cd5dde
--- /dev/null
+++ b/keymaster/attestation_record.h
@@ -0,0 +1,52 @@
+/*
+ * 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>
+
+namespace keymaster {
+
+/**
+ * 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& software_enforced,
+ const AuthorizationSet& tee_enforced,
+ UniquePtr<uint8_t[]>* asn1_key_desc,
+ size_t* asn1_key_desc_len);
+
+keymaster_error_t parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
+ AuthorizationSet* software_enforced,
+ AuthorizationSet* tee_enforced);
+}
+
+#endif // SYSTEM_KEYMASTER_ATTESTATION_RECORD_H_
diff --git a/keymaster/attestation_record_test.cpp b/keymaster/attestation_record_test.cpp
new file mode 100644
index 0000000..21a7eee
--- /dev/null
+++ b/keymaster/attestation_record_test.cpp
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+#include <fstream>
+
+#include <gtest/gtest.h>
+
+#include "android_keymaster_test_utils.h"
+#include "attestation_record.h"
+
+namespace keymaster {
+namespace test {
+
+TEST(AttestTest, Simple) {
+ AuthorizationSet hw_set(AuthorizationSetBuilder()
+ .RsaSigningKey(512, 3)
+ .Digest(KM_DIGEST_SHA_2_256)
+ .Digest(KM_DIGEST_SHA_2_384)
+ .Authorization(TAG_ROOT_OF_TRUST, "foo", 3)
+ .Authorization(TAG_OS_VERSION, 60000)
+ .Authorization(TAG_OS_PATCHLEVEL, 201512)
+ .Authorization(TAG_APPLICATION_ID, "bar", 3));
+ AuthorizationSet sw_set(AuthorizationSetBuilder().Authorization(TAG_ACTIVE_DATETIME, 10));
+
+ UniquePtr<uint8_t[]> asn1;
+ size_t asn1_len;
+ EXPECT_EQ(KM_ERROR_OK, build_attestation_record(sw_set, hw_set, &asn1, &asn1_len));
+ EXPECT_GT(asn1_len, 0U);
+
+ 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);
+ output.close();
+
+ AuthorizationSet parsed_hw_set;
+ AuthorizationSet parsed_sw_set;
+ EXPECT_EQ(KM_ERROR_OK,
+ parse_attestation_record(asn1.get(), asn1_len, &parsed_sw_set, &parsed_hw_set));
+
+ 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);
+}
+
+} // namespace test
+} // namespace keymaster
diff --git a/keymaster/auth_encrypted_key_blob.cpp b/keymaster/auth_encrypted_key_blob.cpp
new file mode 100644
index 0000000..655bc12
--- /dev/null
+++ b/keymaster/auth_encrypted_key_blob.cpp
@@ -0,0 +1,137 @@
+/*
+ * 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 "auth_encrypted_key_blob.h"
+
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/authorization_set.h>
+#include <keymaster/logger.h>
+
+#include "ocb_utils.h"
+
+namespace keymaster {
+
+const uint32_t CURRENT_BLOB_VERSION = 0;
+
+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) {
+ size_t size = 1 /* version byte */ + nonce.SerializedSize() +
+ encrypted_key_material.SerializedSize() + tag.SerializedSize() +
+ hw_enforced.SerializedSize() + sw_enforced.SerializedSize();
+
+ if (!key_blob->Reset(size))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ uint8_t* buf = key_blob->writable_data();
+ const uint8_t* end = key_blob->key_material + key_blob->key_material_size;
+
+ *buf++ = CURRENT_BLOB_VERSION;
+ buf = nonce.Serialize(buf, end);
+ buf = encrypted_key_material.Serialize(buf, end);
+ buf = tag.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 (!nonce->advance_write(OCB_NONCE_LENGTH) || !tag->advance_write(OCB_TAG_LENGTH))
+ return KM_ERROR_UNKNOWN_ERROR;
+ return KM_ERROR_OK;
+}
+
+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;
+
+ 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);
+ }
+ return KM_ERROR_OK;
+}
+
+} // namespace keymaster
diff --git a/keymaster/auth_encrypted_key_blob.h b/keymaster/auth_encrypted_key_blob.h
new file mode 100644
index 0000000..b987d77
--- /dev/null
+++ b/keymaster/auth_encrypted_key_blob.h
@@ -0,0 +1,42 @@
+/*
+ * 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_AUTH_ENCRYPTED_KEY_BLOB_H_
+#define SYSTEM_KEYMASTER_AUTH_ENCRYPTED_KEY_BLOB_H_
+
+#include <hardware/keymaster_defs.h>
+
+namespace keymaster {
+
+class AuthorizationSet;
+class Buffer;
+struct KeymasterKeyBlob;
+
+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);
+
+keymaster_error_t DeserializeAuthEncryptedBlob(const KeymasterKeyBlob& key_blob,
+ KeymasterKeyBlob* encrypted_key_material,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced, Buffer* nonce,
+ Buffer* tag);
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_AUTH_ENCRYPTED_KEY_BLOB_H_
diff --git a/keymaster/authorization_set.cpp b/keymaster/authorization_set.cpp
new file mode 100644
index 0000000..09093c9
--- /dev/null
+++ b/keymaster/authorization_set.cpp
@@ -0,0 +1,616 @@
+/*
+ * Copyright (C) 2014 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/authorization_set.h>
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <new>
+
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/logger.h>
+
+namespace keymaster {
+
+static inline bool is_blob_tag(keymaster_tag_t tag) {
+ return (keymaster_tag_get_type(tag) == KM_BYTES || keymaster_tag_get_type(tag) == KM_BIGNUM);
+}
+
+const size_t STARTING_ELEMS_CAPACITY = 8;
+
+AuthorizationSet::AuthorizationSet(AuthorizationSetBuilder& builder) {
+ elems_ = builder.set.elems_;
+ builder.set.elems_ = NULL;
+
+ elems_size_ = builder.set.elems_size_;
+ builder.set.elems_size_ = 0;
+
+ elems_capacity_ = builder.set.elems_capacity_;
+ builder.set.elems_capacity_ = 0;
+
+ indirect_data_ = builder.set.indirect_data_;
+ builder.set.indirect_data_ = NULL;
+
+ indirect_data_capacity_ = builder.set.indirect_data_capacity_;
+ builder.set.indirect_data_capacity_ = 0;
+
+ indirect_data_size_ = builder.set.indirect_data_size_;
+ builder.set.indirect_data_size_ = 0;
+
+ error_ = builder.set.error_;
+ builder.set.error_ = OK;
+}
+
+AuthorizationSet::~AuthorizationSet() {
+ FreeData();
+}
+
+bool AuthorizationSet::reserve_elems(size_t count) {
+ if (is_valid() != OK)
+ return false;
+
+ if (count >= elems_capacity_) {
+ keymaster_key_param_t* new_elems = new (std::nothrow) keymaster_key_param_t[count];
+ if (new_elems == NULL) {
+ set_invalid(ALLOCATION_FAILURE);
+ return false;
+ }
+ memcpy(new_elems, elems_, sizeof(*elems_) * elems_size_);
+ delete[] elems_;
+ elems_ = new_elems;
+ elems_capacity_ = count;
+ }
+ return true;
+}
+
+bool AuthorizationSet::reserve_indirect(size_t length) {
+ if (is_valid() != OK)
+ return false;
+
+ if (length > indirect_data_capacity_) {
+ uint8_t* new_data = new (std::nothrow) uint8_t[length];
+ if (new_data == NULL) {
+ set_invalid(ALLOCATION_FAILURE);
+ return false;
+ }
+ memcpy(new_data, indirect_data_, indirect_data_size_);
+
+ // Fix up the data pointers to point into the new region.
+ for (size_t i = 0; i < elems_size_; ++i) {
+ if (is_blob_tag(elems_[i].tag))
+ elems_[i].blob.data = new_data + (elems_[i].blob.data - indirect_data_);
+ }
+ delete[] indirect_data_;
+ indirect_data_ = new_data;
+ indirect_data_capacity_ = length;
+ }
+ return true;
+}
+
+bool AuthorizationSet::Reinitialize(const keymaster_key_param_t* elems, const size_t count) {
+ FreeData();
+
+ if (elems == NULL || count == 0) {
+ error_ = OK;
+ return true;
+ }
+
+ if (!reserve_elems(count))
+ return false;
+
+ if (!reserve_indirect(ComputeIndirectDataSize(elems, count)))
+ return false;
+
+ memcpy(elems_, elems, sizeof(keymaster_key_param_t) * count);
+ elems_size_ = count;
+ CopyIndirectData();
+ error_ = OK;
+ return true;
+}
+
+void AuthorizationSet::set_invalid(Error error) {
+ FreeData();
+ error_ = error;
+}
+
+void AuthorizationSet::Sort() {
+ qsort(elems_, elems_size_, sizeof(*elems_),
+ reinterpret_cast<int (*)(const void*, const void*)>(keymaster_param_compare));
+}
+
+void AuthorizationSet::Deduplicate() {
+ Sort();
+
+ size_t invalid_count = 0;
+ for (size_t i = 1; i < size(); ++i) {
+ if (elems_[i - 1].tag == KM_TAG_INVALID)
+ ++invalid_count;
+ else if (keymaster_param_compare(elems_ + i - 1, elems_ + i) == 0) {
+ // Mark dups as invalid. Note that this "leaks" the data referenced by KM_BYTES and
+ // KM_BIGNUM entries, but those are just pointers into indirect_data_, so it will all
+ // get cleaned up.
+ elems_[i - 1].tag = KM_TAG_INVALID;
+ ++invalid_count;
+ }
+ }
+ if (size() > 0 && elems_[size() - 1].tag == KM_TAG_INVALID)
+ ++invalid_count;
+
+ if (invalid_count == 0)
+ return;
+
+ Sort();
+
+ // Since KM_TAG_INVALID == 0, all of the invalid entries are first.
+ elems_size_ -= invalid_count;
+ memmove(elems_, elems_ + invalid_count, size() * sizeof(*elems_));
+}
+
+void AuthorizationSet::CopyToParamSet(keymaster_key_param_set_t* set) const {
+ assert(set);
+
+ set->length = size();
+ set->params =
+ reinterpret_cast<keymaster_key_param_t*>(malloc(sizeof(keymaster_key_param_t) * size()));
+
+ for (size_t i = 0; i < size(); ++i) {
+ const keymaster_key_param_t src = (*this)[i];
+ keymaster_key_param_t& dst(set->params[i]);
+
+ dst = src;
+ keymaster_tag_type_t type = keymaster_tag_get_type(src.tag);
+ if (type == KM_BIGNUM || type == KM_BYTES) {
+ void* tmp = malloc(src.blob.data_length);
+ memcpy(tmp, src.blob.data, src.blob.data_length);
+ dst.blob.data = reinterpret_cast<uint8_t*>(tmp);
+ }
+ }
+}
+
+int AuthorizationSet::find(keymaster_tag_t tag, int begin) const {
+ if (is_valid() != OK)
+ return -1;
+
+ int i = ++begin;
+ while (i < (int)elems_size_ && elems_[i].tag != tag)
+ ++i;
+ if (i == (int)elems_size_)
+ return -1;
+ else
+ return i;
+}
+
+bool AuthorizationSet::erase(size_t index) {
+ if (index >= size())
+ return false;
+
+ --elems_size_;
+ for (size_t i = index; i < elems_size_; ++i)
+ elems_[i] = elems_[i + 1];
+ return true;
+}
+
+keymaster_key_param_t empty_set = {KM_TAG_INVALID, {}};
+keymaster_key_param_t& AuthorizationSet::operator[](int at) {
+ if (is_valid() == OK && at < (int)elems_size_) {
+ return elems_[at];
+ }
+ empty_set = {KM_TAG_INVALID, {}};
+ return empty_set;
+}
+
+keymaster_key_param_t AuthorizationSet::operator[](int at) const {
+ if (is_valid() == OK && at < (int)elems_size_) {
+ return elems_[at];
+ }
+ empty_set = {KM_TAG_INVALID, {}};
+ return empty_set;
+}
+
+bool AuthorizationSet::push_back(const keymaster_key_param_set_t& set) {
+ if (is_valid() != OK)
+ 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;
+
+ return true;
+}
+
+bool AuthorizationSet::push_back(keymaster_key_param_t elem) {
+ if (is_valid() != OK)
+ return false;
+
+ if (elems_size_ >= elems_capacity_)
+ if (!reserve_elems(elems_capacity_ ? elems_capacity_ * 2 : STARTING_ELEMS_CAPACITY))
+ return false;
+
+ if (is_blob_tag(elem.tag)) {
+ if (indirect_data_capacity_ - indirect_data_size_ < elem.blob.data_length)
+ if (!reserve_indirect(2 * (indirect_data_capacity_ + elem.blob.data_length)))
+ return false;
+
+ memcpy(indirect_data_ + indirect_data_size_, elem.blob.data, elem.blob.data_length);
+ elem.blob.data = indirect_data_ + indirect_data_size_;
+ indirect_data_size_ += elem.blob.data_length;
+ }
+
+ elems_[elems_size_++] = elem;
+ return true;
+}
+
+static size_t serialized_size(const keymaster_key_param_t& param) {
+ switch (keymaster_tag_get_type(param.tag)) {
+ case KM_INVALID:
+ return sizeof(uint32_t);
+ case KM_ENUM:
+ case KM_ENUM_REP:
+ case KM_UINT:
+ case KM_UINT_REP:
+ return sizeof(uint32_t) * 2;
+ case KM_ULONG:
+ case KM_ULONG_REP:
+ case KM_DATE:
+ return sizeof(uint32_t) + sizeof(uint64_t);
+ case KM_BOOL:
+ return sizeof(uint32_t) + 1;
+ case KM_BIGNUM:
+ case KM_BYTES:
+ return sizeof(uint32_t) * 3;
+ }
+
+ return sizeof(uint32_t);
+}
+
+static uint8_t* serialize(const keymaster_key_param_t& param, uint8_t* buf, const uint8_t* end,
+ const uint8_t* indirect_base) {
+ buf = append_uint32_to_buf(buf, end, param.tag);
+ switch (keymaster_tag_get_type(param.tag)) {
+ case KM_INVALID:
+ break;
+ case KM_ENUM:
+ case KM_ENUM_REP:
+ buf = append_uint32_to_buf(buf, end, param.enumerated);
+ break;
+ case KM_UINT:
+ case KM_UINT_REP:
+ buf = append_uint32_to_buf(buf, end, param.integer);
+ break;
+ case KM_ULONG:
+ case KM_ULONG_REP:
+ buf = append_uint64_to_buf(buf, end, param.long_integer);
+ break;
+ case KM_DATE:
+ buf = append_uint64_to_buf(buf, end, param.date_time);
+ break;
+ case KM_BOOL:
+ if (buf < end)
+ *buf = static_cast<uint8_t>(param.boolean);
+ buf++;
+ break;
+ case KM_BIGNUM:
+ case KM_BYTES:
+ buf = append_uint32_to_buf(buf, end, param.blob.data_length);
+ buf = append_uint32_to_buf(buf, end, param.blob.data - indirect_base);
+ break;
+ }
+ return buf;
+}
+
+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, ¶m->tag))
+ return false;
+
+ switch (keymaster_tag_get_type(param->tag)) {
+ case KM_INVALID:
+ return false;
+ case KM_ENUM:
+ case KM_ENUM_REP:
+ return copy_uint32_from_buf(buf_ptr, end, ¶m->enumerated);
+ case KM_UINT:
+ case KM_UINT_REP:
+ return copy_uint32_from_buf(buf_ptr, end, ¶m->integer);
+ case KM_ULONG:
+ case KM_ULONG_REP:
+ return copy_uint64_from_buf(buf_ptr, end, ¶m->long_integer);
+ case KM_DATE:
+ return copy_uint64_from_buf(buf_ptr, end, ¶m->date_time);
+ break;
+ case KM_BOOL:
+ if (*buf_ptr < end) {
+ param->boolean = static_cast<bool>(**buf_ptr);
+ (*buf_ptr)++;
+ return true;
+ }
+ return false;
+
+ case KM_BIGNUM:
+ case KM_BYTES: {
+ uint32_t offset;
+ if (!copy_uint32_from_buf(buf_ptr, end, ¶m->blob.data_length) ||
+ !copy_uint32_from_buf(buf_ptr, end, &offset))
+ return false;
+ if (param->blob.data_length + offset < param->blob.data_length || // Overflow check
+ static_cast<ptrdiff_t>(offset) > indirect_end - indirect_base ||
+ static_cast<ptrdiff_t>(offset + param->blob.data_length) > indirect_end - indirect_base)
+ return false;
+ param->blob.data = indirect_base + offset;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+size_t AuthorizationSet::SerializedSizeOfElements() const {
+ size_t size = 0;
+ for (size_t i = 0; i < elems_size_; ++i) {
+ size += serialized_size(elems_[i]);
+ }
+ return size;
+}
+
+size_t AuthorizationSet::SerializedSize() const {
+ return sizeof(uint32_t) + // Size of indirect_data_
+ indirect_data_size_ + // indirect_data_
+ sizeof(uint32_t) + // Number of elems_
+ sizeof(uint32_t) + // Size of elems_
+ SerializedSizeOfElements(); // elems_
+}
+
+uint8_t* AuthorizationSet::Serialize(uint8_t* buf, const uint8_t* end) const {
+ buf = append_size_and_data_to_buf(buf, end, indirect_data_, indirect_data_size_);
+ buf = append_uint32_to_buf(buf, end, elems_size_);
+ buf = append_uint32_to_buf(buf, end, SerializedSizeOfElements());
+ for (size_t i = 0; i < elems_size_; ++i) {
+ buf = serialize(elems_[i], buf, end, indirect_data_);
+ }
+ return buf;
+}
+
+bool AuthorizationSet::DeserializeIndirectData(const uint8_t** buf_ptr, const uint8_t* end) {
+ UniquePtr<uint8_t[]> indirect_buf;
+ if (!copy_size_and_data_from_buf(buf_ptr, end, &indirect_data_size_, &indirect_buf)) {
+ LOG_E("Malformed data found in AuthorizationSet deserialization", 0);
+ set_invalid(MALFORMED_DATA);
+ return false;
+ }
+ indirect_data_ = indirect_buf.release();
+ return true;
+}
+
+bool AuthorizationSet::DeserializeElementsData(const uint8_t** buf_ptr, const uint8_t* end) {
+ uint32_t elements_count;
+ uint32_t elements_size;
+ if (!copy_uint32_from_buf(buf_ptr, end, &elements_count) ||
+ !copy_uint32_from_buf(buf_ptr, end, &elements_size)) {
+ LOG_E("Malformed data found in AuthorizationSet deserialization", 0);
+ set_invalid(MALFORMED_DATA);
+ return false;
+ }
+
+ // Note that the following validation of elements_count is weak, but it prevents allocation of
+ // elems_ arrays which are clearly too large to be reasonable.
+ if (static_cast<ptrdiff_t>(elements_size) > end - *buf_ptr ||
+ elements_count * sizeof(uint32_t) > elements_size ||
+ *buf_ptr + (elements_count * sizeof(*elems_)) < *buf_ptr) {
+ LOG_E("Malformed data found in AuthorizationSet deserialization", 0);
+ set_invalid(MALFORMED_DATA);
+ 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;
+ for (size_t i = 0; i < elements_count; ++i) {
+ if (!deserialize(elems_ + i, buf_ptr, elements_end, indirect_data_, indirect_end)) {
+ LOG_E("Malformed data found in AuthorizationSet deserialization", 0);
+ set_invalid(MALFORMED_DATA);
+ return false;
+ }
+ }
+ elems_size_ = elements_count;
+ return true;
+}
+
+bool AuthorizationSet::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+ FreeData();
+
+ if (!DeserializeIndirectData(buf_ptr, end) || !DeserializeElementsData(buf_ptr, end))
+ return false;
+
+ if (indirect_data_size_ != ComputeIndirectDataSize(elems_, elems_size_)) {
+ LOG_E("Malformed data found in AuthorizationSet deserialization", 0);
+ set_invalid(MALFORMED_DATA);
+ return false;
+ }
+ return true;
+}
+
+void AuthorizationSet::Clear() {
+ memset_s(elems_, 0, elems_size_ * sizeof(keymaster_key_param_t));
+ memset_s(indirect_data_, 0, indirect_data_size_);
+ elems_size_ = 0;
+ indirect_data_size_ = 0;
+}
+
+void AuthorizationSet::FreeData() {
+ Clear();
+
+ delete[] elems_;
+ delete[] indirect_data_;
+
+ elems_ = NULL;
+ indirect_data_ = NULL;
+ elems_capacity_ = 0;
+ indirect_data_capacity_ = 0;
+ error_ = OK;
+}
+
+/* static */
+size_t AuthorizationSet::ComputeIndirectDataSize(const keymaster_key_param_t* elems, size_t count) {
+ size_t size = 0;
+ for (size_t i = 0; i < count; ++i) {
+ if (is_blob_tag(elems[i].tag)) {
+ size += elems[i].blob.data_length;
+ }
+ }
+ return size;
+}
+
+void AuthorizationSet::CopyIndirectData() {
+ memset_s(indirect_data_, 0, indirect_data_capacity_);
+
+ uint8_t* indirect_data_pos = indirect_data_;
+ for (size_t i = 0; i < elems_size_; ++i) {
+ assert(indirect_data_pos <= indirect_data_ + indirect_data_capacity_);
+ if (is_blob_tag(elems_[i].tag)) {
+ memcpy(indirect_data_pos, elems_[i].blob.data, elems_[i].blob.data_length);
+ elems_[i].blob.data = indirect_data_pos;
+ indirect_data_pos += elems_[i].blob.data_length;
+ }
+ }
+ assert(indirect_data_pos == indirect_data_ + indirect_data_capacity_);
+ indirect_data_size_ = indirect_data_pos - indirect_data_;
+}
+
+size_t AuthorizationSet::GetTagCount(keymaster_tag_t tag) const {
+ size_t count = 0;
+ for (int pos = -1; (pos = find(tag, pos)) != -1;)
+ ++count;
+ return count;
+}
+
+bool AuthorizationSet::GetTagValueEnum(keymaster_tag_t tag, uint32_t* val) const {
+ int pos = find(tag);
+ if (pos == -1) {
+ return false;
+ }
+ *val = elems_[pos].enumerated;
+ return true;
+}
+
+bool AuthorizationSet::GetTagValueEnumRep(keymaster_tag_t tag, size_t instance,
+ uint32_t* val) const {
+ size_t count = 0;
+ int pos = -1;
+ while (count <= instance) {
+ pos = find(tag, pos);
+ if (pos == -1) {
+ return false;
+ }
+ ++count;
+ }
+ *val = elems_[pos].enumerated;
+ return true;
+}
+
+bool AuthorizationSet::GetTagValueInt(keymaster_tag_t tag, uint32_t* val) const {
+ int pos = find(tag);
+ if (pos == -1) {
+ return false;
+ }
+ *val = elems_[pos].integer;
+ return true;
+}
+
+bool AuthorizationSet::GetTagValueIntRep(keymaster_tag_t tag, size_t instance,
+ uint32_t* val) const {
+ size_t count = 0;
+ int pos = -1;
+ while (count <= instance) {
+ pos = find(tag, pos);
+ if (pos == -1) {
+ return false;
+ }
+ ++count;
+ }
+ *val = elems_[pos].integer;
+ return true;
+}
+
+bool AuthorizationSet::GetTagValueLong(keymaster_tag_t tag, uint64_t* val) const {
+ int pos = find(tag);
+ if (pos == -1) {
+ return false;
+ }
+ *val = elems_[pos].long_integer;
+ return true;
+}
+
+bool AuthorizationSet::GetTagValueLongRep(keymaster_tag_t tag, size_t instance,
+ uint64_t* val) const {
+ size_t count = 0;
+ int pos = -1;
+ while (count <= instance) {
+ pos = find(tag, pos);
+ if (pos == -1) {
+ return false;
+ }
+ ++count;
+ }
+ *val = elems_[pos].long_integer;
+ return true;
+}
+
+bool AuthorizationSet::GetTagValueDate(keymaster_tag_t tag, uint64_t* val) const {
+ int pos = find(tag);
+ if (pos == -1) {
+ return false;
+ }
+ *val = elems_[pos].date_time;
+ return true;
+}
+
+bool AuthorizationSet::GetTagValueBlob(keymaster_tag_t tag, keymaster_blob_t* val) const {
+ int pos = find(tag);
+ if (pos == -1) {
+ return false;
+ }
+ *val = elems_[pos].blob;
+ return true;
+}
+
+bool AuthorizationSet::GetTagValueBool(keymaster_tag_t tag) const {
+ int pos = find(tag);
+ if (pos == -1) {
+ return false;
+ }
+ assert(elems_[pos].boolean);
+ return elems_[pos].boolean;
+}
+
+bool AuthorizationSet::ContainsEnumValue(keymaster_tag_t tag, uint32_t value) const {
+ for (auto& entry : *this)
+ if (entry.tag == tag && entry.enumerated == value)
+ return true;
+ return false;
+}
+
+} // namespace keymaster
diff --git a/keymaster/authorization_set_test.cpp b/keymaster/authorization_set_test.cpp
new file mode 100644
index 0000000..ddc7df3
--- /dev/null
+++ b/keymaster/authorization_set_test.cpp
@@ -0,0 +1,630 @@
+/*
+ * Copyright (C) 2014 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 <gtest/gtest.h>
+
+#include <keymaster/authorization_set.h>
+#include <keymaster/android_keymaster_utils.h>
+
+#include "android_keymaster_test_utils.h"
+
+namespace keymaster {
+
+namespace test {
+
+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_USER_AUTH_TYPE, HW_AUTH_PASSWORD),
+ Authorization(TAG_APPLICATION_ID, "my_app", 6), Authorization(TAG_KEY_SIZE, 256),
+ Authorization(TAG_AUTH_TIMEOUT, 300),
+ };
+ AuthorizationSet set(params, array_length(params));
+ EXPECT_EQ(8U, set.size());
+}
+
+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_USER_AUTH_TYPE, HW_AUTH_PASSWORD),
+ Authorization(TAG_APPLICATION_ID, "my_app", 6), Authorization(TAG_KEY_SIZE, 256),
+ Authorization(TAG_AUTH_TIMEOUT, 300),
+ };
+ AuthorizationSet set(params, array_length(params));
+ AuthorizationSet set2(set);
+ EXPECT_EQ(set, set2);
+}
+
+TEST(Construction, NullProvided) {
+ keymaster_key_param_t params[] = {
+ Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+ };
+
+ AuthorizationSet set1(params, 0);
+ EXPECT_EQ(0U, set1.size());
+ EXPECT_EQ(AuthorizationSet::OK, set1.is_valid());
+
+ AuthorizationSet set2(reinterpret_cast<keymaster_key_param_t*>(NULL), array_length(params));
+ EXPECT_EQ(0U, set2.size());
+ EXPECT_EQ(AuthorizationSet::OK, set2.is_valid());
+}
+
+TEST(Lookup, NonRepeated) {
+ AuthorizationSet set(AuthorizationSetBuilder()
+ .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_AUTH_TIMEOUT, 300));
+
+ EXPECT_EQ(8U, set.size());
+
+ int pos = set.find(TAG_ALGORITHM);
+ ASSERT_NE(-1, pos);
+ EXPECT_EQ(KM_TAG_ALGORITHM, set[pos].tag);
+ EXPECT_EQ(KM_ALGORITHM_RSA, set[pos].enumerated);
+
+ pos = set.find(TAG_MAC_LENGTH);
+ EXPECT_EQ(-1, pos);
+
+ uint32_t int_val = 0;
+ EXPECT_TRUE(set.GetTagValue(TAG_USER_ID, &int_val));
+ EXPECT_EQ(7U, int_val);
+
+ keymaster_blob_t blob_val;
+ EXPECT_TRUE(set.GetTagValue(TAG_APPLICATION_ID, &blob_val));
+ EXPECT_EQ(6U, blob_val.data_length);
+ EXPECT_EQ(0, memcmp(blob_val.data, "my_app", 6));
+}
+
+TEST(Lookup, Repeated) {
+ AuthorizationSet set(AuthorizationSetBuilder()
+ .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_SECURE_ID, 47727)
+ .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD)
+ .Authorization(TAG_APPLICATION_ID, "my_app", 6)
+ .Authorization(TAG_KEY_SIZE, 256)
+ .Authorization(TAG_AUTH_TIMEOUT, 300));
+ EXPECT_EQ(9U, set.size());
+
+ int pos = set.find(TAG_PURPOSE);
+ ASSERT_FALSE(pos == -1);
+ EXPECT_EQ(KM_TAG_PURPOSE, set[pos].tag);
+ EXPECT_EQ(KM_PURPOSE_SIGN, set[pos].enumerated);
+
+ pos = set.find(TAG_PURPOSE, pos);
+ EXPECT_EQ(KM_TAG_PURPOSE, set[pos].tag);
+ EXPECT_EQ(KM_PURPOSE_VERIFY, set[pos].enumerated);
+
+ EXPECT_EQ(-1, set.find(TAG_PURPOSE, pos));
+
+ pos = set.find(TAG_USER_SECURE_ID, pos);
+ EXPECT_EQ(KM_TAG_USER_SECURE_ID, set[pos].tag);
+ EXPECT_EQ(47727U, set[pos].long_integer);
+}
+
+TEST(Lookup, Indexed) {
+ AuthorizationSet set(AuthorizationSetBuilder()
+ .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_AUTH_TIMEOUT, 300));
+ EXPECT_EQ(8U, set.size());
+
+ EXPECT_EQ(KM_TAG_PURPOSE, set[0].tag);
+ EXPECT_EQ(KM_PURPOSE_SIGN, set[0].enumerated);
+
+ // Lookup beyond end doesn't work, just returns zeros, but doens't blow up either (verify by
+ // running under valgrind).
+ EXPECT_EQ(KM_TAG_INVALID, set[10].tag);
+}
+
+TEST(Serialization, RoundTrip) {
+ AuthorizationSet set(AuthorizationSetBuilder()
+ .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_USER_SECURE_ID, 47727)
+ .Authorization(TAG_AUTH_TIMEOUT, 300)
+ .Authorization(TAG_ALL_USERS)
+ .Authorization(TAG_RSA_PUBLIC_EXPONENT, 3)
+ .Authorization(TAG_ACTIVE_DATETIME, 10));
+
+ size_t size = set.SerializedSize();
+ EXPECT_TRUE(size > 0);
+
+ UniquePtr<uint8_t[]> buf(new uint8_t[size]);
+ EXPECT_EQ(buf.get() + size, set.Serialize(buf.get(), buf.get() + size));
+ AuthorizationSet deserialized(buf.get(), size);
+
+ EXPECT_EQ(AuthorizationSet::OK, deserialized.is_valid());
+ EXPECT_EQ(set, deserialized);
+
+ int pos = deserialized.find(TAG_APPLICATION_ID);
+ ASSERT_NE(-1, pos);
+ EXPECT_EQ(KM_TAG_APPLICATION_ID, deserialized[pos].tag);
+ EXPECT_EQ(6U, deserialized[pos].blob.data_length);
+ EXPECT_EQ(0, memcmp(deserialized[pos].blob.data, "my_app", 6));
+}
+
+TEST(Deserialization, Deserialize) {
+ AuthorizationSet set(AuthorizationSetBuilder()
+ .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_AUTH_TIMEOUT, 300));
+
+ size_t size = set.SerializedSize();
+ EXPECT_TRUE(size > 0);
+
+ UniquePtr<uint8_t[]> buf(new uint8_t[size]);
+ EXPECT_EQ(buf.get() + size, set.Serialize(buf.get(), buf.get() + size));
+ AuthorizationSet deserialized;
+ const uint8_t* p = buf.get();
+ EXPECT_TRUE(deserialized.Deserialize(&p, p + size));
+ EXPECT_EQ(p, buf.get() + size);
+
+ EXPECT_EQ(AuthorizationSet::OK, deserialized.is_valid());
+
+ EXPECT_EQ(set.size(), deserialized.size());
+ for (size_t i = 0; i < set.size(); ++i) {
+ EXPECT_EQ(set[i].tag, deserialized[i].tag);
+ }
+
+ int pos = deserialized.find(TAG_APPLICATION_ID);
+ ASSERT_NE(-1, pos);
+ EXPECT_EQ(KM_TAG_APPLICATION_ID, deserialized[pos].tag);
+ EXPECT_EQ(6U, deserialized[pos].blob.data_length);
+ EXPECT_EQ(0, memcmp(deserialized[pos].blob.data, "my_app", 6));
+}
+
+TEST(Deserialization, TooShortBuffer) {
+ uint8_t buf[] = {0, 0, 0};
+ AuthorizationSet deserialized(buf, array_length(buf));
+ EXPECT_EQ(AuthorizationSet::MALFORMED_DATA, deserialized.is_valid());
+
+ const uint8_t* p = buf;
+ EXPECT_FALSE(deserialized.Deserialize(&p, p + array_length(buf)));
+ EXPECT_EQ(AuthorizationSet::MALFORMED_DATA, deserialized.is_valid());
+}
+
+TEST(Deserialization, InvalidLengthField) {
+ AuthorizationSet set(AuthorizationSetBuilder()
+ .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_AUTH_TIMEOUT, 300));
+
+ size_t size = set.SerializedSize();
+ EXPECT_TRUE(size > 0);
+
+ UniquePtr<uint8_t[]> buf(new uint8_t[size]);
+ EXPECT_EQ(buf.get() + size, set.Serialize(buf.get(), buf.get() + size));
+ *reinterpret_cast<uint32_t*>(buf.get()) = 9;
+
+ AuthorizationSet deserialized(buf.get(), size);
+ EXPECT_EQ(AuthorizationSet::MALFORMED_DATA, deserialized.is_valid());
+
+ const uint8_t* p = buf.get();
+ EXPECT_FALSE(deserialized.Deserialize(&p, p + size));
+ EXPECT_EQ(AuthorizationSet::MALFORMED_DATA, deserialized.is_valid());
+}
+
+static uint32_t read_uint32(const uint8_t* buf) {
+ uint32_t val;
+ memcpy(&val, buf, sizeof(val));
+ return val;
+}
+
+static void add_to_uint32(uint8_t* buf, int delta) {
+ uint32_t val;
+ memcpy(&val, buf, sizeof(val));
+ val += delta;
+ memcpy(buf, &val, sizeof(val));
+}
+
+TEST(Deserialization, MalformedIndirectData) {
+ AuthorizationSet set(AuthorizationSetBuilder()
+ .Authorization(TAG_APPLICATION_ID, "my_app", 6)
+ .Authorization(TAG_APPLICATION_DATA, "foo", 3));
+ size_t size = set.SerializedSize();
+
+ UniquePtr<uint8_t[]> buf(new uint8_t[size]);
+ EXPECT_EQ(buf.get() + size, set.Serialize(buf.get(), buf.get() + size));
+
+ // This sucks. This test, as written, requires intimate knowledge of the serialized layout of
+ // this particular set, which means it's brittle. But it's important to test that we handle
+ // broken serialized data and I can't think of a better way to write this.
+ //
+ // The contents of buf are:
+ //
+ // Bytes: Content:
+ // 0-3 Length of string data, which is 9.
+ // 4-9 "my_app"
+ // 10-12 "foo"
+ // 13-16 Number of elements, which is 2.
+ // 17-20 Length of elements, which is 24.
+ // 21-24 First tag, TAG_APPLICATION_ID
+ // 25-28 Length of string "my_app", 6
+ // 29-32 Offset of string "my_app", 0
+ // 33-36 Second tag, TAG_APPLICATION_DATA
+ // 37-40 Length of string "foo", 3
+ // 41-44 Offset of string "foo", 6
+
+ // Check that stuff is where we think.
+ EXPECT_EQ('m', buf[4]);
+ EXPECT_EQ('f', buf[10]);
+ // Length of "my_app"
+ EXPECT_EQ(6U, read_uint32(buf.get() + 25));
+ // Offset of "my_app"
+ EXPECT_EQ(0U, read_uint32(buf.get() + 29));
+ // Length of "foo"
+ EXPECT_EQ(3U, read_uint32(buf.get() + 37));
+ // Offset of "foo"
+ EXPECT_EQ(6U, read_uint32(buf.get() + 41));
+
+ // Check that deserialization works.
+ AuthorizationSet deserialized1(buf.get(), size);
+ EXPECT_EQ(AuthorizationSet::OK, deserialized1.is_valid());
+
+ const uint8_t* p = buf.get();
+ EXPECT_TRUE(deserialized1.Deserialize(&p, p + size));
+ EXPECT_EQ(AuthorizationSet::OK, deserialized1.is_valid());
+
+ //
+ // Now mess them up in various ways:
+ //
+
+ // Move "foo" offset so offset + length goes off the end
+ add_to_uint32(buf.get() + 41, 1);
+ AuthorizationSet deserialized2(buf.get(), size);
+ EXPECT_EQ(AuthorizationSet::MALFORMED_DATA, deserialized2.is_valid());
+ add_to_uint32(buf.get() + 41, -1);
+
+ // Shorten the "my_app" length to make a gap between the blobs.
+ add_to_uint32(buf.get() + 25, -1);
+ AuthorizationSet deserialized3(buf.get(), size);
+ EXPECT_EQ(AuthorizationSet::MALFORMED_DATA, deserialized3.is_valid());
+ add_to_uint32(buf.get() + 25, 1);
+
+ // Extend the "my_app" length to make them overlap, and decrease the "foo" length to keep the
+ // total length the same. We don't detect this but should.
+ // TODO(swillden): Detect overlaps and holes that leave total size correct.
+ add_to_uint32(buf.get() + 25, 1);
+ add_to_uint32(buf.get() + 37, -1);
+ AuthorizationSet deserialized4(buf.get(), size);
+ EXPECT_EQ(AuthorizationSet::OK, deserialized4.is_valid());
+}
+
+TEST(Growable, SuccessfulRoundTrip) {
+ AuthorizationSet growable;
+ EXPECT_TRUE(growable.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)));
+ EXPECT_EQ(1U, growable.size());
+
+ EXPECT_TRUE(growable.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)));
+ EXPECT_EQ(2U, growable.size());
+
+ EXPECT_TRUE(growable.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)));
+ EXPECT_EQ(3U, growable.size());
+
+ EXPECT_TRUE(growable.push_back(Authorization(TAG_APPLICATION_ID, "data", 4)));
+ EXPECT_EQ(4U, growable.size());
+
+ EXPECT_TRUE(growable.push_back(Authorization(TAG_APPLICATION_DATA, "some more data", 14)));
+ EXPECT_EQ(5U, growable.size());
+
+ size_t serialize_size = growable.SerializedSize();
+ UniquePtr<uint8_t[]> serialized(new uint8_t[serialize_size]);
+ EXPECT_EQ(serialized.get() + serialize_size,
+ growable.Serialize(serialized.get(), serialized.get() + serialize_size));
+
+ AuthorizationSet deserialized(serialized.get(), serialize_size);
+ EXPECT_EQ(growable, deserialized);
+}
+
+TEST(Growable, InsufficientElemBuf) {
+ AuthorizationSet growable;
+ EXPECT_EQ(AuthorizationSet::OK, growable.is_valid());
+
+ // First insertion fits.
+ EXPECT_TRUE(growable.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)));
+ EXPECT_EQ(1U, growable.size());
+ EXPECT_EQ(AuthorizationSet::OK, growable.is_valid());
+
+ // Second does too.
+ EXPECT_TRUE(growable.push_back(Authorization(TAG_RSA_PUBLIC_EXPONENT, 3)));
+ EXPECT_EQ(2U, growable.size());
+}
+
+TEST(Growable, InsufficientIndirectBuf) {
+ AuthorizationSet growable;
+ EXPECT_EQ(AuthorizationSet::OK, growable.is_valid());
+
+ EXPECT_TRUE(growable.push_back(Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)));
+ EXPECT_EQ(1U, growable.size());
+ EXPECT_EQ(AuthorizationSet::OK, growable.is_valid());
+
+ EXPECT_TRUE(growable.push_back(Authorization(TAG_APPLICATION_ID, "1234567890", 10)));
+ EXPECT_EQ(2U, growable.size());
+ EXPECT_EQ(AuthorizationSet::OK, growable.is_valid());
+
+ EXPECT_TRUE(growable.push_back(Authorization(TAG_APPLICATION_DATA, "1", 1)));
+ EXPECT_EQ(3U, growable.size());
+ EXPECT_EQ(AuthorizationSet::OK, growable.is_valid());
+
+ // Can still add another entry without indirect data. Now it's full.
+ EXPECT_TRUE(growable.push_back(Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)));
+ EXPECT_EQ(4U, growable.size());
+ EXPECT_EQ(AuthorizationSet::OK, growable.is_valid());
+}
+
+TEST(Growable, PushBackSets) {
+ AuthorizationSetBuilder builder;
+ builder.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_AUTH_TIMEOUT, 300);
+
+ AuthorizationSet set1(builder.build());
+ AuthorizationSet set2(builder.build());
+
+ AuthorizationSet combined;
+ EXPECT_TRUE(combined.push_back(set1));
+ EXPECT_TRUE(combined.push_back(set2));
+ EXPECT_EQ(set1.size() + set2.size(), combined.size());
+ EXPECT_EQ(12U, combined.indirect_size());
+}
+
+TEST(GetValue, GetInt) {
+ AuthorizationSet set(AuthorizationSetBuilder()
+ .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_AUTH_TIMEOUT, 300));
+
+ uint32_t val;
+ EXPECT_TRUE(set.GetTagValue(TAG_USER_ID, &val));
+ EXPECT_EQ(7U, val);
+
+ // Find one that isn't there
+ EXPECT_FALSE(set.GetTagValue(TAG_KEY_SIZE, &val));
+}
+
+TEST(GetValue, GetLong) {
+ AuthorizationSet set1(AuthorizationSetBuilder()
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+ .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+ .Authorization(TAG_RSA_PUBLIC_EXPONENT, 3));
+
+ AuthorizationSet set2(AuthorizationSetBuilder()
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+ .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA));
+
+ uint64_t val;
+ EXPECT_TRUE(set1.GetTagValue(TAG_RSA_PUBLIC_EXPONENT, &val));
+ EXPECT_EQ(3U, val);
+
+ // Find one that isn't there
+ EXPECT_FALSE(set2.GetTagValue(TAG_RSA_PUBLIC_EXPONENT, &val));
+}
+
+TEST(GetValue, GetLongRep) {
+ AuthorizationSet set1(AuthorizationSetBuilder()
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+ .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+ .Authorization(TAG_USER_SECURE_ID, 8338)
+ .Authorization(TAG_USER_SECURE_ID, 4334)
+ .Authorization(TAG_RSA_PUBLIC_EXPONENT, 3));
+
+ AuthorizationSet set2(AuthorizationSetBuilder()
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+ .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA));
+
+ uint64_t val;
+ EXPECT_TRUE(set1.GetTagValue(TAG_USER_SECURE_ID, 0, &val));
+ EXPECT_EQ(8338U, val);
+ EXPECT_TRUE(set1.GetTagValue(TAG_USER_SECURE_ID, 1, &val));
+ EXPECT_EQ(4334U, val);
+
+ // Find one that isn't there
+ EXPECT_FALSE(set2.GetTagValue(TAG_USER_SECURE_ID, &val));
+}
+
+TEST(GetValue, GetEnum) {
+ AuthorizationSet set(AuthorizationSetBuilder()
+ .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_AUTH_TIMEOUT, 300));
+
+ keymaster_algorithm_t val;
+ EXPECT_TRUE(set.GetTagValue(TAG_ALGORITHM, &val));
+ EXPECT_EQ(KM_ALGORITHM_RSA, val);
+
+ // Find one that isn't there
+ keymaster_padding_t val2;
+ EXPECT_FALSE(set.GetTagValue(TAG_PADDING, &val2));
+}
+
+TEST(GetValue, GetEnumRep) {
+ AuthorizationSet set(AuthorizationSetBuilder()
+ .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_AUTH_TIMEOUT, 300));
+
+ keymaster_purpose_t val;
+ EXPECT_TRUE(set.GetTagValue(TAG_PURPOSE, 0, &val));
+ EXPECT_EQ(KM_PURPOSE_SIGN, val);
+ EXPECT_TRUE(set.GetTagValue(TAG_PURPOSE, 1, &val));
+ EXPECT_EQ(KM_PURPOSE_VERIFY, val);
+
+ // Find one that isn't there
+ EXPECT_FALSE(set.GetTagValue(TAG_PURPOSE, 2, &val));
+}
+
+TEST(GetValue, GetDate) {
+ AuthorizationSet set(AuthorizationSetBuilder()
+ .Authorization(TAG_ACTIVE_DATETIME, 10)
+ .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_AUTH_TIMEOUT, 300));
+
+ uint64_t val;
+ EXPECT_TRUE(set.GetTagValue(TAG_ACTIVE_DATETIME, &val));
+ EXPECT_EQ(10U, val);
+
+ // Find one that isn't there
+ EXPECT_FALSE(set.GetTagValue(TAG_USAGE_EXPIRE_DATETIME, &val));
+}
+
+TEST(GetValue, GetBlob) {
+ AuthorizationSet set(AuthorizationSetBuilder()
+ .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_AUTH_TIMEOUT, 300));
+
+ keymaster_blob_t val;
+ EXPECT_TRUE(set.GetTagValue(TAG_APPLICATION_ID, &val));
+ EXPECT_EQ(6U, val.data_length);
+ EXPECT_EQ(0, memcmp(val.data, "my_app", 6));
+
+ // Find one that isn't there
+ EXPECT_FALSE(set.GetTagValue(TAG_APPLICATION_DATA, &val));
+}
+
+TEST(Deduplication, NoDuplicates) {
+ AuthorizationSet set(AuthorizationSetBuilder()
+ .Authorization(TAG_ACTIVE_DATETIME, 10)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+ .Authorization(TAG_USER_ID, 7)
+ .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD));
+ AuthorizationSet copy(set);
+
+ EXPECT_EQ(copy, set);
+ set.Deduplicate();
+ EXPECT_EQ(copy.size(), set.size());
+
+ // Sets no longer compare equal, because of ordering (ugh, maybe it should be
+ // AuthorizationList, not AuthorizationSet).
+ EXPECT_NE(copy, set);
+}
+
+TEST(Deduplication, NoDuplicatesHasInvalid) {
+ AuthorizationSet set(AuthorizationSetBuilder()
+ .Authorization(TAG_ACTIVE_DATETIME, 10)
+ .Authorization(TAG_INVALID)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+ .Authorization(TAG_USER_ID, 7)
+ .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD));
+ AuthorizationSet copy(set);
+
+ EXPECT_EQ(copy, set);
+ set.Deduplicate();
+
+ // Deduplicate should have removed the invalid.
+ EXPECT_EQ(copy.size() - 1, set.size());
+ EXPECT_NE(copy, set);
+}
+
+TEST(Deduplication, DuplicateEnum) {
+ AuthorizationSet set(AuthorizationSetBuilder()
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+ .Authorization(TAG_ACTIVE_DATETIME, 10)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+ .Authorization(TAG_USER_ID, 7)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+ .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD));
+ AuthorizationSet copy(set);
+
+ EXPECT_EQ(copy, set);
+ set.Deduplicate();
+ EXPECT_EQ(copy.size() - 2, set.size());
+ EXPECT_NE(copy, set);
+}
+
+TEST(Deduplication, DuplicateBlob) {
+ AuthorizationSet set(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_USER_ID, 7)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+ .Authorization(TAG_APPLICATION_DATA, "data", 4)
+ .Authorization(TAG_APPLICATION_DATA, "foo", 3)
+ .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD));
+ AuthorizationSet copy(set);
+
+ EXPECT_EQ(copy, set);
+ set.Deduplicate();
+ EXPECT_EQ(copy.size() - 3, set.size());
+ EXPECT_NE(copy, set);
+
+ // The real test here is that valgrind reports no leak.
+}
+
+} // namespace test
+} // namespace keymaster
diff --git a/keymaster/ec_key.cpp b/keymaster/ec_key.cpp
new file mode 100644
index 0000000..64ffc7a
--- /dev/null
+++ b/keymaster/ec_key.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2014 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 "ec_key.h"
+
+#if defined(OPENSSL_IS_BORINGSSL)
+typedef size_t openssl_size_t;
+#else
+typedef int openssl_size_t;
+#endif
+
+namespace keymaster {
+
+bool EcKey::EvpToInternal(const EVP_PKEY* pkey) {
+ ec_key_.reset(EVP_PKEY_get1_EC_KEY(const_cast<EVP_PKEY*>(pkey)));
+ return ec_key_.get() != NULL;
+}
+
+bool EcKey::InternalToEvp(EVP_PKEY* pkey) const {
+ return EVP_PKEY_set1_EC_KEY(pkey, ec_key_.get()) == 1;
+}
+
+} // namespace keymaster
diff --git a/keymaster/ec_key.h b/keymaster/ec_key.h
new file mode 100644
index 0000000..8230d23
--- /dev/null
+++ b/keymaster/ec_key.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2014 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_KEY_H_
+#define SYSTEM_KEYMASTER_EC_KEY_H_
+
+#include <openssl/ec.h>
+
+#include "asymmetric_key.h"
+#include "openssl_utils.h"
+
+namespace keymaster {
+
+class EcdsaOperationFactory;
+
+class EcKey : public AsymmetricKey {
+ public:
+ EcKey(const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+ keymaster_error_t* error)
+ : AsymmetricKey(hw_enforced, sw_enforced, error) {}
+
+ bool InternalToEvp(EVP_PKEY* pkey) const override;
+ bool EvpToInternal(const EVP_PKEY* pkey) override;
+
+ EC_KEY* key() const { return ec_key_.get(); }
+
+ protected:
+ EcKey(EC_KEY* ec_key, const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+ keymaster_error_t* error)
+ : AsymmetricKey(hw_enforced, sw_enforced, error), ec_key_(ec_key) {}
+
+ private:
+ UniquePtr<EC_KEY, EC_KEY_Delete> ec_key_;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_EC_KEY_H_
diff --git a/keymaster/ec_key_factory.cpp b/keymaster/ec_key_factory.cpp
new file mode 100644
index 0000000..14c8327
--- /dev/null
+++ b/keymaster/ec_key_factory.cpp
@@ -0,0 +1,182 @@
+/*
+ * 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/ec_key_factory.h>
+
+#include <openssl/evp.h>
+
+#include <keymaster/keymaster_context.h>
+
+#include "ec_key.h"
+#include "ecdsa_operation.h"
+#include "openssl_err.h"
+
+namespace keymaster {
+
+static EcdsaSignOperationFactory sign_factory;
+static EcdsaVerifyOperationFactory verify_factory;
+
+OperationFactory* EcKeyFactory::GetOperationFactory(keymaster_purpose_t purpose) const {
+ switch (purpose) {
+ case KM_PURPOSE_SIGN:
+ return &sign_factory;
+ case KM_PURPOSE_VERIFY:
+ return &verify_factory;
+ default:
+ return nullptr;
+ }
+}
+
+keymaster_error_t EcKeyFactory::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;
+
+ AuthorizationSet authorizations(key_description);
+
+ uint32_t key_size;
+ if (!authorizations.GetTagValue(TAG_KEY_SIZE, &key_size)) {
+ LOG_E("%s", "No key size specified for EC key generation");
+ return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+ }
+
+ 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() == NULL || pkey.get() == NULL)
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ UniquePtr<EC_GROUP, EC_GROUP_Delete> group(choose_group(key_size));
+ if (group.get() == NULL) {
+ LOG_E("Unable to get EC group for key of size %d", key_size);
+ return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+ }
+
+#if !defined(OPENSSL_IS_BORINGSSL)
+ EC_GROUP_set_point_conversion_form(group.get(), POINT_CONVERSION_UNCOMPRESSED);
+ EC_GROUP_set_asn1_flag(group.get(), OPENSSL_EC_NAMED_CURVE);
+#endif
+
+ if (EC_KEY_set_group(ec_key.get(), group.get()) != 1 ||
+ EC_KEY_generate_key(ec_key.get()) != 1 || EC_KEY_check_key(ec_key.get()) < 0) {
+ return TranslateLastOpenSslError();
+ }
+
+ if (EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get()) != 1)
+ return TranslateLastOpenSslError();
+
+ KeymasterKeyBlob key_material;
+ keymaster_error_t error = EvpKeyToKeyMaterial(pkey.get(), &key_material);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ return context_->CreateKeyBlob(authorizations, KM_ORIGIN_GENERATED, key_material, key_blob,
+ hw_enforced, sw_enforced);
+}
+
+keymaster_error_t EcKeyFactory::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;
+ 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;
+
+ return context_->CreateKeyBlob(authorizations, KM_ORIGIN_IMPORTED, input_key_material,
+ output_key_blob, hw_enforced, sw_enforced);
+}
+
+keymaster_error_t EcKeyFactory::UpdateImportKeyDescription(const AuthorizationSet& key_description,
+ keymaster_key_format_t key_format,
+ 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;
+
+ 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;
+
+ UniquePtr<EC_KEY, EC_KEY_Delete> ec_key(EVP_PKEY_get1_EC_KEY(pkey.get()));
+ 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;
+
+ *key_size_bits = extracted_key_size_bits;
+ if (!updated_description->GetTagValue(TAG_KEY_SIZE, key_size_bits))
+ updated_description->push_back(TAG_KEY_SIZE, extracted_key_size_bits);
+ if (*key_size_bits != extracted_key_size_bits)
+ return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
+
+ keymaster_algorithm_t algorithm = KM_ALGORITHM_EC;
+ if (!updated_description->GetTagValue(TAG_ALGORITHM, &algorithm))
+ updated_description->push_back(TAG_ALGORITHM, KM_ALGORITHM_EC);
+ if (algorithm != KM_ALGORITHM_EC)
+ return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
+
+ return KM_ERROR_OK;
+}
+
+/* static */
+EC_GROUP* EcKeyFactory::choose_group(size_t key_size_bits) {
+ switch (key_size_bits) {
+ case 224:
+ return EC_GROUP_new_by_curve_name(NID_secp224r1);
+ break;
+ case 256:
+ return EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
+ break;
+ case 384:
+ return EC_GROUP_new_by_curve_name(NID_secp384r1);
+ break;
+ case 521:
+ return EC_GROUP_new_by_curve_name(NID_secp521r1);
+ break;
+ default:
+ return NULL;
+ break;
+ }
+}
+
+keymaster_error_t EcKeyFactory::CreateEmptyKey(const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ UniquePtr<AsymmetricKey>* key) const {
+ keymaster_error_t error;
+ key->reset(new (std::nothrow) EcKey(hw_enforced, sw_enforced, &error));
+ if (!key->get())
+ error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return error;
+}
+
+} // namespace keymaster
diff --git a/keymaster/ec_keymaster0_key.cpp b/keymaster/ec_keymaster0_key.cpp
new file mode 100644
index 0000000..705ee73
--- /dev/null
+++ b/keymaster/ec_keymaster0_key.cpp
@@ -0,0 +1,122 @@
+/*
+ * 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 "ec_keymaster0_key.h"
+
+#include <memory>
+
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/logger.h>
+#include <keymaster/soft_keymaster_context.h>
+
+#include "keymaster0_engine.h"
+#include "openssl_utils.h"
+
+using std::unique_ptr;
+
+namespace keymaster {
+
+EcdsaKeymaster0KeyFactory::EcdsaKeymaster0KeyFactory(const SoftKeymasterContext* context,
+ const Keymaster0Engine* engine)
+ : EcKeyFactory(context), 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);
+
+ uint32_t key_size;
+ if (!key_description.GetTagValue(TAG_KEY_SIZE, &key_size)) {
+ LOG_E("%s", "No key size specified for EC key generation");
+ return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+ }
+
+ 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
+ // context_->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 context_->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
+ // context_->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 context_->CreateKeyBlob(authorizations, KM_ORIGIN_UNKNOWN, imported_hw_key,
+ output_key_blob, hw_enforced, sw_enforced);
+}
+
+keymaster_error_t EcdsaKeymaster0KeyFactory::LoadKey(const KeymasterKeyBlob& key_material,
+ const AuthorizationSet& additional_params,
+ const AuthorizationSet& hw_enforced,
+ const 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(key_material, additional_params, hw_enforced, sw_enforced, key);
+
+ unique_ptr<EC_KEY, EC_KEY_Delete> ec_key(engine_->BlobToEcKey(key_material));
+ if (!ec_key)
+ return KM_ERROR_UNKNOWN_ERROR;
+
+ keymaster_error_t error;
+ key->reset(new (std::nothrow)
+ EcKeymaster0Key(ec_key.release(), hw_enforced, sw_enforced, &error));
+ if (error != KM_ERROR_OK)
+ return error;
+
+ return KM_ERROR_OK;
+}
+
+} // namespace keymaster
diff --git a/keymaster/ec_keymaster0_key.h b/keymaster/ec_keymaster0_key.h
new file mode 100644
index 0000000..0d0af3d
--- /dev/null
+++ b/keymaster/ec_keymaster0_key.h
@@ -0,0 +1,70 @@
+/*
+ * 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/ec_key_factory.h>
+
+#include "ec_key.h"
+
+namespace keymaster {
+
+class Keymaster0Engine;
+class SoftKeymasterContext;
+
+/**
+ * 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 SoftKeymasterContext* context, 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(const KeymasterKeyBlob& key_material,
+ const AuthorizationSet& additional_params,
+ const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ UniquePtr<Key>* key) const override;
+
+ private:
+ const Keymaster0Engine* engine_;
+};
+
+class EcKeymaster0Key : public EcKey {
+ public:
+ EcKeymaster0Key(EC_KEY* ec_key, const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced, keymaster_error_t* error)
+ : EcKey(ec_key, hw_enforced, sw_enforced, error) {}
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_EC_KEYMASTER0_KEY_H_
diff --git a/keymaster/ec_keymaster1_key.cpp b/keymaster/ec_keymaster1_key.cpp
new file mode 100644
index 0000000..5cc2539
--- /dev/null
+++ b/keymaster/ec_keymaster1_key.cpp
@@ -0,0 +1,120 @@
+/*
+ * 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 "ec_keymaster1_key.h"
+
+#include <memory>
+
+#include <keymaster/logger.h>
+
+#include "ecdsa_keymaster1_operation.h"
+#include "ecdsa_operation.h"
+
+using std::unique_ptr;
+
+namespace keymaster {
+
+EcdsaKeymaster1KeyFactory::EcdsaKeymaster1KeyFactory(const SoftKeymasterContext* context,
+ const Keymaster1Engine* engine)
+ : EcKeyFactory(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) {}
+
+static bool is_supported(uint32_t digest) {
+ return digest == KM_DIGEST_NONE || digest == KM_DIGEST_SHA_2_256;
+}
+
+static void UpdateToWorkAroundUnsupportedDigests(const AuthorizationSet& key_description,
+ AuthorizationSet* new_description) {
+ bool have_unsupported_digests = false;
+ bool have_digest_none = false;
+ for (const keymaster_key_param_t& entry : key_description) {
+ new_description->push_back(entry);
+
+ if (entry.tag == TAG_DIGEST) {
+ if (entry.enumerated == KM_DIGEST_NONE) {
+ have_digest_none = true;
+ } else if (!is_supported(entry.enumerated)) {
+ LOG_D("Found request for unsupported digest %u", entry.enumerated);
+ have_unsupported_digests = true;
+ }
+ }
+ }
+
+ if (have_unsupported_digests && !have_digest_none) {
+ LOG_I("Adding KM_DIGEST_NONE to key authorization, to enable software digesting", 0);
+ new_description->push_back(TAG_DIGEST, KM_DIGEST_NONE);
+ }
+}
+
+keymaster_error_t EcdsaKeymaster1KeyFactory::GenerateKey(const AuthorizationSet& key_description,
+ KeymasterKeyBlob* key_blob,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) 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 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 {
+ AuthorizationSet key_params_copy;
+ UpdateToWorkAroundUnsupportedDigests(key_description, &key_params_copy);
+ return engine_->ImportKey(key_params_copy, input_key_material_format, input_key_material,
+ output_key_blob, hw_enforced, sw_enforced);
+}
+
+keymaster_error_t EcdsaKeymaster1KeyFactory::LoadKey(const KeymasterKeyBlob& key_material,
+ const AuthorizationSet& additional_params,
+ const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ UniquePtr<Key>* key) const {
+ 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;
+
+ key->reset(new (std::nothrow)
+ EcdsaKeymaster1Key(ecdsa.release(), hw_enforced, sw_enforced, &error));
+ if (!key->get())
+ error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ if (error != KM_ERROR_OK)
+ return error;
+
+ return KM_ERROR_OK;
+}
+
+OperationFactory*
+EcdsaKeymaster1KeyFactory::GetOperationFactory(keymaster_purpose_t purpose) const {
+ switch (purpose) {
+ case KM_PURPOSE_SIGN:
+ return sign_factory_.get();
+ case KM_PURPOSE_VERIFY:
+ return verify_factory_.get();
+ default:
+ return nullptr;
+ }
+}
+
+} // namespace keymaster
diff --git a/keymaster/ec_keymaster1_key.h b/keymaster/ec_keymaster1_key.h
new file mode 100644
index 0000000..2702b35
--- /dev/null
+++ b/keymaster/ec_keymaster1_key.h
@@ -0,0 +1,79 @@
+/*
+ * 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_KEYMASTER1_KEY_H_
+#define SYSTEM_KEYMASTER_EC_KEYMASTER1_KEY_H_
+
+#include <openssl/ecdsa.h>
+
+#include <hardware/keymaster1.h>
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/logger.h>
+#include <keymaster/ec_key_factory.h>
+#include <keymaster/soft_keymaster_context.h>
+
+#include "ec_key.h"
+#include "keymaster1_engine.h"
+
+namespace keymaster {
+
+class SoftKeymasterContext;
+
+/**
+ * EcdsaKeymaster1KeyFactory is a KeyFactory that creates and loads keys which are actually backed
+ * by a hardware keymaster1 module, but which does not support all keymaster1 digests. During
+ * generation or import any unsupported digests in the key description are silently replaced with
+ * KM_DIGEST_NONE.
+ */
+class EcdsaKeymaster1KeyFactory : public EcKeyFactory {
+ public:
+ EcdsaKeymaster1KeyFactory(const SoftKeymasterContext* context, const Keymaster1Engine* 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(const KeymasterKeyBlob& key_material,
+ const AuthorizationSet& additional_params,
+ const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ UniquePtr<Key>* key) const override;
+
+ OperationFactory* GetOperationFactory(keymaster_purpose_t purpose) const override;
+
+ private:
+ const Keymaster1Engine* engine_;
+
+ std::unique_ptr<OperationFactory> sign_factory_;
+ std::unique_ptr<OperationFactory> verify_factory_;
+};
+
+class EcdsaKeymaster1Key : public EcKey {
+ public:
+ EcdsaKeymaster1Key(EC_KEY* ecdsa_key, const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced, keymaster_error_t* error)
+ : EcKey(ecdsa_key, hw_enforced, sw_enforced, error) {}
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_ECDSA_KEYMASTER1_KEY_H_
diff --git a/keymaster/ec_privkey_pk8.der b/keymaster/ec_privkey_pk8.der
new file mode 100644
index 0000000..a4af673
--- /dev/null
+++ b/keymaster/ec_privkey_pk8.der
Binary files differ
diff --git a/keymaster/ecdsa_keymaster1_operation.cpp b/keymaster/ecdsa_keymaster1_operation.cpp
new file mode 100644
index 0000000..7e1a4f5
--- /dev/null
+++ b/keymaster/ecdsa_keymaster1_operation.cpp
@@ -0,0 +1,139 @@
+/*
+ * 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 "ecdsa_keymaster1_operation.h"
+
+#include <memory>
+
+#include <keymaster/android_keymaster_utils.h>
+
+#include "openssl_err.h"
+#include "openssl_utils.h"
+#include "ec_keymaster1_key.h"
+
+using std::unique_ptr;
+
+namespace keymaster {
+
+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;
+
+ // 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
+ // pass
+ // to the hardware module. The regular Ecdsa*Operation classes will do software digesting and
+ // padding where we've told the HW not to.
+ //
+ // The reason we don't change KM_PAD_ECDSA_PKCS1_1_5_SIGN or KM_PAD_ECDSA_PKCS1_1_5_ENCRYPT to
+ // KM_PAD_NONE is because the hardware can to those padding modes, since they don't involve
+ // digesting.
+ //
+ // We also cache in the key the padding value that we expect to be passed to the engine crypto
+ // operation. This just allows us to double-check that the correct padding value is reaching
+ // that layer.
+ AuthorizationSet begin_params(input_params);
+ int pos = begin_params.find(TAG_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,
+ &begin_params, nullptr /* out_params */, &operation_handle_);
+}
+
+keymaster_error_t
+EcdsaKeymaster1WrappedOperation::PrepareFinish(EVP_PKEY* ecdsa_key,
+ const AuthorizationSet& input_params) {
+ Keymaster1Engine::KeyData* key_data = engine_->GetData(ecdsa_key);
+ if (!key_data) {
+ LOG_E("Could not get extended key data... not a Keymaster1Engine key?", 0);
+ return KM_ERROR_UNKNOWN_ERROR;
+ }
+ key_data->op_handle = operation_handle_;
+ key_data->finish_params.Reinitialize(input_params);
+
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t EcdsaKeymaster1WrappedOperation::Abort() {
+ return engine_->device()->abort(engine_->device(), operation_handle_);
+}
+
+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;
+ return key_data->error;
+}
+
+static EVP_PKEY* GetEvpKey(const EcdsaKeymaster1Key& key, keymaster_error_t* error) {
+ if (!key.key()) {
+ *error = KM_ERROR_UNKNOWN_ERROR;
+ return nullptr;
+ }
+
+ UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new());
+ if (!key.InternalToEvp(pkey.get())) {
+ *error = KM_ERROR_UNKNOWN_ERROR;
+ return nullptr;
+ }
+ return pkey.release();
+}
+
+Operation* EcdsaKeymaster1OperationFactory::CreateOperation(const Key& key,
+ const AuthorizationSet& begin_params,
+ keymaster_error_t* error) {
+ keymaster_digest_t digest;
+ if (!GetAndValidateDigest(begin_params, key, &digest, error))
+ return nullptr;
+
+ const EcdsaKeymaster1Key& ecdsa_km1_key(static_cast<const EcdsaKeymaster1Key&>(key));
+ unique_ptr<EVP_PKEY, EVP_PKEY_Delete> ecdsa(GetEvpKey(ecdsa_km1_key, error));
+ if (!ecdsa)
+ return nullptr;
+
+ switch (purpose_) {
+ case KM_PURPOSE_SIGN:
+ return new EcdsaKeymaster1Operation<EcdsaSignOperation>(digest, ecdsa.release(), engine_);
+ default:
+ LOG_E(
+ "Bug: Pubkey operation requested. Those should be handled by normal ECDSA operations.",
+ 0);
+ *error = KM_ERROR_UNSUPPORTED_PURPOSE;
+ return nullptr;
+ }
+}
+
+static const keymaster_digest_t supported_digests[] = {
+ KM_DIGEST_NONE, KM_DIGEST_MD5, KM_DIGEST_SHA1, KM_DIGEST_SHA_2_224,
+ KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512};
+
+const keymaster_digest_t*
+EcdsaKeymaster1OperationFactory::SupportedDigests(size_t* digest_count) const {
+ *digest_count = array_length(supported_digests);
+ return supported_digests;
+}
+
+const keymaster_padding_t*
+EcdsaKeymaster1OperationFactory::SupportedPaddingModes(size_t* padding_mode_count) const {
+ *padding_mode_count = 0;
+ return nullptr;
+}
+
+} // namespace keymaster
diff --git a/keymaster/ecdsa_keymaster1_operation.h b/keymaster/ecdsa_keymaster1_operation.h
new file mode 100644
index 0000000..6045686
--- /dev/null
+++ b/keymaster/ecdsa_keymaster1_operation.h
@@ -0,0 +1,120 @@
+/*
+ * 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_ECDSA_KEYMASTER1_OPERATION_H_
+#define SYSTEM_KEYMASTER_ECDSA_KEYMASTER1_OPERATION_H_
+
+#include <openssl/evp.h>
+
+#include <hardware/keymaster1.h>
+#include <keymaster/android_keymaster_utils.h>
+
+#include "ecdsa_operation.h"
+#include "keymaster1_engine.h"
+
+namespace keymaster {
+
+class EcdsaKeymaster1WrappedOperation {
+ public:
+ EcdsaKeymaster1WrappedOperation(keymaster_purpose_t purpose, const Keymaster1Engine* engine)
+ : purpose_(purpose), operation_handle_(0), engine_(engine) {}
+ ~EcdsaKeymaster1WrappedOperation() {
+ if (operation_handle_)
+ Abort();
+ }
+
+ keymaster_error_t Begin(EVP_PKEY* ecdsa_key, const AuthorizationSet& input_params);
+ keymaster_error_t PrepareFinish(EVP_PKEY* ecdsa_key, const AuthorizationSet& input_params);
+ void Finish() { operation_handle_ = 0; }
+ keymaster_error_t Abort();
+
+ keymaster_error_t GetError(EVP_PKEY* ecdsa_key);
+
+ protected:
+ keymaster_purpose_t purpose_;
+ keymaster_operation_handle_t operation_handle_;
+ const Keymaster1Engine* engine_;
+};
+
+template <typename BaseOperation> class EcdsaKeymaster1Operation : public BaseOperation {
+ typedef BaseOperation super;
+
+ public:
+ EcdsaKeymaster1Operation(keymaster_digest_t digest, EVP_PKEY* key,
+ const Keymaster1Engine* engine)
+ : BaseOperation(digest, key), wrapped_operation_(super::purpose(), engine) {
+ // Shouldn't be instantiated for public key operations.
+ assert(super::purpose() != KM_PURPOSE_VERIFY);
+ assert(super::purpose() != KM_PURPOSE_ENCRYPT);
+ }
+
+ 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;
+ return super::Begin(input_params, output_params);
+ }
+
+ keymaster_error_t Finish(const AuthorizationSet& input_params, const Buffer& input,
+ 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;
+ 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_);
+ if (error == KM_ERROR_OK)
+ wrapped_operation_.Finish();
+ return error;
+ }
+
+ keymaster_error_t Abort() override {
+ keymaster_error_t error = wrapped_operation_.Abort();
+ if (error != KM_ERROR_OK)
+ return error;
+ return super::Abort();
+ }
+
+ private:
+ EcdsaKeymaster1WrappedOperation wrapped_operation_;
+};
+
+/**
+ * Factory that produces EcdsaKeymaster1Operations. This is instantiated and
+ * provided by EcdsaKeymaster1KeyFactory.
+ */
+class EcdsaKeymaster1OperationFactory : public OperationFactory {
+ public:
+ EcdsaKeymaster1OperationFactory(keymaster_purpose_t purpose, const Keymaster1Engine* engine)
+ : purpose_(purpose), engine_(engine) {}
+ KeyType registry_key() const override { return KeyType(KM_ALGORITHM_EC, purpose_); }
+
+ Operation* CreateOperation(const Key& key, const AuthorizationSet& begin_params,
+ keymaster_error_t* error) override;
+
+ const keymaster_digest_t* SupportedDigests(size_t* digest_count) const override;
+ const keymaster_padding_t* SupportedPaddingModes(size_t* padding_mode_count) const override;
+
+ private:
+ keymaster_purpose_t purpose_;
+ const Keymaster1Engine* engine_;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_ECDSA_KEYMASTER1_OPERATION_H_
diff --git a/keymaster/ecdsa_operation.cpp b/keymaster/ecdsa_operation.cpp
new file mode 100644
index 0000000..405dcb5
--- /dev/null
+++ b/keymaster/ecdsa_operation.cpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2014 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 "ecdsa_operation.h"
+
+#include <openssl/ecdsa.h>
+
+#include "ec_key.h"
+#include "openssl_err.h"
+#include "openssl_utils.h"
+
+namespace keymaster {
+
+static const keymaster_digest_t supported_digests[] = {KM_DIGEST_NONE, KM_DIGEST_SHA1,
+ KM_DIGEST_SHA_2_224, KM_DIGEST_SHA_2_256,
+ KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512};
+
+Operation* EcdsaOperationFactory::CreateOperation(const Key& key,
+ const AuthorizationSet& begin_params,
+ keymaster_error_t* error) {
+ const EcKey* ecdsa_key = static_cast<const EcKey*>(&key);
+ if (!ecdsa_key) {
+ *error = KM_ERROR_UNKNOWN_ERROR;
+ return nullptr;
+ }
+
+ UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new());
+ if (!ecdsa_key->InternalToEvp(pkey.get())) {
+ *error = KM_ERROR_UNKNOWN_ERROR;
+ return nullptr;
+ }
+
+ keymaster_digest_t digest;
+ if (!GetAndValidateDigest(begin_params, key, &digest, error))
+ return nullptr;
+
+ *error = KM_ERROR_OK;
+ Operation* op = InstantiateOperation(digest, pkey.release());
+ if (!op)
+ *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return op;
+}
+
+const keymaster_digest_t* EcdsaOperationFactory::SupportedDigests(size_t* digest_count) const {
+ *digest_count = array_length(supported_digests);
+ return supported_digests;
+}
+
+EcdsaOperation::~EcdsaOperation() {
+ if (ecdsa_key_ != NULL)
+ EVP_PKEY_free(ecdsa_key_);
+ EVP_MD_CTX_cleanup(&digest_ctx_);
+}
+
+keymaster_error_t EcdsaOperation::InitDigest() {
+ switch (digest_) {
+ case KM_DIGEST_NONE:
+ return KM_ERROR_OK;
+ case KM_DIGEST_MD5:
+ return KM_ERROR_UNSUPPORTED_DIGEST;
+ 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:
+ return KM_ERROR_UNSUPPORTED_DIGEST;
+ }
+}
+
+inline size_t min(size_t a, size_t b) {
+ return (a < b) ? a : b;
+}
+
+keymaster_error_t EcdsaOperation::StoreData(const Buffer& input, size_t* input_consumed) {
+ if (!data_.reserve((EVP_PKEY_bits(ecdsa_key_) + 7) / 8))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ if (!data_.write(input.peek_read(), min(data_.available_write(), input.available_read())))
+ return KM_ERROR_UNKNOWN_ERROR;
+
+ *input_consumed = input.available_read();
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t EcdsaSignOperation::Begin(const AuthorizationSet& /* input_params */,
+ AuthorizationSet* /* output_params */) {
+ keymaster_error_t error = InitDigest();
+ if (error != KM_ERROR_OK)
+ return error;
+
+ 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 */,
+ ecdsa_key_) != 1)
+ return TranslateLastOpenSslError();
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t EcdsaSignOperation::Update(const AuthorizationSet& /* additional_params */,
+ const Buffer& input,
+ AuthorizationSet* /* output_params */,
+ Buffer* /* output */, size_t* 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();
+ *input_consumed = input.available_read();
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t EcdsaSignOperation::Finish(const AuthorizationSet& additional_params,
+ const Buffer& input, const Buffer& /* signature */,
+ AuthorizationSet* /* output_params */,
+ Buffer* output) {
+ if (!output)
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+ keymaster_error_t error = UpdateForFinish(additional_params, input);
+ 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();
+
+ output->Reinitialize(ECDSA_size(ecdsa.get()));
+ unsigned int siglen_tmp;
+ if (!ECDSA_sign(0 /* type -- ignored */, data_.peek_read(), data_.available_read(),
+ output->peek_write(), &siglen_tmp, ecdsa.get()))
+ return TranslateLastOpenSslError();
+ siglen = siglen_tmp;
+ } else {
+ if (EVP_DigestSignFinal(&digest_ctx_, nullptr /* signature */, &siglen) != 1)
+ return TranslateLastOpenSslError();
+ 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;
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t EcdsaVerifyOperation::Begin(const AuthorizationSet& /* input_params */,
+ AuthorizationSet* /* output_params */) {
+ keymaster_error_t error = InitDigest();
+ if (error != KM_ERROR_OK)
+ return error;
+
+ 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 */,
+ ecdsa_key_) != 1)
+ return TranslateLastOpenSslError();
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t EcdsaVerifyOperation::Update(const AuthorizationSet& /* additional_params */,
+ const Buffer& input,
+ AuthorizationSet* /* output_params */,
+ Buffer* /* output */, size_t* 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();
+ *input_consumed = input.available_read();
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t EcdsaVerifyOperation::Finish(const AuthorizationSet& additional_params,
+ const Buffer& input, const Buffer& signature,
+ AuthorizationSet* /* output_params */,
+ Buffer* /* output */) {
+ keymaster_error_t error = UpdateForFinish(additional_params, input);
+ 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();
+
+ int result =
+ ECDSA_verify(0 /* type -- ignored */, data_.peek_read(), data_.available_read(),
+ signature.peek_read(), signature.available_read(), ecdsa.get());
+ if (result < 0)
+ return TranslateLastOpenSslError();
+ else if (result == 0)
+ return KM_ERROR_VERIFICATION_FAILED;
+ } else if (!EVP_DigestVerifyFinal(&digest_ctx_, signature.peek_read(),
+ signature.available_read()))
+ return KM_ERROR_VERIFICATION_FAILED;
+
+ return KM_ERROR_OK;
+}
+
+} // namespace keymaster
diff --git a/keymaster/ecdsa_operation.h b/keymaster/ecdsa_operation.h
new file mode 100644
index 0000000..4b95dc9
--- /dev/null
+++ b/keymaster/ecdsa_operation.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2014 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_ECDSA_OPERATION_H_
+#define SYSTEM_KEYMASTER_ECDSA_OPERATION_H_
+
+#include <openssl/ec.h>
+#include <openssl/evp.h>
+
+#include <UniquePtr.h>
+
+#include "operation.h"
+
+namespace keymaster {
+
+class EcdsaOperation : public Operation {
+ public:
+ EcdsaOperation(keymaster_purpose_t purpose, keymaster_digest_t digest, EVP_PKEY* key)
+ : Operation(purpose), digest_(digest), ecdsa_key_(key) {
+ EVP_MD_CTX_init(&digest_ctx_);
+ }
+ ~EcdsaOperation();
+
+ keymaster_error_t Abort() override { return KM_ERROR_OK; }
+
+ protected:
+ keymaster_error_t StoreData(const Buffer& input, size_t* input_consumed);
+ keymaster_error_t InitDigest();
+
+ keymaster_digest_t digest_;
+ const EVP_MD* digest_algorithm_;
+ EVP_PKEY* ecdsa_key_;
+ EVP_MD_CTX digest_ctx_;
+ Buffer data_;
+};
+
+class EcdsaSignOperation : public EcdsaOperation {
+ public:
+ EcdsaSignOperation(keymaster_digest_t digest, EVP_PKEY* key)
+ : EcdsaOperation(KM_PURPOSE_SIGN, digest, key) {}
+ 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;
+};
+
+class EcdsaVerifyOperation : public EcdsaOperation {
+ public:
+ EcdsaVerifyOperation(keymaster_digest_t digest, EVP_PKEY* key)
+ : EcdsaOperation(KM_PURPOSE_VERIFY, digest, key) {}
+ 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;
+};
+
+class EcdsaOperationFactory : public OperationFactory {
+ private:
+ KeyType registry_key() const override { return KeyType(KM_ALGORITHM_EC, purpose()); }
+ Operation* CreateOperation(const Key& key, const AuthorizationSet& begin_params,
+ keymaster_error_t* error) override;
+ const keymaster_digest_t* SupportedDigests(size_t* digest_count) const override;
+
+ virtual keymaster_purpose_t purpose() const = 0;
+ virtual Operation* InstantiateOperation(keymaster_digest_t digest, EVP_PKEY* key) = 0;
+};
+
+class EcdsaSignOperationFactory : public EcdsaOperationFactory {
+ private:
+ keymaster_purpose_t purpose() const override { return KM_PURPOSE_SIGN; }
+ Operation* InstantiateOperation(keymaster_digest_t digest, EVP_PKEY* key) {
+ return new (std::nothrow) EcdsaSignOperation(digest, key);
+ }
+};
+
+class EcdsaVerifyOperationFactory : public EcdsaOperationFactory {
+ public:
+ keymaster_purpose_t purpose() const override { return KM_PURPOSE_VERIFY; }
+ Operation* InstantiateOperation(keymaster_digest_t digest, EVP_PKEY* key) {
+ return new (std::nothrow) EcdsaVerifyOperation(digest, key);
+ }
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_ECDSA_OPERATION_H_
diff --git a/keymaster/ecies_kem.cpp b/keymaster/ecies_kem.cpp
new file mode 100644
index 0000000..2e31573
--- /dev/null
+++ b/keymaster/ecies_kem.cpp
@@ -0,0 +1,185 @@
+/*
+ * 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 "ecies_kem.h"
+
+#include "nist_curve_key_exchange.h"
+#include "openssl_err.h"
+
+namespace keymaster {
+
+EciesKem::EciesKem(const AuthorizationSet& kem_description, keymaster_error_t* error) {
+ const AuthorizationSet& authorizations(kem_description);
+
+ if (!authorizations.GetTagValue(TAG_EC_CURVE, &curve_)) {
+ LOG_E("%s", "EciesKem: no curve specified");
+ *error = KM_ERROR_INVALID_ARGUMENT;
+ return;
+ }
+
+ switch (curve_) {
+ case KM_EC_CURVE_P_224:
+ case KM_EC_CURVE_P_256:
+ case KM_EC_CURVE_P_384:
+ case KM_EC_CURVE_P_521:
+ break;
+ default:
+ LOG_E("EciesKem: curve %d is unsupported", curve_);
+ *error = KM_ERROR_UNSUPPORTED_EC_CURVE;
+ return;
+ }
+
+ keymaster_kdf_t kdf;
+ if (!authorizations.GetTagValue(TAG_KDF, &kdf)) {
+ LOG_E("EciesKem: No KDF specified", 0);
+ *error = KM_ERROR_UNSUPPORTED_KDF;
+ return;
+ }
+ switch (kdf) {
+ case KM_KDF_RFC5869_SHA256:
+ kdf_.reset(new Rfc5869Sha256Kdf());
+ break;
+ default:
+ LOG_E("Kdf %d is unsupported", kdf);
+ *error = KM_ERROR_UNSUPPORTED_KDF;
+ return;
+ }
+ if (!kdf_.get()) {
+ *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return;
+ }
+
+ if (!authorizations.GetTagValue(TAG_KEY_SIZE, &key_bytes_to_generate_)) {
+ LOG_E("%s", "EciesKem: no key length specified");
+ *error = KM_ERROR_UNSUPPORTED_KEY_SIZE;
+ return;
+ }
+
+ single_hash_mode_ = authorizations.GetTagValue(TAG_ECIES_SINGLE_HASH_MODE);
+ *error = KM_ERROR_OK;
+}
+
+bool EciesKem::Encrypt(const Buffer& peer_public_value, Buffer* output_clear_key,
+ Buffer* output_encrypted_key) {
+ return Encrypt(peer_public_value.peek_read(), peer_public_value.available_read(),
+ output_clear_key, output_encrypted_key);
+}
+
+// http://www.shoup.net/iso/std6.pdf, section 10.2.3.
+bool EciesKem::Encrypt(const uint8_t* peer_public_value, size_t peer_public_value_len,
+ Buffer* output_clear_key, Buffer* output_encrypted_key) {
+
+ key_exchange_.reset(NistCurveKeyExchange::GenerateKeyExchange(curve_));
+ if (!key_exchange_.get()) {
+ return false;
+ }
+
+ Buffer shared_secret;
+ if (!key_exchange_->CalculateSharedKey(peer_public_value, peer_public_value_len,
+ &shared_secret)) {
+ LOG_E("EciesKem: ECDH failed, can't obtain shared secret", 0);
+ return false;
+ }
+ if (!key_exchange_->public_value(output_encrypted_key)) {
+ LOG_E("EciesKem: Can't obtain public value", 0);
+ return false;
+ }
+
+ Buffer z;
+ if (single_hash_mode_) {
+ // z is empty.
+ } else {
+ // z = C0
+ z.Reinitialize(output_encrypted_key->peek_read(), output_encrypted_key->available_read());
+ }
+
+ Buffer actual_secret(z.available_read() + shared_secret.available_read());
+ actual_secret.write(z.peek_read(), z.available_read());
+ actual_secret.write(shared_secret.peek_read(), shared_secret.available_read());
+
+ if (!kdf_->Init(actual_secret.peek_read(), actual_secret.available_read(), nullptr /* salt */,
+ 0 /* salt_len */)) {
+ LOG_E("EciesKem: KDF failed, can't derived keys", 0);
+ return false;
+ }
+ output_clear_key->Reinitialize(key_bytes_to_generate_);
+ if (!kdf_->GenerateKey(nullptr /* info */, 0 /* info length */, output_clear_key->peek_write(),
+ key_bytes_to_generate_)) {
+ LOG_E("EciesKem: KDF failed, can't derived keys", 0);
+ return false;
+ }
+ output_clear_key->advance_write(key_bytes_to_generate_);
+
+ return true;
+}
+
+bool EciesKem::Decrypt(EC_KEY* private_key, const Buffer& encrypted_key, Buffer* output_key) {
+ return Decrypt(private_key, encrypted_key.peek_read(), encrypted_key.available_read(),
+ output_key);
+}
+
+// http://www.shoup.net/iso/std6.pdf, section 10.2.4.
+bool EciesKem::Decrypt(EC_KEY* private_key, const uint8_t* encrypted_key, size_t encrypted_key_len,
+ Buffer* output_key) {
+
+ keymaster_error_t error;
+ key_exchange_.reset(new NistCurveKeyExchange(private_key, &error));
+ if (!key_exchange_.get() || error != KM_ERROR_OK) {
+ return false;
+ }
+
+ Buffer shared_secret;
+ if (!key_exchange_->CalculateSharedKey(encrypted_key, encrypted_key_len, &shared_secret)) {
+ LOG_E("EciesKem: ECDH failed, can't obtain shared secret", 0);
+ return false;
+ }
+
+ Buffer public_value;
+ if (!key_exchange_->public_value(&public_value)) {
+ LOG_E("%s", "EciesKem: Can't obtain public value");
+ return false;
+ }
+
+ Buffer z;
+ if (single_hash_mode_) {
+ // z is empty.
+ } else {
+ // z = C0
+ z.Reinitialize(public_value.peek_read(), public_value.available_read());
+ }
+
+ Buffer actual_secret(z.available_read() + shared_secret.available_read());
+ actual_secret.write(z.peek_read(), z.available_read());
+ actual_secret.write(shared_secret.peek_read(), shared_secret.available_read());
+
+ if (!kdf_->Init(actual_secret.peek_read(), actual_secret.available_read(), nullptr /* salt */,
+ 0 /* salt_len */)) {
+ LOG_E("%s", "EciesKem: KDF failed, can't derived keys");
+ return false;
+ }
+
+ output_key->Reinitialize(key_bytes_to_generate_);
+ if (!kdf_->GenerateKey(nullptr /* info */, 0 /* info_len */, output_key->peek_write(),
+ key_bytes_to_generate_)) {
+ LOG_E("%s", "EciesKem: KDF failed, can't derived keys");
+ return false;
+ }
+ output_key->advance_write(key_bytes_to_generate_);
+
+ return true;
+}
+
+} // namespace keymaster
diff --git a/keymaster/ecies_kem.h b/keymaster/ecies_kem.h
new file mode 100644
index 0000000..8c1b330
--- /dev/null
+++ b/keymaster/ecies_kem.h
@@ -0,0 +1,61 @@
+/*
+ * 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_ECIES_KEM_H_
+#define SYSTEM_KEYMASTER_ECIES_KEM_H_
+
+#include "kem.h"
+
+#include <UniquePtr.h>
+#include <openssl/ec.h>
+
+#include <keymaster/authorization_set.h>
+
+#include "hkdf.h"
+#include "key_exchange.h"
+
+namespace keymaster {
+
+/**
+ * EciesKem is an implementation of the key encapsulation mechanism ECIES-KEM described in
+ * ISO 18033-2 (http://www.shoup.net/iso/std6.pdf, http://www.shoup.net/papers/iso-2_1.pdf).
+ */
+class EciesKem : public Kem {
+ public:
+ virtual ~EciesKem() override {}
+ EciesKem(const AuthorizationSet& kem_description, keymaster_error_t* error);
+
+ /* Kem interface. */
+ bool Encrypt(const Buffer& peer_public_value, Buffer* output_clear_key,
+ Buffer* output_encrypted_key) override;
+ bool Encrypt(const uint8_t* peer_public_value, size_t peer_public_value_len,
+ Buffer* output_clear_key, Buffer* output_encrypted_key) override;
+
+ bool Decrypt(EC_KEY* private_key, const Buffer& encrypted_key, Buffer* output_key) override;
+ bool Decrypt(EC_KEY* private_key, const uint8_t* encrypted_key, size_t encrypted_key_len,
+ Buffer* output_key) override;
+
+ private:
+ UniquePtr<KeyExchange> key_exchange_;
+ UniquePtr<Rfc5869Sha256Kdf> kdf_;
+ bool single_hash_mode_;
+ uint32_t key_bytes_to_generate_;
+ keymaster_ec_curve_t curve_;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_ECIES_KEM_H_
diff --git a/keymaster/ecies_kem_test.cpp b/keymaster/ecies_kem_test.cpp
new file mode 100644
index 0000000..f653dc0
--- /dev/null
+++ b/keymaster/ecies_kem_test.cpp
@@ -0,0 +1,73 @@
+/*
+ * 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 "ecies_kem.h"
+
+#include <gtest/gtest.h>
+#include <openssl/evp.h>
+
+#include <hardware/keymaster_defs.h>
+#include <keymaster/android_keymaster_utils.h>
+
+#include "android_keymaster_test_utils.h"
+#include "nist_curve_key_exchange.h"
+
+using std::string;
+
+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};
+
+/**
+ * TestConsistency just tests that the basic key encapsulation hold.
+ */
+TEST(EciesKem, TestConsistency) {
+ static const uint32_t kKeyLen = 32;
+ for (auto& curve : kEcCurves) {
+ AuthorizationSet kem_description(AuthorizationSetBuilder()
+ .Authorization(TAG_EC_CURVE, curve)
+ .Authorization(TAG_KDF, KM_KDF_RFC5869_SHA256)
+ .Authorization(TAG_ECIES_SINGLE_HASH_MODE)
+ .Authorization(TAG_KEY_SIZE, kKeyLen));
+ keymaster_error_t error;
+ EciesKem* kem = new EciesKem(kem_description, &error);
+ ASSERT_EQ(KM_ERROR_OK, error);
+
+ NistCurveKeyExchange* key_exchange = NistCurveKeyExchange::GenerateKeyExchange(curve);
+ Buffer peer_public_value;
+ ASSERT_TRUE(key_exchange->public_value(&peer_public_value));
+
+ Buffer output_clear_key;
+ Buffer output_encrypted_key;
+ ASSERT_TRUE(kem->Encrypt(peer_public_value, &output_clear_key, &output_encrypted_key));
+ ASSERT_EQ(kKeyLen, output_clear_key.available_read());
+ ASSERT_EQ(peer_public_value.available_read(), output_encrypted_key.available_read());
+
+ Buffer decrypted_clear_key;
+ ASSERT_TRUE(
+ kem->Decrypt(key_exchange->private_key(), output_encrypted_key, &decrypted_clear_key));
+ ASSERT_EQ(kKeyLen, decrypted_clear_key.available_read());
+ EXPECT_EQ(0, memcmp(output_clear_key.peek_read(), decrypted_clear_key.peek_read(),
+ output_clear_key.available_read()));
+ }
+}
+
+} // namespace test
+} // namespace keymaster
diff --git a/keymaster/gtest_main.cpp b/keymaster/gtest_main.cpp
new file mode 100644
index 0000000..6072749
--- /dev/null
+++ b/keymaster/gtest_main.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 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 <gtest/gtest.h>
+
+#include <openssl/engine.h>
+
+int main(int argc, char** argv) {
+#if !defined(OPENSSL_IS_BORINGSSL)
+ ERR_load_crypto_strings();
+#endif // not OPENSSL_IS_BORINGSSL
+ ::testing::InitGoogleTest(&argc, argv);
+ int result = RUN_ALL_TESTS();
+#if !defined(OPENSSL_IS_BORINGSSL)
+ // Clean up stuff OpenSSL leaves around, so Valgrind doesn't complain.
+ CRYPTO_cleanup_all_ex_data();
+ ERR_remove_thread_state(NULL);
+ ERR_free_strings();
+#endif // not OPENSSL_IS_BORINGSSL
+ return result;
+}
diff --git a/keymaster/hkdf.cpp b/keymaster/hkdf.cpp
new file mode 100644
index 0000000..9727375
--- /dev/null
+++ b/keymaster/hkdf.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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 "hkdf.h"
+
+#include <new>
+
+#include <keymaster/android_keymaster_utils.h>
+
+#include "hmac.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;
+ /**
+ * Step 1. Extract: PRK = HMAC-SHA256(actual_salt, secret)
+ * https://tools.ietf.org/html/rfc5869#section-2.2
+ */
+ HmacSha256 prk_hmac;
+ bool result;
+ if (salt_.get() != nullptr && salt_len_ > 0) {
+ result = prk_hmac.Init(salt_.get(), salt_len_);
+ } else {
+ UniquePtr<uint8_t[]> zeros(new 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;
+
+ UniquePtr<uint8_t[]> pseudo_random_key(new 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;
+
+ /**
+ * 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;
+
+ UniquePtr<uint8_t[]> buf(new uint8_t[digest_size_ + info_len + 1]);
+ UniquePtr<uint8_t[]> digest(new 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;
+
+ for (size_t i = 0; i < num_blocks; i++) {
+ size_t block_input_len = 0;
+ if (i != 0) {
+ 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);
+ 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;
+ size_t block_output_len = digest_size_ < output_len - i * digest_size_
+ ? digest_size_
+ : output_len - i * digest_size_;
+ memcpy(output + i * digest_size_, digest.get(), block_output_len);
+ }
+ return true;
+}
+
+} // namespace keymaster
diff --git a/keymaster/hkdf.h b/keymaster/hkdf.h
new file mode 100644
index 0000000..9de39bf
--- /dev/null
+++ b/keymaster/hkdf.h
@@ -0,0 +1,50 @@
+/*
+ * 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_HKDF_H_
+#define SYSTEM_KEYMASTER_HKDF_H_
+
+#include "kdf.h"
+
+#include <keymaster/serializable.h>
+
+#include <UniquePtr.h>
+
+namespace keymaster {
+
+/**
+ * Rfc5869Sha256Kdf implements the key derivation function specified in RFC 5869 (using SHA256) and
+ * outputs key material, as needed by ECIES. See https://tools.ietf.org/html/rfc5869 for details.
+ */
+class Rfc5869Sha256Kdf : public Kdf {
+ public:
+ ~Rfc5869Sha256Kdf() {}
+ bool Init(Buffer& secret, Buffer& salt) {
+ return Init(secret.peek_read(), secret.available_read(), salt.peek_read(),
+ salt.available_read());
+ }
+
+ bool Init(const uint8_t* secret, size_t secret_len, const uint8_t* salt, size_t salt_len) {
+ return Kdf::Init(KM_DIGEST_SHA_2_256, secret, secret_len, salt, salt_len);
+ }
+
+ bool GenerateKey(const uint8_t* info, size_t info_len, uint8_t* output,
+ size_t output_len) override;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_HKDF_H_
diff --git a/keymaster/hkdf_test.cpp b/keymaster/hkdf_test.cpp
new file mode 100644
index 0000000..3d3f092
--- /dev/null
+++ b/keymaster/hkdf_test.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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 "hkdf.h"
+
+#include <gtest/gtest.h>
+#include <string.h>
+
+#include "android_keymaster_test_utils.h"
+
+using std::string;
+
+namespace keymaster {
+namespace test {
+
+struct HkdfTest {
+ const char* key_hex;
+ const char* salt_hex;
+ const char* info_hex;
+ const char* output_hex;
+};
+
+// These test cases are taken from
+// https://tools.ietf.org/html/rfc5869#appendix-A.
+static const HkdfTest kHkdfTests[] = {
+ {
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "000102030405060708090a0b0c",
+ "f0f1f2f3f4f5f6f7f8f9",
+ "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865",
+ },
+ {
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c"
+ "2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f",
+ "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c"
+ "8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
+ "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdc"
+ "dddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+ "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e"
+ "590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87",
+ },
+ {
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "", "",
+ "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8",
+ },
+};
+
+TEST(HkdfTest, Hkdf) {
+ for (auto& test : kHkdfTests) {
+ const string key = hex2str(test.key_hex);
+ const string salt = hex2str(test.salt_hex);
+ const string info = hex2str(test.info_hex);
+ const string expected = hex2str(test.output_hex);
+ size_t output_len = expected.size();
+ uint8_t output[output_len];
+ Rfc5869Sha256Kdf hkdf;
+ ASSERT_TRUE(hkdf.Init(reinterpret_cast<const uint8_t*>(key.data()), key.size(),
+ reinterpret_cast<const uint8_t*>(salt.data()), salt.size()));
+ ASSERT_TRUE(hkdf.GenerateKey(reinterpret_cast<const uint8_t*>(info.data()), info.size(),
+ output, output_len));
+ EXPECT_EQ(0, memcmp(output, expected.data(), output_len));
+ }
+}
+
+} // namespace test
+} // namespace keymaster
diff --git a/keymaster/hmac.cpp b/keymaster/hmac.cpp
new file mode 100644
index 0000000..02f739c
--- /dev/null
+++ b/keymaster/hmac.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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 "hmac.h"
+
+#include <assert.h>
+
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/mem.h>
+#include <openssl/sha.h>
+
+#include <keymaster/android_keymaster_utils.h>
+
+namespace keymaster {
+
+size_t HmacSha256::DigestLength() const {
+ return SHA256_DIGEST_LENGTH;
+}
+
+bool HmacSha256::Init(const Buffer& key) {
+ return Init(key.peek_read(), key.available_read());
+}
+
+bool HmacSha256::Init(const uint8_t* key, size_t key_len) {
+ if (!key)
+ return false;
+
+ key_len_ = key_len;
+ key_.reset(dup_buffer(key, key_len));
+ if (!key_.get()) {
+ return false;
+ }
+ return true;
+}
+
+bool HmacSha256::Sign(const Buffer& data, uint8_t* out_digest, size_t digest_len) const {
+ return Sign(data.peek_read(), data.available_read(), out_digest, digest_len);
+}
+
+bool HmacSha256::Sign(const uint8_t* data, size_t data_len, uint8_t* out_digest,
+ size_t digest_len) const {
+ assert(digest_len);
+
+ uint8_t tmp[SHA256_DIGEST_LENGTH];
+ uint8_t* digest = tmp;
+ 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);
+
+ return true;
+}
+
+bool HmacSha256::Verify(const Buffer& data, const Buffer& digest) const {
+ return Verify(data.peek_read(), data.available_read(), digest.peek_read(),
+ digest.available_read());
+}
+
+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;
+
+ uint8_t computed_digest[SHA256_DIGEST_LENGTH];
+ if (!Sign(data, data_len, computed_digest, sizeof(computed_digest)))
+ return false;
+
+ return 0 == CRYPTO_memcmp(digest, computed_digest, SHA256_DIGEST_LENGTH);
+}
+
+} // namespace keymaster
diff --git a/keymaster/hmac.h b/keymaster/hmac.h
new file mode 100644
index 0000000..ebd5b70
--- /dev/null
+++ b/keymaster/hmac.h
@@ -0,0 +1,60 @@
+/*
+ * 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_HMAC_H_
+#define SYSTEM_KEYMASTER_HMAC_H_
+
+#include <keymaster/serializable.h>
+
+namespace keymaster {
+
+// Only HMAC-SHA256 is supported.
+class HmacSha256 {
+ public:
+ HmacSha256(){};
+
+ // DigestLength returns the length, in bytes, of the resulting digest.
+ size_t DigestLength() const;
+
+ // Initializes this instance using |key|. Call Init only once. It returns
+ // false on the second of later calls.
+ bool Init(const uint8_t* key, size_t key_length);
+ bool Init(const Buffer& key);
+
+ // Sign calculates the HMAC of |data| with the key supplied to the Init
+ // method. At most |digest_len| bytes of the resulting digest are written
+ // to |digest|.
+ bool Sign(const Buffer& data, uint8_t* digest, size_t digest_len) const;
+ bool Sign(const uint8_t* data, size_t data_len, uint8_t* digest, size_t digest_len) const;
+
+ // Verify returns true if |digest| is a valid HMAC of |data| using the key
+ // supplied to Init. |digest| must be exactly |DigestLength()| bytes long.
+ // Use of this method is strongly recommended over using Sign() with a manual
+ // comparison (such as memcmp), as such comparisons may result in
+ // side-channel disclosures, such as timing, that undermine the cryptographic
+ // integrity.
+ bool Verify(const Buffer& data, const Buffer& digest) const;
+ bool Verify(const uint8_t* data, size_t data_len, const uint8_t* digest,
+ size_t digest_len) const;
+
+ private:
+ UniquePtr<uint8_t[]> key_;
+ size_t key_len_;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_HMAC_H_
diff --git a/keymaster/hmac_key.cpp b/keymaster/hmac_key.cpp
new file mode 100644
index 0000000..40a8906
--- /dev/null
+++ b/keymaster/hmac_key.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2014 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 "hmac_key.h"
+
+#include <new>
+
+#include <openssl/err.h>
+#include <openssl/rand.h>
+
+#include "hmac_operation.h"
+
+namespace keymaster {
+
+static HmacSignOperationFactory sign_factory;
+static HmacVerifyOperationFactory verify_factory;
+
+OperationFactory* HmacKeyFactory::GetOperationFactory(keymaster_purpose_t purpose) const {
+ switch (purpose) {
+ case KM_PURPOSE_SIGN:
+ return &sign_factory;
+ case KM_PURPOSE_VERIFY:
+ return &verify_factory;
+ default:
+ return nullptr;
+ }
+}
+
+keymaster_error_t HmacKeyFactory::LoadKey(const KeymasterKeyBlob& key_material,
+ const AuthorizationSet& /* additional_params */,
+ const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ UniquePtr<Key>* key) const {
+ if (!key)
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+ uint32_t min_mac_length;
+ if (!hw_enforced.GetTagValue(TAG_MIN_MAC_LENGTH, &min_mac_length) &&
+ !sw_enforced.GetTagValue(TAG_MIN_MAC_LENGTH, &min_mac_length)) {
+ LOG_E("HMAC key must have KM_TAG_MIN_MAC_LENGTH", 0);
+ return KM_ERROR_INVALID_KEY_BLOB;
+ }
+
+ keymaster_error_t error;
+ key->reset(new (std::nothrow) HmacKey(key_material, hw_enforced, sw_enforced, &error));
+ if (!key->get())
+ error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return error;
+}
+
+keymaster_error_t HmacKeyFactory::validate_algorithm_specific_new_key_params(
+ const AuthorizationSet& key_description) const {
+ uint32_t min_mac_length_bits;
+ if (!key_description.GetTagValue(TAG_MIN_MAC_LENGTH, &min_mac_length_bits))
+ return KM_ERROR_MISSING_MIN_MAC_LENGTH;
+
+ keymaster_digest_t digest;
+ if (!key_description.GetTagValue(TAG_DIGEST, &digest)) {
+ LOG_E("%d digests specified for HMAC key", key_description.GetTagCount(TAG_DIGEST));
+ return KM_ERROR_UNSUPPORTED_DIGEST;
+ }
+
+ size_t hash_size_bits = 0;
+ switch (digest) {
+ case KM_DIGEST_NONE:
+ return KM_ERROR_UNSUPPORTED_DIGEST;
+ case KM_DIGEST_MD5:
+ hash_size_bits = 128;
+ break;
+ case KM_DIGEST_SHA1:
+ hash_size_bits = 160;
+ break;
+ case KM_DIGEST_SHA_2_224:
+ hash_size_bits = 224;
+ break;
+ case KM_DIGEST_SHA_2_256:
+ hash_size_bits = 256;
+ break;
+ case KM_DIGEST_SHA_2_384:
+ hash_size_bits = 384;
+ break;
+ case KM_DIGEST_SHA_2_512:
+ hash_size_bits = 512;
+ break;
+ };
+
+ if (hash_size_bits == 0) {
+ // digest was not matched
+ return KM_ERROR_UNSUPPORTED_DIGEST;
+ }
+
+ 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;
+
+ return KM_ERROR_OK;
+}
+
+} // namespace keymaster
diff --git a/keymaster/hmac_key.h b/keymaster/hmac_key.h
new file mode 100644
index 0000000..c05e6a3
--- /dev/null
+++ b/keymaster/hmac_key.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2014 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_HMAC_KEY_H_
+#define SYSTEM_KEYMASTER_HMAC_KEY_H_
+
+#include "symmetric_key.h"
+
+namespace keymaster {
+
+const size_t kMinHmacLengthBits = 64;
+
+class HmacKeyFactory : public SymmetricKeyFactory {
+ public:
+ explicit HmacKeyFactory(const KeymasterContext* context) : SymmetricKeyFactory(context) {}
+
+ keymaster_error_t LoadKey(const KeymasterKeyBlob& key_material,
+ const AuthorizationSet& additional_params,
+ const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ UniquePtr<Key>* key) const override;
+
+ OperationFactory* GetOperationFactory(keymaster_purpose_t purpose) const override;
+
+ private:
+ bool key_size_supported(size_t key_size_bits) const override {
+ return key_size_bits > 0 && key_size_bits % 8 == 00 &&
+ key_size_bits <= 2048 /* Some RFC test cases require >1024-bit keys */;
+ }
+ keymaster_error_t validate_algorithm_specific_new_key_params(
+ const AuthorizationSet& key_description) const override;
+};
+
+class HmacKey : public SymmetricKey {
+ public:
+ HmacKey(const KeymasterKeyBlob& key_material, const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced, keymaster_error_t* error)
+ : SymmetricKey(key_material, hw_enforced, sw_enforced, error) {}
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_HMAC_KEY_H_
diff --git a/keymaster/hmac_operation.cpp b/keymaster/hmac_operation.cpp
new file mode 100644
index 0000000..7f21393
--- /dev/null
+++ b/keymaster/hmac_operation.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2014 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 "hmac_operation.h"
+
+#include <new>
+
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+
+#include "hmac_key.h"
+#include "openssl_err.h"
+
+#if defined(OPENSSL_IS_BORINGSSL)
+#include <openssl/mem.h>
+typedef size_t openssl_size_t;
+#else
+typedef int openssl_size_t;
+#endif
+
+namespace keymaster {
+
+Operation* HmacOperationFactory::CreateOperation(const Key& key,
+ const AuthorizationSet& begin_params,
+ keymaster_error_t* error) {
+ uint32_t min_mac_length_bits;
+ if (!key.authorizations().GetTagValue(TAG_MIN_MAC_LENGTH, &min_mac_length_bits)) {
+ LOG_E("HMAC key must have KM_TAG_MIN_MAC_LENGTH", 0);
+ *error = KM_ERROR_INVALID_KEY_BLOB;
+ return nullptr;
+ }
+
+ uint32_t mac_length_bits = UINT32_MAX;
+ if (begin_params.GetTagValue(TAG_MAC_LENGTH, &mac_length_bits)) {
+ if (purpose() == KM_PURPOSE_VERIFY) {
+ LOG_E("MAC length may not be specified for verify", 0);
+ *error = KM_ERROR_INVALID_ARGUMENT;
+ return nullptr;
+ }
+ } else {
+ if (purpose() == KM_PURPOSE_SIGN) {
+ *error = KM_ERROR_MISSING_MAC_LENGTH;
+ return nullptr;
+ }
+ }
+
+ keymaster_digest_t digest;
+ if (!key.authorizations().GetTagValue(TAG_DIGEST, &digest)) {
+ LOG_E("%d digests found in HMAC key authorizations; must be exactly 1",
+ begin_params.GetTagCount(TAG_DIGEST));
+ *error = KM_ERROR_INVALID_KEY_BLOB;
+ return nullptr;
+ }
+
+ const SymmetricKey* symmetric_key = static_cast<const SymmetricKey*>(&key);
+ UniquePtr<HmacOperation> op(new (std::nothrow) HmacOperation(
+ purpose(), symmetric_key->key_data(), symmetric_key->key_data_size(), digest,
+ mac_length_bits / 8, min_mac_length_bits / 8));
+ if (!op.get())
+ *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ else
+ *error = op->error();
+
+ if (*error != KM_ERROR_OK)
+ return nullptr;
+
+ return op.release();
+}
+
+static keymaster_digest_t supported_digests[] = {KM_DIGEST_SHA1, KM_DIGEST_SHA_2_224,
+ KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384,
+ KM_DIGEST_SHA_2_512};
+const keymaster_digest_t* HmacOperationFactory::SupportedDigests(size_t* digest_count) const {
+ *digest_count = array_length(supported_digests);
+ return supported_digests;
+}
+
+HmacOperation::HmacOperation(keymaster_purpose_t purpose, const uint8_t* key_data,
+ size_t key_data_size, keymaster_digest_t digest, size_t mac_length,
+ size_t min_mac_length)
+ : Operation(purpose), error_(KM_ERROR_OK), mac_length_(mac_length),
+ min_mac_length_(min_mac_length) {
+ // Initialize CTX first, so dtor won't crash even if we error out later.
+ HMAC_CTX_init(&ctx_);
+
+ const EVP_MD* md = nullptr;
+ switch (digest) {
+ case KM_DIGEST_NONE:
+ case KM_DIGEST_MD5:
+ error_ = KM_ERROR_UNSUPPORTED_DIGEST;
+ break;
+ case KM_DIGEST_SHA1:
+ md = EVP_sha1();
+ break;
+ case KM_DIGEST_SHA_2_224:
+ md = EVP_sha224();
+ break;
+ case KM_DIGEST_SHA_2_256:
+ md = EVP_sha256();
+ break;
+ case KM_DIGEST_SHA_2_384:
+ md = EVP_sha384();
+ break;
+ case KM_DIGEST_SHA_2_512:
+ md = EVP_sha512();
+ break;
+ }
+
+ if (md == nullptr) {
+ error_ = KM_ERROR_UNSUPPORTED_DIGEST;
+ return;
+ }
+
+ if (purpose == KM_PURPOSE_SIGN) {
+ if (mac_length > EVP_MD_size(md) || mac_length < kMinHmacLengthBits / 8) {
+ error_ = KM_ERROR_UNSUPPORTED_MAC_LENGTH;
+ return;
+ }
+ if (mac_length < min_mac_length) {
+ error_ = KM_ERROR_INVALID_MAC_LENGTH;
+ return;
+ }
+ }
+
+ HMAC_Init_ex(&ctx_, key_data, key_data_size, md, NULL /* engine */);
+}
+
+HmacOperation::~HmacOperation() {
+ HMAC_CTX_cleanup(&ctx_);
+}
+
+keymaster_error_t HmacOperation::Begin(const AuthorizationSet& /* input_params */,
+ AuthorizationSet* /* output_params */) {
+ return error_;
+}
+
+keymaster_error_t HmacOperation::Update(const AuthorizationSet& /* additional_params */,
+ const Buffer& input, AuthorizationSet* /* output_params */,
+ Buffer* /* output */, size_t* input_consumed) {
+ if (!HMAC_Update(&ctx_, input.peek_read(), input.available_read()))
+ return TranslateLastOpenSslError();
+ *input_consumed = input.available_read();
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t HmacOperation::Abort() {
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t HmacOperation::Finish(const AuthorizationSet& additional_params,
+ const Buffer& input, const Buffer& signature,
+ AuthorizationSet* /* output_params */, Buffer* output) {
+ keymaster_error_t error = UpdateForFinish(additional_params, input);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ uint8_t digest[EVP_MAX_MD_SIZE];
+ unsigned int digest_len;
+ if (!HMAC_Final(&ctx_, digest, &digest_len))
+ return TranslateLastOpenSslError();
+
+ switch (purpose()) {
+ case KM_PURPOSE_SIGN:
+ if (mac_length_ > digest_len)
+ return KM_ERROR_UNSUPPORTED_MAC_LENGTH;
+ if (!output->reserve(mac_length_) || !output->write(digest, mac_length_))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return KM_ERROR_OK;
+ case KM_PURPOSE_VERIFY: {
+ size_t siglen = signature.available_read();
+ if (siglen > digest_len || siglen < kMinHmacLengthBits / 8)
+ return KM_ERROR_UNSUPPORTED_MAC_LENGTH;
+ if (siglen < min_mac_length_)
+ return KM_ERROR_INVALID_MAC_LENGTH;
+ if (CRYPTO_memcmp(signature.peek_read(), digest, siglen) != 0)
+ return KM_ERROR_VERIFICATION_FAILED;
+ return KM_ERROR_OK;
+ }
+ default:
+ return KM_ERROR_UNSUPPORTED_PURPOSE;
+ }
+}
+
+} // namespace keymaster
diff --git a/keymaster/hmac_operation.h b/keymaster/hmac_operation.h
new file mode 100644
index 0000000..83f2e09
--- /dev/null
+++ b/keymaster/hmac_operation.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2014 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_HMAC_OPERATION_H_
+#define SYSTEM_KEYMASTER_HMAC_OPERATION_H_
+
+#include "operation.h"
+
+#include <openssl/hmac.h>
+
+namespace keymaster {
+
+class HmacOperation : public Operation {
+ public:
+ HmacOperation(keymaster_purpose_t purpose, const uint8_t* key_data, size_t key_data_size,
+ keymaster_digest_t digest, size_t mac_length, size_t min_mac_length);
+ ~HmacOperation();
+
+ virtual keymaster_error_t Begin(const AuthorizationSet& input_params,
+ AuthorizationSet* output_params);
+ virtual keymaster_error_t Update(const AuthorizationSet& additional_params, const Buffer& input,
+ AuthorizationSet* output_params, Buffer* output,
+ size_t* input_consumed);
+ virtual keymaster_error_t Abort();
+ virtual keymaster_error_t Finish(const AuthorizationSet& additional_params, const Buffer& input,
+ const Buffer& signature, AuthorizationSet* output_params,
+ Buffer* output);
+
+ keymaster_error_t error() { return error_; }
+
+ private:
+ HMAC_CTX ctx_;
+ keymaster_error_t error_;
+ const size_t mac_length_;
+ const size_t min_mac_length_;
+};
+
+/**
+ * Abstract base for HMAC operation factories. This class does all of the work to create
+ * HMAC operations.
+ */
+class HmacOperationFactory : public OperationFactory {
+ public:
+ virtual KeyType registry_key() const { return KeyType(KM_ALGORITHM_HMAC, purpose()); }
+
+ virtual Operation* CreateOperation(const Key& key, const AuthorizationSet& begin_params,
+ keymaster_error_t* error);
+
+ virtual const keymaster_digest_t* SupportedDigests(size_t* digest_count) const;
+
+ virtual keymaster_purpose_t purpose() const = 0;
+};
+
+class HmacSignOperationFactory : public HmacOperationFactory {
+ keymaster_purpose_t purpose() const { return KM_PURPOSE_SIGN; }
+};
+
+class HmacVerifyOperationFactory : public HmacOperationFactory {
+ keymaster_purpose_t purpose() const { return KM_PURPOSE_VERIFY; }
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_HMAC_OPERATION_H_
diff --git a/keymaster/hmac_test.cpp b/keymaster/hmac_test.cpp
new file mode 100644
index 0000000..04f9356
--- /dev/null
+++ b/keymaster/hmac_test.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 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 "hmac.h"
+
+#include <gtest/gtest.h>
+#include <string.h>
+
+#include "android_keymaster_test_utils.h"
+
+using std::string;
+
+namespace keymaster {
+
+namespace test {
+
+struct HmacTest {
+ const char* data;
+ const char* key;
+ uint8_t digest[32];
+};
+
+static const HmacTest kHmacTests[] = {
+ {
+ "Test Using Larger Than Block-Size Key - Hash Key First",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "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,
+ },
+ },
+ {
+ "The test message for the MD2, MD5, and SHA-1 hashing algorithms.",
+ "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,
+ },
+ },
+};
+
+TEST(HmacTest, SHA256) {
+ for (size_t i = 0; i < 2; i++) {
+ const HmacTest& test(kHmacTests[i]);
+
+ HmacSha256 hmac;
+ const string key = hex2str(test.key);
+ Buffer key_buffer(key.data(), key.size());
+ ASSERT_TRUE(hmac.Init(key_buffer));
+
+ uint8_t digest_copy[sizeof(test.digest)];
+ memcpy(digest_copy, test.digest, sizeof(test.digest));
+ Buffer digest_buffer(reinterpret_cast<uint8_t*>(digest_copy), sizeof(digest_copy));
+
+ Buffer data_buffer(test.data, strlen(test.data));
+ EXPECT_TRUE(hmac.Verify(data_buffer, digest_buffer));
+
+ digest_copy[16] ^= 0x80;
+ digest_buffer.Reinitialize(reinterpret_cast<uint8_t*>(digest_copy), sizeof(digest_copy));
+ EXPECT_FALSE(hmac.Verify(data_buffer, digest_buffer));
+ }
+}
+
+} // namespace test
+} // namespace keymaster
diff --git a/keymaster/include/keymaster/android_keymaster.h b/keymaster/include/keymaster/android_keymaster.h
new file mode 100644
index 0000000..c7ecfad
--- /dev/null
+++ b/keymaster/include/keymaster/android_keymaster.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2014 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_ANDROID_KEYMASTER_H_
+#define SYSTEM_KEYMASTER_ANDROID_KEYMASTER_H_
+
+#include <keymaster/android_keymaster_messages.h>
+#include <keymaster/authorization_set.h>
+
+namespace keymaster {
+
+class Key;
+class KeyFactory;
+class KeymasterContext;
+class OperationTable;
+
+/**
+ * This is the reference implementation of Keymaster. In addition to acting as a reference for
+ * other Keymaster implementers to check their assumptions against, it is used by Keystore as the
+ * default implementation when no secure implementation is available, and may be installed and
+ * executed in secure hardware as a secure implementation.
+ *
+ * Note that this class doesn't actually implement the Keymaster HAL interface, instead it
+ * implements an alternative API which is similar to and based upon the HAL, but uses C++ "message"
+ * classes which support serialization.
+ *
+ * For non-secure, pure software implementation there is a HAL translation layer that converts the
+ * HAL's parameters to and from the message representations, which are then passed in to this
+ * API.
+ *
+ * For secure implementation there is another HAL translation layer that serializes the messages to
+ * the TEE. In the TEE implementation there's another component which deserializes the messages,
+ * extracts the relevant parameters and calls this API.
+ */
+class AndroidKeymaster {
+ public:
+ AndroidKeymaster(KeymasterContext* context, size_t operation_table_size);
+ virtual ~AndroidKeymaster();
+
+ void GetVersion(const GetVersionRequest& request, GetVersionResponse* response);
+ void SupportedAlgorithms(const SupportedAlgorithmsRequest& request,
+ SupportedAlgorithmsResponse* response);
+ void SupportedBlockModes(const SupportedBlockModesRequest& request,
+ SupportedBlockModesResponse* response);
+ void SupportedPaddingModes(const SupportedPaddingModesRequest& request,
+ SupportedPaddingModesResponse* response);
+ void SupportedDigests(const SupportedDigestsRequest& request,
+ SupportedDigestsResponse* response);
+ void SupportedImportFormats(const SupportedImportFormatsRequest& request,
+ SupportedImportFormatsResponse* response);
+ void SupportedExportFormats(const SupportedExportFormatsRequest& request,
+ SupportedExportFormatsResponse* response);
+
+ void AddRngEntropy(const AddEntropyRequest& request, AddEntropyResponse* response);
+ void GenerateKey(const GenerateKeyRequest& request, GenerateKeyResponse* response);
+ void GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
+ GetKeyCharacteristicsResponse* response);
+ void ImportKey(const ImportKeyRequest& request, ImportKeyResponse* response);
+ void ExportKey(const ExportKeyRequest& request, ExportKeyResponse* response);
+ void AttestKey(const AttestKeyRequest& request, AttestKeyResponse* response);
+ void DeleteKey(const DeleteKeyRequest& request, DeleteKeyResponse* response);
+ void DeleteAllKeys(const DeleteAllKeysRequest& request, DeleteAllKeysResponse* response);
+ void BeginOperation(const BeginOperationRequest& request, BeginOperationResponse* response);
+ void UpdateOperation(const UpdateOperationRequest& request, UpdateOperationResponse* response);
+ void FinishOperation(const FinishOperationRequest& request, FinishOperationResponse* response);
+ void AbortOperation(const AbortOperationRequest& request, AbortOperationResponse* response);
+
+ bool has_operation(keymaster_operation_handle_t op_handle) const;
+
+ private:
+ keymaster_error_t LoadKey(const keymaster_key_blob_t& key_blob,
+ const AuthorizationSet& additional_params,
+ AuthorizationSet* hw_enforced, AuthorizationSet* sw_enforced,
+ const KeyFactory** factory, UniquePtr<Key>* key);
+
+ UniquePtr<KeymasterContext> context_;
+ UniquePtr<OperationTable> operation_table_;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_ANDROID_KEYMASTER_H_
diff --git a/keymaster/include/keymaster/android_keymaster_messages.h b/keymaster/include/keymaster/android_keymaster_messages.h
new file mode 100644
index 0000000..30d3fb7
--- /dev/null
+++ b/keymaster/include/keymaster/android_keymaster_messages.h
@@ -0,0 +1,627 @@
+/*
+ * Copyright 2014 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_ANDROID_KEYMASTER_MESSAGES_H_
+#define SYSTEM_KEYMASTER_ANDROID_KEYMASTER_MESSAGES_H_
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/authorization_set.h>
+
+namespace keymaster {
+
+// Commands
+enum AndroidKeymasterCommand {
+ GENERATE_KEY = 0,
+ BEGIN_OPERATION = 1,
+ UPDATE_OPERATION = 2,
+ FINISH_OPERATION = 3,
+ ABORT_OPERATION = 4,
+ IMPORT_KEY = 5,
+ EXPORT_KEY = 6,
+ GET_VERSION = 7,
+ ADD_RNG_ENTROPY = 8,
+ GET_SUPPORTED_ALGORITHMS = 9,
+ GET_SUPPORTED_BLOCK_MODES = 10,
+ GET_SUPPORTED_PADDING_MODES = 11,
+ GET_SUPPORTED_DIGESTS = 12,
+ GET_SUPPORTED_IMPORT_FORMATS = 13,
+ GET_SUPPORTED_EXPORT_FORMATS = 14,
+ GET_KEY_CHARACTERISTICS = 15,
+ ATTEST_KEY = 16,
+};
+
+/**
+ * Keymaster message versions are tied to keymaster versions. We map the keymaster
+ * major.minor.subminor version to a sequential "message version".
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * Note that this approach implies that GetVersionRequest and GetVersionResponse cannot be
+ * versioned.
+ */
+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;
+ };
+ return message_version;
+}
+
+struct KeymasterMessage : public Serializable {
+ explicit KeymasterMessage(int32_t ver) : message_version(ver) { assert(ver >= 0); }
+ uint32_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.
+ */
+struct KeymasterResponse : public KeymasterMessage {
+ explicit KeymasterResponse(int32_t ver)
+ : KeymasterMessage(ver), error(KM_ERROR_UNKNOWN_ERROR) {}
+
+ 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;
+
+ virtual size_t NonErrorSerializedSize() const = 0;
+ virtual uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* end) const = 0;
+ virtual bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) = 0;
+
+ keymaster_error_t error;
+};
+
+struct SupportedAlgorithmsRequest : public KeymasterMessage {
+ explicit SupportedAlgorithmsRequest(int32_t ver = MAX_MESSAGE_VERSION)
+ : KeymasterMessage(ver) {}
+
+ size_t SerializedSize() const override { return 0; };
+ uint8_t* Serialize(uint8_t* buf, const uint8_t* /* end */) const override { return buf; }
+ bool Deserialize(const uint8_t** /* buf_ptr */, const uint8_t* /* end */) override {
+ return true;
+ }
+};
+
+struct SupportedByAlgorithmRequest : public KeymasterMessage {
+ explicit SupportedByAlgorithmRequest(int32_t ver = MAX_MESSAGE_VERSION)
+ : KeymasterMessage(ver) {}
+
+ size_t SerializedSize() const override { return sizeof(uint32_t); };
+ uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+ return append_uint32_to_buf(buf, end, algorithm);
+ }
+ bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+ return copy_uint32_from_buf(buf_ptr, end, &algorithm);
+ }
+
+ keymaster_algorithm_t algorithm;
+};
+
+struct SupportedImportFormatsRequest : public SupportedByAlgorithmRequest {
+ explicit SupportedImportFormatsRequest(int32_t ver = MAX_MESSAGE_VERSION)
+ : SupportedByAlgorithmRequest(ver) {}
+};
+
+struct SupportedExportFormatsRequest : public SupportedByAlgorithmRequest {
+ explicit SupportedExportFormatsRequest(int32_t ver = MAX_MESSAGE_VERSION)
+ : SupportedByAlgorithmRequest(ver) {}
+};
+
+struct SupportedByAlgorithmAndPurposeRequest : public KeymasterMessage {
+ explicit SupportedByAlgorithmAndPurposeRequest(int32_t ver = MAX_MESSAGE_VERSION)
+ : KeymasterMessage(ver) {}
+
+ size_t SerializedSize() const override { return sizeof(uint32_t) * 2; };
+ uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+ buf = append_uint32_to_buf(buf, end, algorithm);
+ return append_uint32_to_buf(buf, end, purpose);
+ }
+ bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+ return copy_uint32_from_buf(buf_ptr, end, &algorithm) &&
+ copy_uint32_from_buf(buf_ptr, end, &purpose);
+ }
+
+ keymaster_algorithm_t algorithm;
+ keymaster_purpose_t purpose;
+};
+
+struct SupportedBlockModesRequest : public SupportedByAlgorithmAndPurposeRequest {
+ explicit SupportedBlockModesRequest(int32_t ver = MAX_MESSAGE_VERSION)
+ : SupportedByAlgorithmAndPurposeRequest(ver) {}
+};
+
+struct SupportedPaddingModesRequest : public SupportedByAlgorithmAndPurposeRequest {
+ explicit SupportedPaddingModesRequest(int32_t ver = MAX_MESSAGE_VERSION)
+ : SupportedByAlgorithmAndPurposeRequest(ver) {}
+};
+
+struct SupportedDigestsRequest : public SupportedByAlgorithmAndPurposeRequest {
+ explicit SupportedDigestsRequest(int32_t ver = MAX_MESSAGE_VERSION)
+ : SupportedByAlgorithmAndPurposeRequest(ver) {}
+};
+
+template <typename T> struct SupportedResponse : public KeymasterResponse {
+ explicit SupportedResponse(int32_t ver = MAX_MESSAGE_VERSION)
+ : KeymasterResponse(ver), results(nullptr), results_length(0) {}
+ ~SupportedResponse() { delete[] results; }
+
+ template <size_t N> void SetResults(const T (&arr)[N]) { SetResults(arr, N); }
+
+ void SetResults(const T* arr, size_t n) {
+ delete[] results;
+ results_length = 0;
+ results = dup_array(arr, n);
+ if (results == nullptr) {
+ error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ } else {
+ results_length = n;
+ error = KM_ERROR_OK;
+ }
+ }
+
+ size_t NonErrorSerializedSize() const override {
+ return sizeof(uint32_t) + results_length * sizeof(uint32_t);
+ }
+ uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* end) const override {
+ return append_uint32_array_to_buf(buf, end, results, results_length);
+ }
+ bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+ delete[] results;
+ results = nullptr;
+ UniquePtr<T[]> tmp;
+ if (!copy_uint32_array_from_buf(buf_ptr, end, &tmp, &results_length))
+ return false;
+ results = tmp.release();
+ return true;
+ }
+
+ T* results;
+ size_t results_length;
+};
+
+struct SupportedAlgorithmsResponse : public SupportedResponse<keymaster_algorithm_t> {
+ explicit SupportedAlgorithmsResponse(int32_t ver = MAX_MESSAGE_VERSION)
+ : SupportedResponse<keymaster_algorithm_t>(ver) {}
+};
+
+struct SupportedBlockModesResponse : public SupportedResponse<keymaster_block_mode_t> {
+ explicit SupportedBlockModesResponse(int32_t ver = MAX_MESSAGE_VERSION)
+ : SupportedResponse<keymaster_block_mode_t>(ver) {}
+};
+
+struct SupportedPaddingModesResponse : public SupportedResponse<keymaster_padding_t> {
+ explicit SupportedPaddingModesResponse(int32_t ver = MAX_MESSAGE_VERSION)
+ : SupportedResponse<keymaster_padding_t>(ver) {}
+};
+
+struct SupportedDigestsResponse : public SupportedResponse<keymaster_digest_t> {
+ explicit SupportedDigestsResponse(int32_t ver = MAX_MESSAGE_VERSION)
+ : SupportedResponse<keymaster_digest_t>(ver) {}
+};
+
+struct SupportedImportFormatsResponse : public SupportedResponse<keymaster_key_format_t> {
+ explicit SupportedImportFormatsResponse(int32_t ver = MAX_MESSAGE_VERSION)
+ : SupportedResponse<keymaster_key_format_t>(ver) {}
+};
+
+struct SupportedExportFormatsResponse : public SupportedResponse<keymaster_key_format_t> {
+ explicit SupportedExportFormatsResponse(int32_t ver = MAX_MESSAGE_VERSION)
+ : SupportedResponse<keymaster_key_format_t>(ver) {}
+};
+
+struct GenerateKeyRequest : public KeymasterMessage {
+ explicit GenerateKeyRequest(int32_t ver = MAX_MESSAGE_VERSION) : 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);
+ }
+
+ AuthorizationSet key_description;
+};
+
+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();
+
+ 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;
+ AuthorizationSet enforced;
+ AuthorizationSet unenforced;
+};
+
+struct GetKeyCharacteristicsRequest : public KeymasterMessage {
+ explicit GetKeyCharacteristicsRequest(int32_t ver = MAX_MESSAGE_VERSION)
+ : KeymasterMessage(ver) {
+ key_blob.key_material = nullptr;
+ key_blob.key_material_size = 0;
+ }
+ ~GetKeyCharacteristicsRequest();
+
+ 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);
+ }
+
+ 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;
+
+ keymaster_key_blob_t key_blob;
+ AuthorizationSet additional_params;
+};
+
+struct GetKeyCharacteristicsResponse : public KeymasterResponse {
+ explicit GetKeyCharacteristicsResponse(int32_t ver = MAX_MESSAGE_VERSION)
+ : 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;
+
+ AuthorizationSet enforced;
+ AuthorizationSet unenforced;
+};
+
+struct BeginOperationRequest : public KeymasterMessage {
+ explicit BeginOperationRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {
+ key_blob.key_material = nullptr;
+ key_blob.key_material_size = 0;
+ }
+ ~BeginOperationRequest() { delete[] key_blob.key_material; }
+
+ 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);
+ }
+
+ size_t SerializedSize() const;
+ uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override;
+ bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+
+ keymaster_purpose_t purpose;
+ keymaster_key_blob_t key_blob;
+ AuthorizationSet additional_params;
+};
+
+struct BeginOperationResponse : public KeymasterResponse {
+ explicit BeginOperationResponse(int32_t ver = MAX_MESSAGE_VERSION) : 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_operation_handle_t op_handle;
+ AuthorizationSet output_params;
+};
+
+struct UpdateOperationRequest : public KeymasterMessage {
+ explicit UpdateOperationRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {}
+
+ 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;
+
+ keymaster_operation_handle_t op_handle;
+ Buffer input;
+ AuthorizationSet additional_params;
+};
+
+struct UpdateOperationResponse : public KeymasterResponse {
+ explicit UpdateOperationResponse(int32_t ver = MAX_MESSAGE_VERSION)
+ : KeymasterResponse(ver), input_consumed(0) {}
+
+ 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;
+
+ Buffer output;
+ size_t input_consumed;
+ AuthorizationSet output_params;
+};
+
+struct FinishOperationRequest : public KeymasterMessage {
+ explicit FinishOperationRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {}
+
+ 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;
+
+ keymaster_operation_handle_t op_handle;
+ Buffer input;
+ Buffer signature;
+ AuthorizationSet additional_params;
+};
+
+struct FinishOperationResponse : public KeymasterResponse {
+ explicit FinishOperationResponse(int32_t ver = MAX_MESSAGE_VERSION) : 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;
+
+ Buffer output;
+ AuthorizationSet output_params;
+};
+
+struct AbortOperationRequest : public KeymasterMessage {
+ explicit AbortOperationRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {}
+
+ size_t SerializedSize() const override { return sizeof(uint64_t); }
+ uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+ return append_uint64_to_buf(buf, end, op_handle);
+ }
+ bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+ return copy_uint64_from_buf(buf_ptr, end, &op_handle);
+ }
+
+ 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; }
+};
+
+struct AddEntropyRequest : public KeymasterMessage {
+ explicit AddEntropyRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {}
+
+ 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;
+
+ 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;
+ }
+};
+
+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);
+ }
+
+ 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;
+ keymaster_key_format_t key_format;
+ uint8_t* key_data;
+ size_t key_data_length;
+};
+
+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; }
+
+ 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);
+ }
+
+ 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;
+ AuthorizationSet enforced;
+ AuthorizationSet unenforced;
+};
+
+struct ExportKeyRequest : public KeymasterMessage {
+ explicit ExportKeyRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {
+ key_blob.key_material = nullptr;
+ key_blob.key_material_size = 0;
+ }
+ ~ExportKeyRequest() { delete[] key_blob.key_material; }
+
+ 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);
+ }
+
+ 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 additional_params;
+ keymaster_key_format_t key_format;
+ keymaster_key_blob_t key_blob;
+};
+
+struct ExportKeyResponse : public KeymasterResponse {
+ explicit ExportKeyResponse(int32_t ver = MAX_MESSAGE_VERSION)
+ : KeymasterResponse(ver), key_data(nullptr) {}
+ ~ExportKeyResponse() { 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);
+ }
+
+ 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;
+
+ uint8_t* key_data;
+ size_t key_data_length;
+};
+
+struct DeleteKeyRequest : public KeymasterMessage {
+ explicit DeleteKeyRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {
+ key_blob.key_material = nullptr;
+ key_blob.key_material_size = 0;
+ }
+ ~DeleteKeyRequest() { delete[] key_blob.key_material; }
+
+ 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);
+ }
+
+ 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;
+
+ keymaster_key_blob_t key_blob;
+};
+
+struct DeleteKeyResponse : public KeymasterResponse {
+ explicit DeleteKeyResponse(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 DeleteAllKeysRequest : public KeymasterMessage {
+ explicit DeleteAllKeysRequest(int32_t ver = MAX_MESSAGE_VERSION) : 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; };
+};
+
+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 GetVersionResponse : public KeymasterResponse {
+ GetVersionResponse()
+ : KeymasterResponse(0 /* not versionable */), major_ver(0), minor_ver(0), subminor_ver(0) {}
+
+ 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;
+
+ uint8_t major_ver;
+ uint8_t minor_ver;
+ uint8_t subminor_ver;
+};
+
+struct AttestKeyRequest : public KeymasterMessage {
+ explicit AttestKeyRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {
+ key_blob.key_material = nullptr;
+ key_blob.key_material_size = 0;
+ }
+ ~AttestKeyRequest();
+
+ 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);
+ }
+
+ 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;
+
+ keymaster_key_blob_t key_blob;
+ AuthorizationSet attest_params;
+};
+
+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);
+
+ 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;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_ANDROID_KEYMASTER_MESSAGES_H_
diff --git a/keymaster/include/keymaster/android_keymaster_utils.h b/keymaster/include/keymaster/android_keymaster_utils.h
new file mode 100644
index 0000000..c190e04
--- /dev/null
+++ b/keymaster/include/keymaster/android_keymaster_utils.h
@@ -0,0 +1,330 @@
+/*
+ * Copyright 2014 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_ANDROID_KEYMASTER_UTILS_H_
+#define SYSTEM_KEYMASTER_ANDROID_KEYMASTER_UTILS_H_
+
+#include <stdint.h>
+#include <string.h>
+#include <time.h> // for time_t.
+
+#include <UniquePtr.h>
+
+#include <hardware/keymaster_defs.h>
+#include <keymaster/serializable.h>
+
+namespace keymaster {
+
+/**
+ * Convert the specified time value into "Java time", which is a signed 64-bit integer representing
+ * elapsed milliseconds since Jan 1, 1970.
+ */
+inline int64_t java_time(time_t time) {
+ // The exact meaning of a time_t value is implementation-dependent. If this code is ported to a
+ // platform that doesn't define it as "seconds since Jan 1, 1970 UTC", this function will have
+ // to be revised.
+ return 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);
+}
+
+/**
+ * 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
+ * efficient implementation, but the compiler should unroll the loop and tighten it up.
+ */
+template <typename T> T ntoh(T t) {
+ const uint8_t* byte_ptr = reinterpret_cast<const uint8_t*>(&t);
+ T retval = 0;
+ for (size_t i = 0; i < sizeof(t); ++i) {
+ retval <<= 8;
+ retval |= byte_ptr[i];
+ }
+ return retval;
+}
+
+/**
+ * Convert any unsigned integer from host to network 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
+ * efficient implementation, but the compiler should unroll the loop and tighten it up.
+ */
+template <typename T> T hton(T t) {
+ T retval;
+ uint8_t* byte_ptr = reinterpret_cast<uint8_t*>(&retval);
+ for (size_t i = sizeof(t); i > 0; --i) {
+ byte_ptr[i - 1] = t & 0xFF;
+ t >>= 8;
+ }
+ return retval;
+}
+
+/**
+ * KeymasterKeyBlob is a very simple extension of the C struct keymaster_key_blob_t. It manages its
+ * own memory, which makes avoiding memory leaks much easier.
+ */
+struct KeymasterKeyBlob : public keymaster_key_blob_t {
+ KeymasterKeyBlob() {
+ key_material = nullptr;
+ key_material_size = 0;
+ }
+
+ KeymasterKeyBlob(const uint8_t* data, size_t size) {
+ key_material_size = 0;
+ key_material = dup_buffer(data, size);
+ if (key_material)
+ key_material_size = size;
+ }
+
+ explicit KeymasterKeyBlob(size_t size) {
+ key_material_size = 0;
+ key_material = new (std::nothrow) uint8_t[size];
+ if (key_material)
+ key_material_size = size;
+ }
+
+ explicit KeymasterKeyBlob(const keymaster_key_blob_t& blob) {
+ key_material_size = 0;
+ key_material = dup_buffer(blob.key_material, blob.key_material_size);
+ if (key_material)
+ key_material_size = blob.key_material_size;
+ }
+
+ KeymasterKeyBlob(const KeymasterKeyBlob& blob) {
+ key_material_size = 0;
+ key_material = dup_buffer(blob.key_material, blob.key_material_size);
+ if (key_material)
+ key_material_size = blob.key_material_size;
+ }
+
+ void operator=(const KeymasterKeyBlob& blob) {
+ Clear();
+ key_material = dup_buffer(blob.key_material, blob.key_material_size);
+ key_material_size = blob.key_material_size;
+ }
+
+ ~KeymasterKeyBlob() { Clear(); }
+
+ const uint8_t* begin() const { return key_material; }
+ const uint8_t* end() const { return key_material + key_material_size; }
+
+ void Clear() {
+ memset_s(const_cast<uint8_t*>(key_material), 0, key_material_size);
+ delete[] key_material;
+ key_material = nullptr;
+ key_material_size = 0;
+ }
+
+ const uint8_t* Reset(size_t new_size) {
+ Clear();
+ key_material = new (std::nothrow) uint8_t[new_size];
+ if (key_material)
+ key_material_size = new_size;
+ return key_material;
+ }
+
+ // The key_material in keymaster_key_blob_t is const, which is the right thing in most
+ // circumstances, but occasionally we do need to write into it. This method exposes a non-const
+ // version of the pointer. Use sparingly.
+ uint8_t* writable_data() { return const_cast<uint8_t*>(key_material); }
+
+ keymaster_key_blob_t release() {
+ keymaster_key_blob_t tmp = {key_material, key_material_size};
+ key_material = nullptr;
+ key_material_size = 0;
+ return tmp;
+ }
+
+ size_t SerializedSize() const { return sizeof(uint32_t) + key_material_size; }
+ uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const {
+ return append_size_and_data_to_buf(buf, end, key_material, key_material_size);
+ }
+
+ bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+ Clear();
+ UniquePtr<uint8_t[]> tmp;
+ if (!copy_size_and_data_from_buf(buf_ptr, end, &key_material_size, &tmp)) {
+ key_material = nullptr;
+ key_material_size = 0;
+ return false;
+ }
+ key_material = tmp.release();
+ return true;
+ }
+};
+
+struct Characteristics_Delete {
+ void operator()(keymaster_key_characteristics_t* p) {
+ keymaster_free_characteristics(p);
+ free(p);
+ }
+};
+
+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;
+ }
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_ANDROID_KEYMASTER_UTILS_H_
diff --git a/keymaster/include/keymaster/asymmetric_key_factory.h b/keymaster/include/keymaster/asymmetric_key_factory.h
new file mode 100644
index 0000000..afcfc1c
--- /dev/null
+++ b/keymaster/include/keymaster/asymmetric_key_factory.h
@@ -0,0 +1,51 @@
+/*
+ * 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_ASYMMETRIC_KEY_FACTORY_H_
+#define SYSTEM_KEYMASTER_ASYMMETRIC_KEY_FACTORY_H_
+
+#include <keymaster/key_factory.h>
+
+namespace keymaster {
+
+/**
+ * Abstract base for KeyFactories that handle asymmetric keys.
+ */
+class AsymmetricKey;
+class AsymmetricKeyFactory : public KeyFactory {
+ public:
+ explicit AsymmetricKeyFactory(const KeymasterContext* context) : KeyFactory(context) {}
+
+ keymaster_error_t LoadKey(const KeymasterKeyBlob& key_material,
+ const AuthorizationSet& additional_params,
+ const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ UniquePtr<Key>* key) const override;
+
+ virtual keymaster_error_t CreateEmptyKey(const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ UniquePtr<AsymmetricKey>* key) const = 0;
+
+ 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;
+ virtual const keymaster_key_format_t* SupportedExportFormats(size_t* format_count) const;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_ASYMMETRIC_KEY_FACTORY_H_
diff --git a/keymaster/include/keymaster/authorization_set.h b/keymaster/include/keymaster/authorization_set.h
new file mode 100644
index 0000000..74daa8d
--- /dev/null
+++ b/keymaster/include/keymaster/authorization_set.h
@@ -0,0 +1,570 @@
+/*
+ * Copyright 2014 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_AUTHORIZATION_SET_H_
+#define SYSTEM_KEYMASTER_AUTHORIZATION_SET_H_
+
+#include <UniquePtr.h>
+
+#include <hardware/keymaster_defs.h>
+#include <keymaster/keymaster_tags.h>
+#include <keymaster/serializable.h>
+
+namespace keymaster {
+
+class AuthorizationSetBuilder;
+
+/**
+ * An extension of the keymaster_key_param_set_t struct, which provides serialization memory
+ * management and methods for easy manipulation and construction.
+ */
+class AuthorizationSet : public Serializable, public keymaster_key_param_set_t {
+ public:
+ /**
+ * Construct an empty, dynamically-allocated, growable AuthorizationSet. Does not actually
+ * allocate any storage until elements are added, so there is no cost to creating an
+ * AuthorizationSet with this constructor and then reinitializing it to point at pre-allocated
+ * buffers, with \p Reinitialize.
+ */
+ AuthorizationSet()
+ : elems_capacity_(0), indirect_data_(NULL), indirect_data_size_(0),
+ indirect_data_capacity_(0), error_(OK) {
+ elems_ = nullptr;
+ elems_size_ = 0;
+ }
+
+ /**
+ * Construct an AuthorizationSet from the provided array. The AuthorizationSet copies the data
+ * from the provided array (and the data referenced by its embedded pointers, if any) into
+ * dynamically-allocated storage. If allocation of the needed storage fails, \p is_valid() will
+ * return ALLOCATION_FAILURE. It is the responsibility of the caller to check before using the
+ * set, if allocations might fail.
+ */
+ AuthorizationSet(const keymaster_key_param_t* elems, size_t count) : indirect_data_(nullptr) {
+ elems_ = nullptr;
+ Reinitialize(elems, count);
+ }
+
+ explicit AuthorizationSet(const keymaster_key_param_set_t& set) : indirect_data_(nullptr) {
+ elems_ = nullptr;
+ Reinitialize(set.params, set.length);
+ }
+
+ explicit AuthorizationSet(const uint8_t* serialized_set, size_t serialized_size)
+ : indirect_data_(nullptr) {
+ elems_ = nullptr;
+ Deserialize(&serialized_set, serialized_set + serialized_size);
+ }
+
+ /**
+ * Construct an AuthorizationSet from the provided builder. This extracts the data from the
+ * builder, rather than copying it, so after this call the builder is empty.
+ */
+ explicit AuthorizationSet(/* NOT const */ AuthorizationSetBuilder& builder);
+
+ // Copy constructor.
+ AuthorizationSet(const AuthorizationSet& set) : Serializable(), indirect_data_(nullptr) {
+ elems_ = nullptr;
+ Reinitialize(set.elems_, set.elems_size_);
+ }
+
+ /**
+ * Clear existing authorization set data
+ */
+ void Clear();
+
+ /**
+ * Reinitialize an AuthorizationSet as a dynamically-allocated, growable copy of the data in the
+ * provided array (and the data referenced by its embedded pointers, if any). If the allocation
+ * of the needed storage fails this method will return false and \p is_valid() will return
+ * ALLOCATION_FAILURE.
+ */
+ bool Reinitialize(const keymaster_key_param_t* elems, size_t count);
+
+ bool Reinitialize(const AuthorizationSet& set) {
+ return Reinitialize(set.elems_, set.elems_size_);
+ }
+
+ bool Reinitialize(const keymaster_key_param_set_t& set) {
+ return Reinitialize(set.params, set.length);
+ }
+
+ ~AuthorizationSet();
+
+ enum Error {
+ OK,
+ ALLOCATION_FAILURE,
+ MALFORMED_DATA,
+ };
+
+ Error is_valid() const { return error_; }
+
+ /**
+ * Returns the size of the set.
+ */
+ size_t size() const { return elems_size_; }
+
+ /**
+ * Returns true if the set is empty.
+ */
+ bool empty() const { return size() == 0; }
+
+ /**
+ * Returns the total size of all indirect data referenced by set elements.
+ */
+ size_t indirect_size() const { return indirect_data_size_; }
+
+ /**
+ * Returns the data in the set, directly. Be careful with this.
+ */
+ const keymaster_key_param_t* data() const { return elems_; }
+
+ /**
+ * Sorts the set
+ */
+ void Sort();
+
+ /**
+ * Sorts the set and removes duplicates (inadvertently duplicating tags is easy to do with the
+ * AuthorizationSetBuilder).
+ */
+ void Deduplicate();
+
+ /**
+ * Returns the data in a keymaster_key_param_set_t, suitable for returning to C code. For C
+ * compatibility, the contents are malloced, not new'ed, and so must be freed with free(), or
+ * better yet with keymaster_free_param_set, not delete. The caller takes ownership.
+ */
+ void CopyToParamSet(keymaster_key_param_set_t* set) const;
+
+ /**
+ * Returns the offset of the next entry that matches \p tag, starting from the element after \p
+ * begin. If not found, returns -1.
+ */
+ int find(keymaster_tag_t tag, int begin = -1) const;
+
+ /**
+ * Removes the entry at the specified index. Returns true if successful, false if the index was
+ * out of bounds.
+ */
+ bool erase(size_t index);
+
+ /**
+ * Returns iterator (pointer) to beginning of elems array, to enable STL-style iteration
+ */
+ const keymaster_key_param_t* begin() const { return elems_; }
+
+ /**
+ * Returns iterator (pointer) one past end of elems array, to enable STL-style iteration
+ */
+ const keymaster_key_param_t* end() const { return elems_ + elems_size_; }
+
+ /**
+ * Returns the nth element of the set.
+ */
+ keymaster_key_param_t& operator[](int n);
+
+ /**
+ * Returns the nth element of the set.
+ */
+ keymaster_key_param_t operator[](int n) const;
+
+ /**
+ * Returns the number of \p tag entries.
+ */
+ size_t GetTagCount(keymaster_tag_t tag) const;
+
+ /**
+ * Returns true if the set contains the specified tag and value.
+ */
+ template <keymaster_tag_t Tag, typename T>
+ bool Contains(TypedEnumTag<KM_ENUM_REP, Tag, T> tag, T val) const {
+ return ContainsEnumValue(tag, val);
+ }
+
+ /**
+ * Returns true if the set contains the specified tag and value.
+ */
+ template <keymaster_tag_t Tag, typename T>
+ bool Contains(TypedEnumTag<KM_ENUM, Tag, T> tag, T val) const {
+ return ContainsEnumValue(tag, val);
+ }
+
+ /**
+ * If the specified integer-typed \p tag exists, places its value in \p val and returns true.
+ * If \p tag is not present, leaves \p val unmodified and returns false.
+ */
+ template <keymaster_tag_t T>
+ inline bool GetTagValue(TypedTag<KM_UINT, T> tag, uint32_t* val) const {
+ return GetTagValueInt(tag, val);
+ }
+
+ /**
+ * If the specified instance of the specified integer-typed \p tag exists, places its value
+ * in \p val and returns true. If \p tag is not present, leaves \p val unmodified and returns
+ * false.
+ */
+ template <keymaster_tag_t Tag>
+ bool GetTagValue(TypedTag<KM_UINT_REP, Tag> tag, size_t instance, uint32_t* val) const {
+ return GetTagValueIntRep(tag, instance, val);
+ }
+
+ /**
+ * If the specified long-typed \p tag exists, places its value in \p val and returns true.
+ * If \p tag is not present, leaves \p val unmodified and returns false.
+ */
+ template <keymaster_tag_t T>
+ inline bool GetTagValue(TypedTag<KM_ULONG, T> tag, uint64_t* val) const {
+ return GetTagValueLong(tag, val);
+ }
+
+ /**
+ * If the specified instance of the specified integer-typed \p tag exists, places its value
+ * in \p val and returns true. If \p tag is not present, leaves \p val unmodified and returns
+ * false.
+ */
+ template <keymaster_tag_t Tag>
+ bool GetTagValue(TypedTag<KM_ULONG_REP, Tag> tag, size_t instance, uint64_t* val) const {
+ return GetTagValueLongRep(tag, instance, val);
+ }
+
+ /**
+ * If the specified enumeration-typed \p tag exists, places its value in \p val and returns
+ * true. If \p tag is not present, leaves \p val unmodified and returns false.
+ */
+ template <keymaster_tag_t Tag, typename T>
+ bool GetTagValue(TypedEnumTag<KM_ENUM, Tag, T> tag, T* val) const {
+ return GetTagValueEnum(tag, reinterpret_cast<uint32_t*>(val));
+ }
+
+ /**
+ * If the specified instance of the specified enumeration-typed \p tag exists, places its value
+ * in \p val and returns true. If \p tag is not present, leaves \p val unmodified and returns
+ * false.
+ */
+ template <keymaster_tag_t Tag, typename T>
+ bool GetTagValue(TypedEnumTag<KM_ENUM_REP, Tag, T> tag, size_t instance, T* val) const {
+ return GetTagValueEnumRep(tag, instance, reinterpret_cast<uint32_t*>(val));
+ }
+
+ /**
+ * If exactly one instance of the specified enumeration-typed \p tag exists, places its value in
+ * \p val and returns true. If \p tag is not present or if multiple copies are present, leaves
+ * \p val unmodified and returns false.
+ */
+ 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;
+ return GetTagValueEnumRep(tag, 0, reinterpret_cast<uint32_t*>(val));
+ }
+
+ /**
+ * If the specified date-typed \p tag exists, places its value in \p val and returns
+ * true. If \p tag is not present, leaves \p val unmodified and returns false.
+ */
+ template <keymaster_tag_t Tag>
+ bool GetTagValue(TypedTag<KM_UINT_REP, Tag> tag, size_t instance,
+ typename TypedTag<KM_UINT_REP, Tag>::value_type* val) const {
+ return GetTagValueIntRep(tag, instance, val);
+ }
+
+ /**
+ * If the specified bytes-typed \p tag exists, places its value in \p val and returns
+ * true. If \p tag is not present, leaves \p val unmodified and returns false.
+ */
+ template <keymaster_tag_t Tag>
+ bool GetTagValue(TypedTag<KM_BYTES, Tag> tag, keymaster_blob_t* val) const {
+ return GetTagValueBlob(tag, val);
+ }
+
+ /**
+ * If the specified bignum-typed \p tag exists, places its value in \p val and returns
+ * true. If \p tag is not present, leaves \p val unmodified and returns false.
+ */
+ template <keymaster_tag_t Tag>
+ bool GetTagValue(TypedTag<KM_BIGNUM, Tag> tag, keymaster_blob_t* val) const {
+ return GetTagValueBlob(tag, val);
+ }
+
+ /**
+ * Returns true if the specified tag is present, and therefore has the value 'true'.
+ */
+ template <keymaster_tag_t Tag> bool GetTagValue(TypedTag<KM_BOOL, Tag> tag) const {
+ return GetTagValueBool(tag);
+ }
+
+ /**
+ * If the specified \p tag exists, places its value in \p val and returns true. If \p tag is
+ * not present, leaves \p val unmodified and returns false.
+ */
+ template <keymaster_tag_t Tag, keymaster_tag_type_t Type>
+ bool GetTagValue(TypedTag<Type, Tag> tag, typename TagValueType<Type>::value_type* val) const {
+ return GetTagValueLong(tag, val);
+ }
+
+ bool push_back(keymaster_key_param_t elem);
+
+ /**
+ * Grow the elements array to ensure it can contain \p count entries. Preserves any existing
+ * entries.
+ */
+ bool reserve_elems(size_t count);
+
+ /**
+ * Grow the indirect data array to ensure it can contain \p length bytes. Preserves any
+ * existing indirect data.
+ */
+ bool reserve_indirect(size_t length);
+
+ bool push_back(const keymaster_key_param_set_t& set);
+
+ /**
+ * Append the tag and enumerated value to the set.
+ */
+ template <keymaster_tag_t Tag, keymaster_tag_type_t Type, typename KeymasterEnum>
+ bool push_back(TypedEnumTag<Type, Tag, KeymasterEnum> tag, KeymasterEnum val) {
+ return push_back(Authorization(tag, val));
+ }
+
+ /**
+ * Append the boolean tag (value "true") to the set.
+ */
+ template <keymaster_tag_t Tag> bool push_back(TypedTag<KM_BOOL, Tag> tag) {
+ return push_back(Authorization(tag));
+ }
+
+ /**
+ * Append the tag and byte array to the set. Copies the array into internal storage; does not
+ * take ownership of the passed-in array.
+ */
+ template <keymaster_tag_t Tag>
+ bool push_back(TypedTag<KM_BYTES, Tag> tag, const void* bytes, size_t bytes_len) {
+ return push_back(keymaster_param_blob(tag, static_cast<const uint8_t*>(bytes), bytes_len));
+ }
+
+ /**
+ * Append the tag and blob to the set. Copies the blob contents into internal storage; does not
+ * take ownership of the blob's data.
+ */
+ template <keymaster_tag_t Tag>
+ bool push_back(TypedTag<KM_BYTES, Tag> tag, const keymaster_blob_t& blob) {
+ return push_back(tag, blob.data, blob.data_length);
+ }
+
+ /**
+ * Append the tag and bignum array to the set. Copies the array into internal storage; does not
+ * take ownership of the passed-in array.
+ */
+ template <keymaster_tag_t Tag>
+ bool push_back(TypedTag<KM_BIGNUM, Tag> tag, const void* bytes, size_t bytes_len) {
+ return push_back(keymaster_param_blob(tag, static_cast<const uint8_t*>(bytes), bytes_len));
+ }
+
+ template <keymaster_tag_t Tag, keymaster_tag_type_t Type>
+ bool push_back(TypedTag<Type, Tag> tag, typename TypedTag<Type, Tag>::value_type val) {
+ return push_back(Authorization(tag, val));
+ }
+
+ template <keymaster_tag_t Tag, keymaster_tag_type_t Type>
+ bool push_back(TypedTag<Type, Tag> tag, const void* bytes, size_t bytes_len) {
+ return push_back(Authorization(tag, bytes, bytes_len));
+ }
+
+ /* Virtual methods from Serializable */
+ size_t SerializedSize() const;
+ uint8_t* Serialize(uint8_t* serialized_set, const uint8_t* end) const;
+ bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end);
+
+ size_t SerializedSizeOfElements() const;
+
+ private:
+ // Disallow assignment
+ void operator=(const AuthorizationSet&);
+
+ void FreeData();
+ void set_invalid(Error err);
+
+ static size_t ComputeIndirectDataSize(const keymaster_key_param_t* elems, size_t count);
+ void CopyIndirectData();
+ bool CheckIndirectData();
+
+ bool DeserializeIndirectData(const uint8_t** buf_ptr, const uint8_t* end);
+ bool DeserializeElementsData(const uint8_t** buf_ptr, const uint8_t* end);
+
+ bool GetTagValueEnum(keymaster_tag_t tag, uint32_t* val) const;
+ bool GetTagValueEnumRep(keymaster_tag_t tag, size_t instance, uint32_t* val) const;
+ bool GetTagValueInt(keymaster_tag_t tag, uint32_t* val) const;
+ bool GetTagValueIntRep(keymaster_tag_t tag, size_t instance, uint32_t* val) const;
+ bool GetTagValueLong(keymaster_tag_t tag, uint64_t* val) const;
+ bool GetTagValueLongRep(keymaster_tag_t tag, size_t instance, uint64_t* val) const;
+ bool GetTagValueDate(keymaster_tag_t tag, uint64_t* val) const;
+ bool GetTagValueBlob(keymaster_tag_t tag, keymaster_blob_t* val) const;
+ bool GetTagValueBool(keymaster_tag_t tag) const;
+
+ bool ContainsEnumValue(keymaster_tag_t tag, uint32_t val) const;
+
+ // Define elems_ and elems_size_ as aliases to params and length, respectivley. This is to
+ // avoid using the variables without the trailing underscore in the implementation.
+ keymaster_key_param_t*& elems_ = keymaster_key_param_set_t::params;
+ size_t& elems_size_ = keymaster_key_param_set_t::length;
+
+ size_t elems_capacity_;
+ uint8_t* indirect_data_;
+ size_t indirect_data_size_;
+ size_t indirect_data_capacity_;
+ Error error_;
+};
+
+class AuthorizationSetBuilder {
+ public:
+ template <typename TagType, typename ValueType>
+ AuthorizationSetBuilder& Authorization(TagType tag, ValueType value) {
+ set.push_back(tag, value);
+ return *this;
+ }
+
+ template <keymaster_tag_t Tag>
+ AuthorizationSetBuilder& Authorization(TypedTag<KM_BOOL, Tag> tag) {
+ set.push_back(tag);
+ return *this;
+ }
+
+ template <keymaster_tag_t Tag>
+ AuthorizationSetBuilder& Authorization(TypedTag<KM_INVALID, Tag> tag) {
+ keymaster_key_param_t param;
+ param.tag = tag;
+ set.push_back(param);
+ return *this;
+ }
+
+ template <keymaster_tag_t Tag>
+ AuthorizationSetBuilder& Authorization(TypedTag<KM_BYTES, Tag> tag, const uint8_t* data,
+ size_t data_length) {
+ set.push_back(tag, data, data_length);
+ return *this;
+ }
+
+ template <keymaster_tag_t Tag>
+ AuthorizationSetBuilder& Authorization(TypedTag<KM_BYTES, Tag> tag, const char* data,
+ size_t data_length) {
+ return Authorization(tag, reinterpret_cast<const uint8_t*>(data), data_length);
+ }
+
+ AuthorizationSetBuilder& RsaKey(uint32_t key_size, uint64_t public_exponent);
+ AuthorizationSetBuilder& EcdsaKey(uint32_t key_size);
+ AuthorizationSetBuilder& AesKey(uint32_t key_size);
+ AuthorizationSetBuilder& HmacKey(uint32_t key_size);
+
+ AuthorizationSetBuilder& RsaSigningKey(uint32_t key_size, uint64_t public_exponent);
+ AuthorizationSetBuilder& RsaEncryptionKey(uint32_t key_size, uint64_t public_exponent);
+ AuthorizationSetBuilder& EcdsaSigningKey(uint32_t key_size);
+ AuthorizationSetBuilder& AesEncryptionKey(uint32_t key_size);
+
+ AuthorizationSetBuilder& SigningKey();
+ AuthorizationSetBuilder& EncryptionKey();
+ AuthorizationSetBuilder& NoDigestOrPadding();
+ AuthorizationSetBuilder& EcbMode();
+
+ AuthorizationSetBuilder& Digest(keymaster_digest_t digest) {
+ return Authorization(TAG_DIGEST, digest);
+ }
+
+ AuthorizationSetBuilder& Padding(keymaster_padding_t padding) {
+ return Authorization(TAG_PADDING, padding);
+ }
+
+ AuthorizationSetBuilder& Deduplicate() {
+ set.Deduplicate();
+ return *this;
+ }
+
+ AuthorizationSet build() const { return set; }
+
+ private:
+ friend AuthorizationSet;
+ AuthorizationSet set;
+};
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::RsaKey(uint32_t key_size,
+ uint64_t public_exponent) {
+ Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA);
+ Authorization(TAG_KEY_SIZE, key_size);
+ Authorization(TAG_RSA_PUBLIC_EXPONENT, public_exponent);
+ return *this;
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaKey(uint32_t key_size) {
+ Authorization(TAG_ALGORITHM, KM_ALGORITHM_EC);
+ Authorization(TAG_KEY_SIZE, key_size);
+ return *this;
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::AesKey(uint32_t key_size) {
+ Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES);
+ return Authorization(TAG_KEY_SIZE, key_size);
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::HmacKey(uint32_t key_size) {
+ Authorization(TAG_ALGORITHM, KM_ALGORITHM_HMAC);
+ Authorization(TAG_KEY_SIZE, key_size);
+ return SigningKey();
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::RsaSigningKey(uint32_t key_size,
+ uint64_t public_exponent) {
+ RsaKey(key_size, public_exponent);
+ return SigningKey();
+}
+
+inline AuthorizationSetBuilder&
+AuthorizationSetBuilder::RsaEncryptionKey(uint32_t key_size, uint64_t public_exponent) {
+ RsaKey(key_size, public_exponent);
+ return EncryptionKey();
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaSigningKey(uint32_t key_size) {
+ EcdsaKey(key_size);
+ return SigningKey();
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::AesEncryptionKey(uint32_t key_size) {
+ AesKey(key_size);
+ return EncryptionKey();
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::SigningKey() {
+ Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN);
+ return Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY);
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::EncryptionKey() {
+ Authorization(TAG_PURPOSE, KM_PURPOSE_ENCRYPT);
+ return Authorization(TAG_PURPOSE, KM_PURPOSE_DECRYPT);
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::NoDigestOrPadding() {
+ Authorization(TAG_DIGEST, KM_DIGEST_NONE);
+ return Authorization(TAG_PADDING, KM_PAD_NONE);
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcbMode() {
+ return Authorization(TAG_BLOCK_MODE, KM_MODE_ECB);
+}
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_KEY_AUTHORIZATION_SET_H_
diff --git a/keymaster/include/keymaster/ec_key_factory.h b/keymaster/include/keymaster/ec_key_factory.h
new file mode 100644
index 0000000..aaeb548
--- /dev/null
+++ b/keymaster/include/keymaster/ec_key_factory.h
@@ -0,0 +1,60 @@
+/*
+ * 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_KEY_FACTORY_H_
+#define SYSTEM_KEYMASTER_EC_KEY_FACTORY_H_
+
+#include <openssl/ec.h>
+#include <openssl/evp.h>
+
+#include <keymaster/asymmetric_key_factory.h>
+
+namespace keymaster {
+
+class EcKeyFactory : public AsymmetricKeyFactory {
+ public:
+ explicit EcKeyFactory(const KeymasterContext* context) : AsymmetricKeyFactory(context) {}
+
+ 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;
+ 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 CreateEmptyKey(const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ UniquePtr<AsymmetricKey>* key) const override;
+
+ keymaster_error_t UpdateImportKeyDescription(const AuthorizationSet& key_description,
+ keymaster_key_format_t key_format,
+ const KeymasterKeyBlob& key_material,
+ AuthorizationSet* updated_description,
+ uint32_t* key_size) const;
+
+ OperationFactory* GetOperationFactory(keymaster_purpose_t purpose) const override;
+
+ static EC_GROUP* choose_group(size_t key_size_bits);
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_EC_KEY_FACTORY_H_
diff --git a/keymaster/include/keymaster/key_factory.h b/keymaster/include/keymaster/key_factory.h
new file mode 100644
index 0000000..18f69c4
--- /dev/null
+++ b/keymaster/include/keymaster/key_factory.h
@@ -0,0 +1,69 @@
+/*
+ * 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_KEY_FACTORY_H_
+#define SYSTEM_KEYMASTER_KEY_FACTORY_H_
+
+#include <hardware/keymaster_defs.h>
+#include <keymaster/authorization_set.h>
+
+namespace keymaster {
+
+class Key;
+class KeymasterContext;
+class OperationFactory;
+struct KeymasterKeyBlob;
+
+/**
+ * KeyFactory is a abstraction that encapsulats the knowledge of how to build and parse a specifiec
+ * subclass of Key.
+ */
+class KeyFactory {
+ public:
+ explicit KeyFactory(const KeymasterContext* context) : context_(context) {}
+ virtual ~KeyFactory() {}
+
+ // Factory methods.
+ virtual keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
+ KeymasterKeyBlob* key_blob, 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 LoadKey(const KeymasterKeyBlob& key_material,
+ const AuthorizationSet& additional_params,
+ const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ UniquePtr<Key>* key) const = 0;
+
+ virtual OperationFactory* GetOperationFactory(keymaster_purpose_t purpose) const = 0;
+
+ // Informational methods.
+ virtual const keymaster_key_format_t* SupportedImportFormats(size_t* format_count) const = 0;
+ virtual const keymaster_key_format_t* SupportedExportFormats(size_t* format_count) const = 0;
+
+ protected:
+ const KeymasterContext* context_;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_KEY_FACTORY_H_
diff --git a/keymaster/include/keymaster/keymaster_context.h b/keymaster/include/keymaster/keymaster_context.h
new file mode 100644
index 0000000..c9802e4
--- /dev/null
+++ b/keymaster/include/keymaster/keymaster_context.h
@@ -0,0 +1,154 @@
+/*
+ * 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_KEYMASTER_CONTEXT_H_
+#define SYSTEM_KEYMASTER_KEYMASTER_CONTEXT_H_
+
+#include <assert.h>
+
+#include <openssl/evp.h>
+
+#include <hardware/keymaster_defs.h>
+#include <keymaster/keymaster_enforcement.h>
+
+namespace keymaster {
+
+class AuthorizationSet;
+class KeyFactory;
+class OperationFactory;
+struct KeymasterKeyBlob;
+
+/**
+ * KeymasterContext provides a singleton abstract interface that encapsulates various
+ * environment-dependent elements of AndroidKeymaster.
+ *
+ * AndroidKeymaster runs in multiple contexts. Primarily:
+ *
+ * - In a trusted execution environment (TEE) as a "secure hardware" implementation. In this
+ * context keys are wrapped with an master key that never leaves the TEE, TEE-specific routines
+ * are used for random number generation, all AndroidKeymaster-enforced authorizations are
+ * considered hardware-enforced, and there's a bootloader-provided root of trust.
+ *
+ * - In the non-secure world as a software-only implementation. In this context keys are not
+ * encrypted (though they are integrity-checked) because there is no place to securely store a
+ * key, OpenSSL is used for random number generation, no AndroidKeymaster-enforced authorizations
+ * are considered hardware enforced and the root of trust is a static string.
+ *
+ * - In the non-secure world as a hybrid implementation fronting a less-capable hardware
+ * implementation. For example, a keymaster0 hardware implementation. In this context keys are
+ * not encrypted by AndroidKeymaster, but some may be opaque blobs provided by the backing
+ * hardware, but blobs that lack the extended authorization lists of keymaster1. In addition,
+ * keymaster0 lacks many features of keymaster1, including modes of operation related to the
+ * backing keymaster0 keys. AndroidKeymaster must extend the blobs to add authorization lists,
+ * and must provide the missing operation mode implementations in software, which means that
+ * authorization lists are partially hardware-enforced (the bits that are enforced by the
+ * underlying keymaster0) and partially software-enforced (the rest). OpenSSL is used for number
+ * generation and the root of trust is a static string.
+ *
+ * More contexts are possible.
+ */
+class KeymasterContext {
+ public:
+ KeymasterContext() {}
+ virtual ~KeymasterContext(){};
+
+ virtual KeyFactory* GetKeyFactory(keymaster_algorithm_t algorithm) const = 0;
+ virtual OperationFactory* GetOperationFactory(keymaster_algorithm_t algorithm,
+ keymaster_purpose_t purpose) const = 0;
+ virtual keymaster_algorithm_t* GetSupportedAlgorithms(size_t* algorithms_count) const = 0;
+
+ /**
+ * CreateKeyBlob takes authorization sets and key material and produces a key blob and hardware
+ * and software authorization lists ready to be returned to the AndroidKeymaster client
+ * (Keystore, generally). The blob is integrity-checked and may be encrypted, depending on the
+ * needs of the context.
+ *
+ * This method is generally called only by KeyFactory subclassses.
+ */
+ virtual keymaster_error_t CreateKeyBlob(const AuthorizationSet& key_description,
+ keymaster_key_origin_t origin,
+ const KeymasterKeyBlob& key_material,
+ KeymasterKeyBlob* blob, AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) const = 0;
+
+ /**
+ * ParseKeyBlob takes a blob and extracts authorization sets and key material, returning an
+ * error if the blob fails integrity checking or decryption. Note that the returned key
+ * material may itself be an opaque blob usable only by secure hardware (in the hybrid case).
+ *
+ * This method is called by AndroidKeymaster.
+ */
+ virtual keymaster_error_t ParseKeyBlob(const KeymasterKeyBlob& blob,
+ const AuthorizationSet& additional_params,
+ KeymasterKeyBlob* key_material,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) const = 0;
+
+ /**
+ * Take whatever environment-specific action is appropriate (if any) to delete the specified
+ * key.
+ */
+ virtual keymaster_error_t DeleteKey(const KeymasterKeyBlob& /* blob */) const {
+ return KM_ERROR_OK;
+ }
+
+ /**
+ * Take whatever environment-specific action is appropriate to delete all keys.
+ */
+ virtual keymaster_error_t DeleteAllKeys() const { return KM_ERROR_OK; }
+
+ /**
+ * Adds entropy to the Cryptographic Pseudo Random Number Generator used to generate key
+ * material, and other cryptographic protocol elements. Note that if the underlying CPRNG
+ * tracks the size of its entropy pool, it should not assume that the provided data contributes
+ * any entropy, and it should also ensure that data provided through this interface cannot
+ * "poison" the CPRNG outputs, making them predictable.
+ */
+ virtual keymaster_error_t AddRngEntropy(const uint8_t* buf, size_t length) const = 0;
+
+ /**
+ * Generates \p length random bytes, placing them in \p buf.
+ */
+ virtual keymaster_error_t GenerateRandom(uint8_t* buf, size_t length) const = 0;
+
+ /**
+ * Return the enforcement policy for this context, or null if no enforcement should be done.
+ */
+ virtual KeymasterEnforcement* enforcement_policy() = 0;
+
+ /**
+ * Return the attestation signing key of the specified algorithm (KM_ALGORITHM_RSA or
+ * KM_ALGORITHM_EC).
+ */
+ virtual EVP_PKEY* AttestationKey(keymaster_algorithm_t algorithm,
+ keymaster_error_t* error) const = 0;
+
+ /**
+ * Return the certificate chain of the attestation signing key of the specified algorithm
+ * (KM_ALGORITHM_RSA or KM_ALGORITHM_EC).
+ */
+ virtual keymaster_cert_chain_t* AttestationChain(keymaster_algorithm_t algorithm,
+ keymaster_error_t* error) const = 0;
+
+ private:
+ // Uncopyable.
+ KeymasterContext(const KeymasterContext&);
+ void operator=(const KeymasterContext&);
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_KEYMASTER_CONTEXT_H_
diff --git a/keymaster/include/keymaster/keymaster_enforcement.h b/keymaster/include/keymaster/keymaster_enforcement.h
new file mode 100644
index 0000000..69ef5e3
--- /dev/null
+++ b/keymaster/include/keymaster/keymaster_enforcement.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2014 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 ANDROID_LIBRARY_KEYMASTER_ENFORCEMENT_H
+#define ANDROID_LIBRARY_KEYMASTER_ENFORCEMENT_H
+
+#include <stdio.h>
+
+#include <keymaster/authorization_set.h>
+
+namespace keymaster {
+
+typedef uint64_t km_id_t;
+
+class KeymasterEnforcementContext {
+ public:
+ virtual ~KeymasterEnforcementContext() {}
+ /*
+ * Get current time.
+ */
+};
+
+class AccessTimeMap;
+class AccessCountMap;
+
+class KeymasterEnforcement {
+ public:
+ /**
+ * Construct a KeymasterEnforcement.
+ */
+ KeymasterEnforcement(uint32_t max_access_time_map_size, uint32_t max_access_count_map_size);
+ virtual ~KeymasterEnforcement();
+
+ /**
+ * Iterates through the authorization set and returns the corresponding keymaster error. Will
+ * return KM_ERROR_OK if all criteria is met for the given purpose in the authorization set with
+ * the given operation params and handle. Used for encrypt, decrypt sign, and verify.
+ */
+ keymaster_error_t AuthorizeOperation(const keymaster_purpose_t purpose, const km_id_t keyid,
+ const AuthorizationSet& auth_set,
+ const AuthorizationSet& operation_params,
+ keymaster_operation_handle_t op_handle,
+ bool is_begin_operation);
+
+ /**
+ * Iterates through the authorization set and returns the corresponding keymaster error. Will
+ * return KM_ERROR_OK if all criteria is met for the given purpose in the authorization set with
+ * the given operation params. Used for encrypt, decrypt sign, and verify.
+ */
+ keymaster_error_t AuthorizeBegin(const keymaster_purpose_t purpose, const km_id_t keyid,
+ const AuthorizationSet& auth_set,
+ const AuthorizationSet& operation_params);
+
+ /**
+ * Iterates through the authorization set and returns the corresponding keymaster error. Will
+ * return KM_ERROR_OK if all criteria is met for the given purpose in the authorization set with
+ * the given operation params and handle. Used for encrypt, decrypt sign, and verify.
+ */
+ keymaster_error_t AuthorizeUpdate(const AuthorizationSet& auth_set,
+ const AuthorizationSet& operation_params,
+ keymaster_operation_handle_t op_handle) {
+ return AuthorizeUpdateOrFinish(auth_set, operation_params, op_handle);
+ }
+
+ /**
+ * Iterates through the authorization set and returns the corresponding keymaster error. Will
+ * return KM_ERROR_OK if all criteria is met for the given purpose in the authorization set with
+ * the given operation params and handle. Used for encrypt, decrypt sign, and verify.
+ */
+ keymaster_error_t AuthorizeFinish(const AuthorizationSet& auth_set,
+ const AuthorizationSet& operation_params,
+ keymaster_operation_handle_t op_handle) {
+ return AuthorizeUpdateOrFinish(auth_set, operation_params, op_handle);
+ }
+
+ /**
+ * Creates a key ID for use in subsequent calls to AuthorizeOperation. Clients needn't use this
+ * method of creating key IDs, as long as they use something consistent and unique. This method
+ * hashes the key blob.
+ *
+ * Returns false if an error in the crypto library prevents creation of an ID.
+ */
+ static bool CreateKeyId(const keymaster_key_blob_t& key_blob, km_id_t* keyid);
+
+ //
+ // Methods that must be implemented by subclasses
+ //
+ // The time-related methods address the fact that different enforcement contexts may have
+ // different time-related capabilities. In particular:
+ //
+ // - They may or may not be able to check dates against real-world clocks.
+ //
+ // - They may or may not be able to check timestampls against authentication trustlets (minters
+ // of hw_auth_token_t structs).
+ //
+ // - They must have some time source for relative times, but may not be able to provide more
+ // than reliability and monotonicity.
+
+ /*
+ * Returns true if the specified activation date has passed, or if activation cannot be
+ * enforced.
+ */
+ virtual bool activation_date_valid(uint64_t activation_date) const = 0;
+
+ /*
+ * Returns true if the specified expiration date has passed. Returns false if it has not, or if
+ * expiration cannot be enforced.
+ */
+ virtual bool expiration_date_passed(uint64_t expiration_date) const = 0;
+
+ /*
+ * Returns true if the specified auth_token is older than the specified timeout.
+ */
+ virtual bool auth_token_timed_out(const hw_auth_token_t& token, uint32_t timeout) const = 0;
+
+ /*
+ * 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
+ * "second").
+ *
+ * On POSIX systems, it's recommented to use clock_gettime(CLOCK_MONOTONIC, ...) to implement
+ * this method.
+ */
+ virtual uint32_t get_current_time() const = 0;
+
+ /*
+ * Returns true if the specified auth_token has a valid signature, or if signature validation is
+ * not available.
+ */
+ virtual bool ValidateTokenSignature(const hw_auth_token_t& token) const = 0;
+
+ private:
+ keymaster_error_t AuthorizeUpdateOrFinish(const AuthorizationSet& auth_set,
+ const AuthorizationSet& operation_params,
+ keymaster_operation_handle_t op_handle);
+
+ bool MinTimeBetweenOpsPassed(uint32_t min_time_between, const km_id_t keyid);
+ bool MaxUsesPerBootNotExceeded(const km_id_t keyid, uint32_t max_uses);
+ bool AuthTokenMatches(const AuthorizationSet& auth_set,
+ const AuthorizationSet& operation_params, const uint64_t user_secure_id,
+ const int auth_type_index, const int auth_timeout_index,
+ const keymaster_operation_handle_t op_handle,
+ bool is_begin_operation) const;
+
+ AccessTimeMap* access_time_map_;
+ AccessCountMap* access_count_map_;
+};
+
+}; /* namespace keymaster */
+
+#endif // ANDROID_LIBRARY_KEYMASTER_ENFORCEMENT_H
diff --git a/keymaster/include/keymaster/keymaster_tags.h b/keymaster/include/keymaster/keymaster_tags.h
new file mode 100644
index 0000000..dcaf0da
--- /dev/null
+++ b/keymaster/include/keymaster/keymaster_tags.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2014 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_KEYMASTER_TAGS_H_
+#define SYSTEM_KEYMASTER_KEYMASTER_TAGS_H_
+
+/**
+ * This header contains various definitions that make working with keymaster tags safer and easier.
+ * It makes use of a fair amount of template metaprogramming, which is genarally a bad idea for
+ * maintainability, but in this case all of the metaprogramming serves the purpose of making it
+ * impossible to make certain classes of mistakes when operating on keymaster authorizations. For
+ * example, it's an error to create a keymaster_param_t with tag == KM_TAG_PURPOSE and then to
+ * assign KM_ALGORITHM_RSA to the enumerated element of its union, but because "enumerated" is a
+ * uint32_t, there's no way for the compiler, ordinarily, to diagnose it. Also, generic functions
+ * to manipulate authorizations of multiple types can't be written, because they need to know which
+ * union parameter to modify.
+ *
+ * The machinery in this header solves these problems. The core elements are two templated classes,
+ * TypedTag and TypedEnumTag. These classes are templated on a tag type and a tag value, and in the
+ * case of TypedEnumTag, an enumeration type as well. Specializations are created for each
+ * keymaster tag, associating the tag type with the tag, and an instance of each specialization is
+ * created, and named the same as the keymaster tag, but with the KM_ prefix omitted. Because the
+ * classes include a conversion operator to keymaster_tag_t, they can be used anywhere a
+ * keymaster_tag_t is expected.
+ *
+ * They also define a "value_type" typedef, which specifies the type of values associated with that
+ * particular tag. This enables template functions to be written that check that the correct
+ * parameter type is used for a given tag, and that use the correct union entry for the tag type. A
+ * very useful example is the overloaded "Authorization" function defined below, which takes tag and
+ * value arguments and correctly constructs a keyamster_param_t struct.
+ *
+ * Because the classes have no data members and all of their methods are inline, they have ZERO
+ * run-time cost in and of themselves. The one way in which they can create code bloat is when
+ * template functions using them are expanded multiple times. The standard method of creating
+ * trivial, inlined template functions which call non-templated functions which are compact but not
+ * type-safe, allows the program to have both the type-safety of the templates and the compactness
+ * of the non-templated functions, at the same time.
+ */
+
+#include <hardware/hw_auth_token.h>
+#include <hardware/keymaster_defs.h>
+
+namespace keymaster {
+
+// The following create the numeric values that KM_TAG_PADDING and KM_TAG_DIGEST used to have. We
+// need these old values to be able to support old keys that use them.
+static const keymaster_tag_t KM_TAG_DIGEST_OLD = static_cast<keymaster_tag_t>(KM_ENUM | 5);
+static const keymaster_tag_t KM_TAG_PADDING_OLD = static_cast<keymaster_tag_t>(KM_ENUM | 7);
+
+// Until we have C++11, fake std::static_assert.
+template <bool b> struct StaticAssert {};
+template <> struct StaticAssert<true> {
+ static void check() {}
+};
+
+// An unusable type that we can associate with tag types that don't have a simple value type.
+// That will prevent the associated type from being used inadvertently.
+class Void {
+ Void();
+ ~Void();
+};
+
+/**
+ * A template that defines the association between non-enumerated tag types and their value
+ * types. For each tag type we define a specialized struct that contains a typedef "value_type".
+ */
+template <keymaster_tag_type_t tag_type> struct TagValueType {};
+template <> struct TagValueType<KM_ULONG> { typedef uint64_t value_type; };
+template <> struct TagValueType<KM_ULONG_REP> { typedef uint64_t value_type; };
+template <> struct TagValueType<KM_DATE> { typedef uint64_t value_type; };
+template <> struct TagValueType<KM_UINT> { typedef uint32_t value_type; };
+template <> struct TagValueType<KM_UINT_REP> { typedef uint32_t value_type; };
+template <> struct TagValueType<KM_INVALID> { typedef Void value_type; };
+template <> struct TagValueType<KM_BOOL> { typedef bool value_type; };
+template <> struct TagValueType<KM_BYTES> { typedef keymaster_blob_t value_type; };
+template <> struct TagValueType<KM_BIGNUM> { typedef keymaster_blob_t value_type; };
+
+/**
+ * TypedTag is a templatized version of keymaster_tag_t, which provides compile-time checking of
+ * keymaster tag types. Instances are convertible to keymaster_tag_t, so they can be used wherever
+ * keymaster_tag_t is expected, and because they encode the tag type it's possible to create
+ * function overloadings that only operate on tags with a particular type.
+ */
+template <keymaster_tag_type_t tag_type, keymaster_tag_t tag> class TypedTag {
+ public:
+ typedef typename TagValueType<tag_type>::value_type value_type;
+
+ inline TypedTag() {
+ // Ensure that it's impossible to create a TypedTag instance whose 'tag' doesn't have type
+ // 'tag_type'. Attempting to instantiate a tag with the wrong type will result in a compile
+ // error (no match for template specialization StaticAssert<false>), with no run-time cost.
+ StaticAssert<(tag & tag_type) == tag_type>::check();
+ StaticAssert<(tag_type != KM_ENUM) && (tag_type != KM_ENUM_REP)>::check();
+ }
+ inline operator keymaster_tag_t() { return tag; }
+ inline long masked_tag() { return static_cast<long>(keymaster_tag_mask_type(tag)); }
+};
+
+template <keymaster_tag_type_t tag_type, keymaster_tag_t tag, typename KeymasterEnum>
+class TypedEnumTag {
+ public:
+ typedef KeymasterEnum value_type;
+
+ inline TypedEnumTag() {
+ // Ensure that it's impossible to create a TypedTag instance whose 'tag' doesn't have type
+ // 'tag_type'. Attempting to instantiate a tag with the wrong type will result in a compile
+ // error (no match for template specialization StaticAssert<false>), with no run-time cost.
+ StaticAssert<(tag & tag_type) == tag_type>::check();
+ StaticAssert<(tag_type == KM_ENUM) || (tag_type == KM_ENUM_REP)>::check();
+ }
+ inline operator keymaster_tag_t() { return tag; }
+ inline long masked_tag() { return static_cast<long>(keymaster_tag_mask_type(tag)); }
+};
+
+#ifdef KEYMASTER_NAME_TAGS
+const char* StringifyTag(keymaster_tag_t tag);
+#endif
+
+// DECLARE_KEYMASTER_TAG is used to declare TypedTag instances for each non-enum keymaster tag.
+#define DECLARE_KEYMASTER_TAG(type, name) extern TypedTag<type, KM_##name> name
+
+DECLARE_KEYMASTER_TAG(KM_INVALID, TAG_INVALID);
+DECLARE_KEYMASTER_TAG(KM_UINT, TAG_KEY_SIZE);
+DECLARE_KEYMASTER_TAG(KM_UINT, TAG_MAC_LENGTH);
+DECLARE_KEYMASTER_TAG(KM_BOOL, TAG_CALLER_NONCE);
+DECLARE_KEYMASTER_TAG(KM_UINT, TAG_MIN_MAC_LENGTH);
+DECLARE_KEYMASTER_TAG(KM_ULONG, TAG_RSA_PUBLIC_EXPONENT);
+DECLARE_KEYMASTER_TAG(KM_BOOL, TAG_ECIES_SINGLE_HASH_MODE);
+DECLARE_KEYMASTER_TAG(KM_BOOL, TAG_INCLUDE_UNIQUE_ID);
+DECLARE_KEYMASTER_TAG(KM_DATE, TAG_ACTIVE_DATETIME);
+DECLARE_KEYMASTER_TAG(KM_DATE, TAG_ORIGINATION_EXPIRE_DATETIME);
+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_BOOL, TAG_ALL_USERS);
+DECLARE_KEYMASTER_TAG(KM_UINT, TAG_USER_ID);
+DECLARE_KEYMASTER_TAG(KM_ULONG_REP, TAG_USER_SECURE_ID);
+DECLARE_KEYMASTER_TAG(KM_BOOL, TAG_NO_AUTH_REQUIRED);
+DECLARE_KEYMASTER_TAG(KM_UINT, TAG_AUTH_TIMEOUT);
+DECLARE_KEYMASTER_TAG(KM_BOOL, TAG_ALLOW_WHILE_ON_BODY);
+DECLARE_KEYMASTER_TAG(KM_BOOL, TAG_ALL_APPLICATIONS);
+DECLARE_KEYMASTER_TAG(KM_BYTES, TAG_APPLICATION_ID);
+DECLARE_KEYMASTER_TAG(KM_BYTES, TAG_APPLICATION_DATA);
+DECLARE_KEYMASTER_TAG(KM_DATE, TAG_CREATION_DATETIME);
+DECLARE_KEYMASTER_TAG(KM_BOOL, TAG_ROLLBACK_RESISTANT);
+DECLARE_KEYMASTER_TAG(KM_BYTES, TAG_ROOT_OF_TRUST);
+DECLARE_KEYMASTER_TAG(KM_BYTES, TAG_ASSOCIATED_DATA);
+DECLARE_KEYMASTER_TAG(KM_BYTES, TAG_NONCE);
+DECLARE_KEYMASTER_TAG(KM_BYTES, TAG_AUTH_TOKEN);
+DECLARE_KEYMASTER_TAG(KM_BOOL, TAG_BOOTLOADER_ONLY);
+DECLARE_KEYMASTER_TAG(KM_UINT, TAG_OS_VERSION);
+DECLARE_KEYMASTER_TAG(KM_UINT, TAG_OS_PATCHLEVEL);
+DECLARE_KEYMASTER_TAG(KM_BYTES, TAG_UNIQUE_ID);
+
+// 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
+
+DECLARE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_PURPOSE, keymaster_purpose_t);
+DECLARE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_ALGORITHM, keymaster_algorithm_t);
+DECLARE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_BLOCK_MODE, keymaster_block_mode_t);
+DECLARE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_DIGEST, keymaster_digest_t);
+DECLARE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_DIGEST_OLD, keymaster_digest_t);
+DECLARE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_PADDING, keymaster_padding_t);
+DECLARE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_PADDING_OLD, keymaster_padding_t);
+DECLARE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_BLOB_USAGE_REQUIREMENTS,
+ keymaster_key_blob_usage_requirements_t);
+DECLARE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_ORIGIN, keymaster_key_origin_t);
+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);
+
+//
+// Overloaded function "Authorization" to create keymaster_key_param_t objects for all of tags.
+//
+
+template <keymaster_tag_t Tag>
+inline keymaster_key_param_t Authorization(TypedTag<KM_BOOL, Tag> tag) {
+ return keymaster_param_bool(tag);
+}
+
+template <keymaster_tag_t Tag>
+inline keymaster_key_param_t Authorization(TypedTag<KM_UINT, Tag> tag, uint32_t value) {
+ return keymaster_param_int(tag, value);
+}
+
+template <keymaster_tag_t Tag>
+inline keymaster_key_param_t Authorization(TypedTag<KM_UINT_REP, Tag> tag, uint32_t value) {
+ return keymaster_param_int(tag, value);
+}
+
+template <keymaster_tag_t Tag>
+inline keymaster_key_param_t Authorization(TypedTag<KM_ULONG, Tag> tag, uint64_t value) {
+ return keymaster_param_long(tag, value);
+}
+
+template <keymaster_tag_t Tag>
+inline keymaster_key_param_t Authorization(TypedTag<KM_ULONG_REP, Tag> tag, uint64_t value) {
+ return keymaster_param_long(tag, value);
+}
+
+template <keymaster_tag_t Tag>
+inline keymaster_key_param_t Authorization(TypedTag<KM_DATE, Tag> tag, uint64_t value) {
+ return keymaster_param_date(tag, value);
+}
+
+template <keymaster_tag_t Tag>
+inline keymaster_key_param_t Authorization(TypedTag<KM_BYTES, Tag> tag, const void* bytes,
+ size_t bytes_len) {
+ return keymaster_param_blob(tag, reinterpret_cast<const uint8_t*>(bytes), bytes_len);
+}
+
+template <keymaster_tag_t Tag>
+inline keymaster_key_param_t Authorization(TypedTag<KM_BYTES, Tag> tag,
+ const keymaster_blob_t& blob) {
+ return keymaster_param_blob(tag, blob.data, blob.data_length);
+}
+
+template <keymaster_tag_t Tag>
+inline keymaster_key_param_t Authorization(TypedTag<KM_BIGNUM, Tag> tag, const void* bytes,
+ size_t bytes_len) {
+ return keymaster_param_blob(tag, reinterpret_cast<const uint8_t*>(bytes), bytes_len);
+}
+
+template <keymaster_tag_t Tag>
+inline keymaster_key_param_t Authorization(TypedTag<KM_BIGNUM, Tag> tag,
+ const keymaster_blob_t& blob) {
+ return keymaster_param_blob(tag, blob.data, blob.data_length);
+}
+
+template <keymaster_tag_t Tag, typename KeymasterEnum>
+inline keymaster_key_param_t Authorization(TypedEnumTag<KM_ENUM, Tag, KeymasterEnum> tag,
+ KeymasterEnum value) {
+ return keymaster_param_enum(tag, value);
+}
+
+template <keymaster_tag_t Tag, typename KeymasterEnum>
+inline keymaster_key_param_t Authorization(TypedEnumTag<KM_ENUM_REP, Tag, KeymasterEnum> tag,
+ KeymasterEnum value) {
+ return keymaster_param_enum(tag, value);
+}
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_KEYMASTER_TAGS_H_
diff --git a/keymaster/include/keymaster/logger.h b/keymaster/include/keymaster/logger.h
new file mode 100644
index 0000000..a4fdea3
--- /dev/null
+++ b/keymaster/include/keymaster/logger.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2014 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_LOGGER_H_
+#define SYSTEM_KEYMASTER_LOGGER_H_
+
+#include <stdarg.h>
+
+namespace keymaster {
+
+class Logger {
+ public:
+ Logger() {}
+ virtual ~Logger() {}
+
+ enum LogLevel {
+ DEBUG_LVL, // Messages used only for debugging
+ INFO_LVL, // Informational messages; something is unusual but not wrong
+ WARNING_LVL, // There's an indication of trouble, but it may be okay.
+ ERROR_LVL, // A problem has occurred, but processing can continue
+ SEVERE_LVL, // A severe problem has occurred; likely indicates a defect.
+ };
+
+ virtual int log_msg(LogLevel level, const char* fmt, va_list args) const = 0;
+
+ static int Log(LogLevel level, const char* fmt, va_list args);
+ static int Log(LogLevel level, const char* fmt, ...);
+ static int Debug(const char* fmt, ...);
+ static int Info(const char* fmt, ...);
+ static int Warning(const char* fmt, ...);
+ static int Error(const char* fmt, ...);
+ static int Severe(const char* fmt, ...);
+
+ protected:
+ static void set_instance(Logger* logger) { instance_ = logger; }
+
+ private:
+ // Disallow copying.
+ Logger(const Logger&);
+ void operator=(const Logger&);
+
+ static Logger* instance_;
+};
+
+#define STR(x) #x
+#define STRINGIFY(x) STR(x)
+#define FILE_LINE __FILE__ ", Line " STRINGIFY(__LINE__) ": "
+
+#define LOG_D(fmt, ...) Logger::Debug(FILE_LINE fmt, __VA_ARGS__)
+#define LOG_I(fmt, ...) Logger::Info(FILE_LINE fmt, __VA_ARGS__)
+#define LOG_W(fmt, ...) Logger::Warning(FILE_LINE fmt, __VA_ARGS__)
+#define LOG_E(fmt, ...) Logger::Error(FILE_LINE fmt, __VA_ARGS__)
+#define LOG_S(fmt, ...) Logger::Severe(FILE_LINE fmt, __VA_ARGS__)
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_LOGGER_H_
diff --git a/keymaster/include/keymaster/rsa_key_factory.h b/keymaster/include/keymaster/rsa_key_factory.h
new file mode 100644
index 0000000..f651652
--- /dev/null
+++ b/keymaster/include/keymaster/rsa_key_factory.h
@@ -0,0 +1,60 @@
+/*
+ * 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_KEY_FACTORY_H_
+#define SYSTEM_KEYMASTER_RSA_KEY_FACTORY_H_
+
+#include <openssl/evp.h>
+#include <openssl/rsa.h>
+
+#include <keymaster/asymmetric_key_factory.h>
+
+namespace keymaster {
+
+class RsaKeyFactory : public AsymmetricKeyFactory {
+ public:
+ explicit RsaKeyFactory(const KeymasterContext* context) : AsymmetricKeyFactory(context) {}
+
+ 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 CreateEmptyKey(const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ UniquePtr<AsymmetricKey>* key) const override;
+
+ OperationFactory* GetOperationFactory(keymaster_purpose_t purpose) const override;
+
+ keymaster_algorithm_t keymaster_key_type() const override { return KM_ALGORITHM_RSA; }
+ int evp_key_type() const override { return EVP_PKEY_RSA; }
+
+ protected:
+ keymaster_error_t UpdateImportKeyDescription(const AuthorizationSet& key_description,
+ keymaster_key_format_t import_key_format,
+ const KeymasterKeyBlob& import_key_material,
+ AuthorizationSet* updated_description,
+ uint64_t* public_exponent,
+ uint32_t* key_size) const;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_RSA_KEY_FACTORY_H_
diff --git a/keymaster/include/keymaster/serializable.h b/keymaster/include/keymaster/serializable.h
new file mode 100644
index 0000000..8748c55
--- /dev/null
+++ b/keymaster/include/keymaster/serializable.h
@@ -0,0 +1,253 @@
+/*
+ * Copyright 2014 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_SERIALIZABLE_H_
+#define SYSTEM_KEYMASTER_SERIALIZABLE_H_
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <cstddef>
+#include <new>
+
+#include <UniquePtr.h>
+
+namespace keymaster {
+
+class Serializable {
+ public:
+ Serializable() {}
+ virtual ~Serializable() {}
+
+ /**
+ * Return the size of the serialized representation of this object.
+ */
+ virtual size_t SerializedSize() const = 0;
+
+ /**
+ * Serialize this object into the provided buffer. Returns a pointer to the byte after the last
+ * written. Will not write past \p end, which should point to \p buf + size of the buffer
+ * (i.e. one past the end of the buffer).
+ */
+ virtual uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const = 0;
+
+ /**
+ * Deserialize from the provided buffer, copying the data into newly-allocated storage. Returns
+ * true if successful, and advances *buf past the bytes read.
+ */
+ virtual bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) = 0;
+
+ private:
+ // Disallow copying and assignment.
+ Serializable(const Serializable&);
+ void operator=(const Serializable&);
+};
+
+/*
+ * Utility functions for writing Serialize() methods
+ */
+
+/**
+ * Append a byte array to a buffer. Note that by itself this function isn't very useful, because it
+ * provides no indication in the serialized buffer of what the array size is. For writing arrays,
+ * see \p append_size_and_data_to_buf().
+ *
+ * Returns a pointer to the first byte after the data written.
+ */
+uint8_t* append_to_buf(uint8_t* buf, const uint8_t* end, const void* data, size_t data_len);
+
+/**
+ * Append some type of value convertible to a uint32_t to a buffer. This is primarily used for
+ * writing enumerated values, and uint32_ts.
+ *
+ * Returns a pointer to the first byte after the data written.
+ */
+template <typename T>
+inline uint8_t* append_uint32_to_buf(uint8_t* buf, const uint8_t* end, T value) {
+ uint32_t val = static_cast<uint32_t>(value);
+ return append_to_buf(buf, end, &val, sizeof(val));
+}
+
+/**
+ * Append a uint64_t to a buffer. Returns a pointer to the first byte after the data written.
+ */
+inline uint8_t* append_uint64_to_buf(uint8_t* buf, const uint8_t* end, uint64_t value) {
+ return append_to_buf(buf, end, &value, sizeof(value));
+}
+
+/**
+ * Appends a byte array to a buffer, prefixing it with a 32-bit size field. Returns a pointer to
+ * the first byte after the data written.
+ *
+ * See copy_size_and_data_from_buf().
+ */
+inline uint8_t* append_size_and_data_to_buf(uint8_t* buf, const uint8_t* end, const void* data,
+ size_t data_len) {
+ buf = append_uint32_to_buf(buf, end, data_len);
+ return append_to_buf(buf, end, data, data_len);
+}
+
+/**
+ * Appends an array of values that are convertible to uint32_t as uint32ts to a buffer, prefixing a
+ * count so deserialization knows how many values to read.
+ *
+ * See copy_uint32_array_from_buf().
+ */
+template <typename T>
+inline uint8_t* append_uint32_array_to_buf(uint8_t* buf, const uint8_t* end, const T* data,
+ size_t count) {
+ // Check for overflow
+ if (count >= (UINT32_MAX / sizeof(uint32_t)) || buf + count * sizeof(uint32_t) < buf)
+ return buf;
+ buf = append_uint32_to_buf(buf, end, count);
+ for (size_t i = 0; i < count; ++i)
+ buf = append_uint32_to_buf(buf, end, static_cast<uint32_t>(data[i]));
+ return buf;
+}
+
+/*
+ * Utility functions for writing Deserialize() methods.
+ */
+
+/**
+ * Copy \p size bytes from \p *buf_ptr into \p dest. If there are fewer than \p size bytes to read,
+ * returns false. Advances *buf_ptr to the next byte to be read.
+ */
+bool copy_from_buf(const uint8_t** buf_ptr, const uint8_t* end, void* dest, size_t size);
+
+/**
+ * Extracts a uint32_t size from *buf_ptr, placing it in \p *size, and then reads *size bytes from
+ * *buf_ptr, placing them in newly-allocated storage in *dest. If there aren't enough bytes in
+ * *buf_ptr, returns false. Advances \p *buf_ptr to the next byte to be read.
+ *
+ * See \p append_size_and_data_to_buf().
+ */
+bool copy_size_and_data_from_buf(const uint8_t** buf_ptr, const uint8_t* end, size_t* size,
+ UniquePtr<uint8_t[]>* dest);
+
+/**
+ * Copies a value convertible from uint32_t from \p *buf_ptr. Returns false if there are less than
+ * four bytes remaining in \p *buf_ptr. Advances \p *buf_ptr to the next byte to be read.
+ */
+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;
+ *value = static_cast<T>(val);
+ return true;
+}
+
+/**
+ * Copies a uint64_t from \p *buf_ptr. Returns false if there are less than eight bytes remaining
+ * in \p *buf_ptr. Advances \p *buf_ptr to the next byte to be read.
+ */
+inline bool copy_uint64_from_buf(const uint8_t** buf_ptr, const uint8_t* end, uint64_t* value) {
+ return copy_from_buf(buf_ptr, end, value, sizeof(*value));
+}
+
+/**
+ * Copies an array of values convertible to uint32_t from \p *buf_ptr, first reading a count of
+ * values to read. The count is returned in \p *count and the values returned in newly-allocated
+ * storage at *data. Returns false if there are insufficient bytes at \p *buf_ptr. Advances \p
+ * *buf_ptr to the next byte to be read.
+ */
+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;
+
+ const uint8_t* array_end = *buf_ptr + *count * sizeof(uint32_t);
+ if (*count >= UINT32_MAX / sizeof(uint32_t) || array_end < *buf_ptr || array_end > end)
+ return false;
+
+ data->reset(new (std::nothrow) T[*count]);
+ 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;
+ return true;
+}
+
+/**
+ * A simple buffer that supports reading and writing. Manages its own memory.
+ */
+class Buffer : public Serializable {
+ public:
+ Buffer() : buffer_(NULL), buffer_size_(0), read_position_(0), write_position_(0) {}
+ explicit Buffer(size_t size) : buffer_(NULL) { Reinitialize(size); }
+ Buffer(const void* buf, size_t size) : buffer_(NULL) { Reinitialize(buf, size); }
+
+ // Grow the buffer so that at least \p size bytes can be written.
+ bool reserve(size_t size);
+
+ bool Reinitialize(size_t size);
+ bool Reinitialize(const void* buf, size_t size);
+
+ // Reinitialize with a copy of the provided buffer's readable data.
+ bool Reinitialize(const Buffer& buffer) {
+ return Reinitialize(buffer.peek_read(), buffer.available_read());
+ }
+
+ const uint8_t* begin() const { return peek_read(); }
+ const uint8_t* end() const { return peek_read() + available_read(); }
+
+ void Clear();
+
+ size_t available_write() const;
+ size_t available_read() const;
+ size_t buffer_size() const { return buffer_size_; }
+
+ bool write(const uint8_t* src, size_t write_length);
+ bool read(uint8_t* dest, size_t read_length);
+ const uint8_t* peek_read() const { return buffer_.get() + read_position_; }
+ bool advance_read(int distance) {
+ if (static_cast<size_t>(read_position_ + distance) <= write_position_) {
+ read_position_ += distance;
+ return true;
+ }
+ return false;
+ }
+ uint8_t* peek_write() { return buffer_.get() + write_position_; }
+ bool advance_write(int distance) {
+ if (static_cast<size_t>(write_position_ + distance) <= buffer_size_) {
+ write_position_ += distance;
+ return true;
+ }
+ return false;
+ }
+
+ size_t SerializedSize() const;
+ uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const;
+ 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_;
+ size_t write_position_;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_SERIALIZABLE_H_
diff --git a/keymaster/include/keymaster/soft_keymaster_context.h b/keymaster/include/keymaster/soft_keymaster_context.h
new file mode 100644
index 0000000..2091d6f
--- /dev/null
+++ b/keymaster/include/keymaster/soft_keymaster_context.h
@@ -0,0 +1,115 @@
+/*
+ * 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_SOFT_KEYMASTER_CONTEXT_H_
+#define SYSTEM_KEYMASTER_SOFT_KEYMASTER_CONTEXT_H_
+
+#include <memory>
+#include <string>
+
+#include <openssl/evp.h>
+
+#include <hardware/keymaster0.h>
+#include <hardware/keymaster1.h>
+#include <keymaster/keymaster_context.h>
+
+namespace keymaster {
+
+class SoftKeymasterKeyRegistrations;
+class Keymaster0Engine;
+class Keymaster1Engine;
+
+/**
+ * SoftKeymasterContext provides the context for a non-secure implementation of AndroidKeymaster.
+ */
+class SoftKeymasterContext : public KeymasterContext {
+ public:
+ explicit SoftKeymasterContext(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);
+
+ /**
+ * Use the specified HW keymaster1 device for performing undigested RSA and EC operations after
+ * digesting has been done in software. Takes ownership of the specified device (will call
+ * keymaster1_device->common.close());
+ */
+ keymaster_error_t SetHardwareDevice(keymaster1_device_t* keymaster1_device);
+
+ KeyFactory* GetKeyFactory(keymaster_algorithm_t algorithm) const override;
+ OperationFactory* GetOperationFactory(keymaster_algorithm_t algorithm,
+ keymaster_purpose_t purpose) const override;
+ keymaster_algorithm_t* GetSupportedAlgorithms(size_t* algorithms_count) const override;
+ keymaster_error_t CreateKeyBlob(const AuthorizationSet& auths, keymaster_key_origin_t origin,
+ const KeymasterKeyBlob& key_material, KeymasterKeyBlob* blob,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) const override;
+
+ keymaster_error_t ParseKeyBlob(const KeymasterKeyBlob& blob,
+ const AuthorizationSet& additional_params,
+ KeymasterKeyBlob* key_material, AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) const override;
+ 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 GenerateRandom(uint8_t* buf, size_t length) const override;
+
+ EVP_PKEY* AttestationKey(keymaster_algorithm_t algorithm,
+ keymaster_error_t* error) const override;
+ keymaster_cert_chain_t* AttestationChain(keymaster_algorithm_t algorithm,
+ keymaster_error_t* error) const override;
+
+ KeymasterEnforcement* enforcement_policy() override {
+ // SoftKeymaster does no enforcement; it's all done by Keystore.
+ return nullptr;
+ }
+
+ private:
+ keymaster_error_t ParseOldSoftkeymasterBlob(const KeymasterKeyBlob& blob,
+ KeymasterKeyBlob* key_material,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) const;
+ keymaster_error_t ParseKeymaster1HwBlob(const KeymasterKeyBlob& blob,
+ const AuthorizationSet& additional_params,
+ 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;
+ keymaster_error_t FakeKeyAuthorizations(EVP_PKEY* pubkey, AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) const;
+ keymaster_error_t BuildHiddenAuthorizations(const AuthorizationSet& input_set,
+ AuthorizationSet* hidden) 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_;
+ std::unique_ptr<KeyFactory> aes_factory_;
+ std::unique_ptr<KeyFactory> hmac_factory_;
+ keymaster1_device* km1_dev_;
+ const std::string root_of_trust_;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_SOFT_KEYMASTER_CONTEXT_H_
diff --git a/keymaster/include/keymaster/soft_keymaster_device.h b/keymaster/include/keymaster/soft_keymaster_device.h
new file mode 100644
index 0000000..4a734f1
--- /dev/null
+++ b/keymaster/include/keymaster/soft_keymaster_device.h
@@ -0,0 +1,245 @@
+/*
+ * 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_SOFT_KEYMASTER_DEVICE_H_
+#define SYSTEM_KEYMASTER_SOFT_KEYMASTER_DEVICE_H_
+
+#include <cstdlib>
+#include <map>
+#include <vector>
+
+#include <hardware/keymaster0.h>
+#include <hardware/keymaster1.h>
+#include <hardware/keymaster2.h>
+
+#include <keymaster/android_keymaster.h>
+#include <keymaster/soft_keymaster_context.h>
+
+#include <UniquePtr.h>
+
+namespace keymaster {
+
+class AuthorizationSet;
+
+/**
+ * Keymaster1 device implementation.
+ *
+ * This is a hybrid software/hardware implementation which wraps a keymaster0_device_t, forwarding
+ * RSA operations to secure hardware and doing everything else in software.
+ *
+ * IMPORTANT MAINTAINER NOTE: Pointers to instances of this class must be castable to hw_device_t
+ * and keymaster_device. This means it must remain a standard layout class (no virtual functions and
+ * no data members which aren't standard layout), and device_ must be the first data member.
+ * Assertions in the constructor validate compliance with those constraints.
+ */
+class SoftKeymasterDevice {
+ public:
+ SoftKeymasterDevice();
+
+ // Public only for testing.
+ 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());
+ */
+ keymaster_error_t SetHardwareDevice(keymaster1_device_t* keymaster1_device);
+
+ /**
+ * Returns true if a keymaster1_device_t has been set as the hardware device, and if that
+ * hardware device should be used directly.
+ */
+ bool Keymaster1DeviceIsGood();
+
+ hw_device_t* hw_device();
+ keymaster1_device_t* keymaster_device();
+ keymaster2_device_t* keymaster2_device();
+
+ // Public only for testing
+ void GetVersion(const GetVersionRequest& req, GetVersionResponse* rsp) {
+ impl_->GetVersion(req, rsp);
+ }
+
+ typedef std::pair<keymaster_algorithm_t, keymaster_purpose_t> AlgPurposePair;
+ typedef std::map<AlgPurposePair, std::vector<keymaster_digest_t>> DigestMap;
+
+ private:
+ void initialize_device_struct(uint32_t flags);
+ bool FindUnsupportedDigest(keymaster_algorithm_t algorithm, keymaster_purpose_t purpose,
+ const AuthorizationSet& params,
+ keymaster_digest_t* unsupported) const;
+ bool RequiresSoftwareDigesting(keymaster_algorithm_t algorithm, keymaster_purpose_t purpose,
+ const AuthorizationSet& params) const;
+ bool KeyRequiresSoftwareDigesting(const AuthorizationSet& key_description) const;
+
+ static void StoreDefaultNewKeyParams(keymaster_algorithm_t algorithm,
+ AuthorizationSet* auth_set);
+ static keymaster_error_t GetPkcs8KeyAlgorithm(const uint8_t* key, size_t key_length,
+ keymaster_algorithm_t* algorithm);
+
+ static int close_device(hw_device_t* dev);
+
+ /*
+ * These static methods are the functions referenced through the function pointers in
+ * keymaster_device.
+ */
+
+ // Keymaster1 methods
+ static keymaster_error_t get_supported_algorithms(const keymaster1_device_t* dev,
+ keymaster_algorithm_t** algorithms,
+ size_t* algorithms_length);
+ static keymaster_error_t get_supported_block_modes(const keymaster1_device_t* dev,
+ keymaster_algorithm_t algorithm,
+ keymaster_purpose_t purpose,
+ keymaster_block_mode_t** modes,
+ size_t* modes_length);
+ static keymaster_error_t get_supported_padding_modes(const keymaster1_device_t* dev,
+ keymaster_algorithm_t algorithm,
+ keymaster_purpose_t purpose,
+ keymaster_padding_t** modes,
+ size_t* modes_length);
+ static keymaster_error_t get_supported_digests(const keymaster1_device_t* dev,
+ keymaster_algorithm_t algorithm,
+ keymaster_purpose_t purpose,
+ keymaster_digest_t** digests,
+ size_t* digests_length);
+ static keymaster_error_t get_supported_import_formats(const keymaster1_device_t* dev,
+ keymaster_algorithm_t algorithm,
+ keymaster_key_format_t** formats,
+ size_t* formats_length);
+ static keymaster_error_t get_supported_export_formats(const keymaster1_device_t* dev,
+ keymaster_algorithm_t algorithm,
+ keymaster_key_format_t** formats,
+ size_t* formats_length);
+ static keymaster_error_t add_rng_entropy(const keymaster1_device_t* dev, const uint8_t* data,
+ size_t data_length);
+ static keymaster_error_t 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);
+ static keymaster_error_t get_key_characteristics(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** character);
+ static keymaster_error_t import_key(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);
+ static keymaster_error_t export_key(const keymaster1_device_t* dev, //
+ keymaster_key_format_t export_format,
+ const keymaster_key_blob_t* key_to_export,
+ const keymaster_blob_t* client_id,
+ const keymaster_blob_t* app_data,
+ keymaster_blob_t* export_data);
+ static keymaster_error_t delete_key(const keymaster1_device_t* dev,
+ const keymaster_key_blob_t* key);
+ static keymaster_error_t delete_all_keys(const keymaster1_device_t* dev);
+ static keymaster_error_t begin(const keymaster1_device_t* dev, keymaster_purpose_t purpose,
+ const keymaster_key_blob_t* key,
+ const keymaster_key_param_set_t* in_params,
+ keymaster_key_param_set_t* out_params,
+ keymaster_operation_handle_t* operation_handle);
+ static keymaster_error_t update(const keymaster1_device_t* dev, //
+ keymaster_operation_handle_t operation_handle,
+ const keymaster_key_param_set_t* in_params,
+ const keymaster_blob_t* input, size_t* input_consumed,
+ keymaster_key_param_set_t* out_params,
+ keymaster_blob_t* output);
+ static keymaster_error_t finish(const keymaster1_device_t* dev, //
+ keymaster_operation_handle_t operation_handle,
+ const keymaster_key_param_set_t* in_params,
+ const keymaster_blob_t* signature,
+ keymaster_key_param_set_t* out_params,
+ keymaster_blob_t* output);
+ static keymaster_error_t abort(const keymaster1_device_t* dev,
+ keymaster_operation_handle_t operation_handle);
+
+ // Keymaster2 methods
+ static keymaster_error_t add_rng_entropy(const keymaster2_device_t* dev, const uint8_t* data,
+ size_t data_length);
+ static keymaster_error_t generate_key(const keymaster2_device_t* dev,
+ const keymaster_key_param_set_t* params,
+ keymaster_key_blob_t* key_blob,
+ keymaster_key_characteristics_t* characteristics);
+ static keymaster_error_t get_key_characteristics(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* character);
+ static keymaster_error_t import_key(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);
+ static keymaster_error_t export_key(const keymaster2_device_t* dev, //
+ keymaster_key_format_t export_format,
+ const keymaster_key_blob_t* key_to_export,
+ const keymaster_blob_t* client_id,
+ const keymaster_blob_t* app_data,
+ keymaster_blob_t* export_data);
+ static keymaster_error_t attest_key(const keymaster2_device_t* dev,
+ const keymaster_key_blob_t* key_to_attest,
+ const keymaster_key_param_set_t* attest_params,
+ keymaster_cert_chain_t* cert_chain);
+ static keymaster_error_t delete_key(const keymaster2_device_t* dev,
+ const keymaster_key_blob_t* key);
+ static keymaster_error_t delete_all_keys(const keymaster2_device_t* dev);
+ static keymaster_error_t begin(const keymaster2_device_t* dev, keymaster_purpose_t purpose,
+ const keymaster_key_blob_t* key,
+ const keymaster_key_param_set_t* in_params,
+ keymaster_key_param_set_t* out_params,
+ keymaster_operation_handle_t* operation_handle);
+ static keymaster_error_t update(const keymaster2_device_t* dev, //
+ keymaster_operation_handle_t operation_handle,
+ const keymaster_key_param_set_t* in_params,
+ const keymaster_blob_t* input, size_t* input_consumed,
+ keymaster_key_param_set_t* out_params,
+ keymaster_blob_t* output);
+ static keymaster_error_t finish(const keymaster2_device_t* dev, //
+ keymaster_operation_handle_t operation_handle,
+ const keymaster_key_param_set_t* in_params,
+ const keymaster_blob_t* input,
+ const keymaster_blob_t* signature,
+ keymaster_key_param_set_t* out_params,
+ keymaster_blob_t* output);
+ static keymaster_error_t abort(const keymaster2_device_t* dev,
+ keymaster_operation_handle_t operation_handle);
+
+ keymaster1_device_t km1_device_;
+ keymaster2_device_t km2_device_;
+
+ keymaster0_device_t* wrapped_km0_device_;
+ keymaster1_device_t* wrapped_km1_device_;
+ DigestMap km1_device_digests_;
+ SoftKeymasterContext* context_;
+ UniquePtr<AndroidKeymaster> impl_;
+ std::string module_name_;
+ hw_module_t updated_module_;
+};
+
+} // namespace keymaster
+
+#endif // EXTERNAL_KEYMASTER_TRUSTY_KEYMASTER_DEVICE_H_
diff --git a/keymaster/include/keymaster/soft_keymaster_logger.h b/keymaster/include/keymaster/soft_keymaster_logger.h
new file mode 100644
index 0000000..3be83b8
--- /dev/null
+++ b/keymaster/include/keymaster/soft_keymaster_logger.h
@@ -0,0 +1,34 @@
+/*
+ * 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_SOFT_KEYMASTER_LOGGER_H_
+#define SYSTEM_KEYMASTER_SOFT_KEYMASTER_LOGGER_H_
+
+#include <keymaster/logger.h>
+
+namespace keymaster {
+
+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_
diff --git a/keymaster/integrity_assured_key_blob.cpp b/keymaster/integrity_assured_key_blob.cpp
new file mode 100644
index 0000000..5c317a3
--- /dev/null
+++ b/keymaster/integrity_assured_key_blob.cpp
@@ -0,0 +1,149 @@
+/*
+ * 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 "integrity_assured_key_blob.h"
+
+#include <assert.h>
+
+#include <new>
+
+#include <openssl/hmac.h>
+#include <openssl/mem.h>
+
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/authorization_set.h>
+
+#include "openssl_err.h"
+
+namespace keymaster {
+
+static const uint8_t BLOB_VERSION = 0;
+static const size_t HMAC_SIZE = 8;
+static const char HMAC_KEY[] = "IntegrityAssuredBlob0";
+
+inline size_t min(size_t a, size_t b) {
+ if (a < b)
+ return a;
+ return b;
+}
+
+class HmacCleanup {
+ public:
+ explicit HmacCleanup(HMAC_CTX* ctx) : ctx_(ctx) {}
+ ~HmacCleanup() { HMAC_CTX_cleanup(ctx_); }
+
+ private:
+ HMAC_CTX* ctx_;
+};
+
+static keymaster_error_t ComputeHmac(const uint8_t* serialized_data, size_t serialized_data_size,
+ 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;
+ hidden.Serialize(hidden_bytes.get(), hidden_bytes.get() + hidden_bytes_size);
+
+ HMAC_CTX ctx;
+ HMAC_CTX_init(&ctx);
+ const EVP_MD* md = EVP_sha256();
+ if (!HMAC_Init_ex(&ctx, HMAC_KEY, sizeof(HMAC_KEY), md, NULL /* engine */))
+ return TranslateLastOpenSslError();
+ HmacCleanup cleanup(&ctx);
+
+ uint8_t tmp[EVP_MAX_MD_SIZE];
+ unsigned tmp_len;
+ if (!HMAC_Update(&ctx, serialized_data, serialized_data_size) ||
+ !HMAC_Update(&ctx, hidden_bytes.get(), hidden_bytes_size) || //
+ !HMAC_Final(&ctx, tmp, &tmp_len))
+ return TranslateLastOpenSslError();
+
+ assert(tmp_len >= HMAC_SIZE);
+ memcpy(hmac, tmp, min(HMAC_SIZE, tmp_len));
+
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t SerializeIntegrityAssuredBlob(const KeymasterKeyBlob& key_material,
+ const AuthorizationSet& hidden,
+ const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ KeymasterKeyBlob* key_blob) {
+ size_t size = 1 /* version */ + //
+ key_material.SerializedSize() + //
+ hw_enforced.SerializedSize() + //
+ sw_enforced.SerializedSize() + //
+ HMAC_SIZE;
+
+ if (!key_blob->Reset(size))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ uint8_t* p = key_blob->writable_data();
+ *p++ = BLOB_VERSION;
+ p = key_material.Serialize(p, key_blob->end());
+ p = hw_enforced.Serialize(p, key_blob->end());
+ p = sw_enforced.Serialize(p, key_blob->end());
+
+ return ComputeHmac(key_blob->key_material, p - key_blob->key_material, hidden, p);
+}
+
+keymaster_error_t DeserializeIntegrityAssuredBlob(const KeymasterKeyBlob& key_blob,
+ const AuthorizationSet& hidden,
+ KeymasterKeyBlob* key_material,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) {
+ 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;
+
+ 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 (CRYPTO_memcmp(key_blob.end() - HMAC_SIZE, computed_hmac, HMAC_SIZE) != 0)
+ return KM_ERROR_INVALID_KEY_BLOB;
+
+ return DeserializeIntegrityAssuredBlob_NoHmacCheck(key_blob, key_material, hw_enforced,
+ sw_enforced);
+}
+
+keymaster_error_t DeserializeIntegrityAssuredBlob_NoHmacCheck(const KeymasterKeyBlob& key_blob,
+ KeymasterKeyBlob* key_material,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) {
+ 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 != BLOB_VERSION)
+ return KM_ERROR_INVALID_KEY_BLOB;
+ ++p;
+
+ if (!key_material->Deserialize(&p, end) || //
+ !hw_enforced->Deserialize(&p, end) || //
+ !sw_enforced->Deserialize(&p, end))
+ return KM_ERROR_INVALID_KEY_BLOB;
+
+ return KM_ERROR_OK;
+}
+
+} // namespace keymaster;
diff --git a/keymaster/integrity_assured_key_blob.h b/keymaster/integrity_assured_key_blob.h
new file mode 100644
index 0000000..6239a8a
--- /dev/null
+++ b/keymaster/integrity_assured_key_blob.h
@@ -0,0 +1,47 @@
+/*
+ * 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_INTEGRITY_ASSURED_KEY_BLOB_
+#define SYSTEM_KEYMASTER_INTEGRITY_ASSURED_KEY_BLOB_
+
+#include <hardware/keymaster_defs.h>
+
+namespace keymaster {
+
+class AuthorizationSet;
+class Buffer;
+struct KeymasterKeyBlob;
+
+keymaster_error_t SerializeIntegrityAssuredBlob(const KeymasterKeyBlob& key_material,
+ const AuthorizationSet& hidden,
+ const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ KeymasterKeyBlob* key_blob);
+
+keymaster_error_t DeserializeIntegrityAssuredBlob(const KeymasterKeyBlob& key_blob,
+ const AuthorizationSet& hidden,
+ KeymasterKeyBlob* key_material,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced);
+
+keymaster_error_t DeserializeIntegrityAssuredBlob_NoHmacCheck(const KeymasterKeyBlob& key_blob,
+ KeymasterKeyBlob* key_material,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced);
+
+} // namespace keymaster;
+
+#endif // SYSTEM_KEYMASTER_INTEGRITY_ASSURED_KEY_BLOB_
diff --git a/keymaster/iso18033kdf.cpp b/keymaster/iso18033kdf.cpp
new file mode 100644
index 0000000..3de0fdf
--- /dev/null
+++ b/keymaster/iso18033kdf.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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 "iso18033kdf.h"
+#include "openssl_utils.h"
+
+#include <algorithm>
+
+#include <openssl/evp.h>
+
+namespace keymaster {
+
+inline size_t min(size_t a, size_t b) {
+ return (a < b) ? a : b;
+}
+
+bool Iso18033Kdf::GenerateKey(const uint8_t* info, size_t info_len, uint8_t* output,
+ size_t output_len) {
+ if (!is_initialized_ || output == nullptr)
+ return false;
+
+ /* Check whether output length is too long as specified in ISO/IEC 18033-2. */
+ if ((0xFFFFFFFFULL + start_counter_) * digest_size_ < (uint64_t)output_len)
+ return false;
+
+ EVP_MD_CTX ctx;
+ EvpMdCtxCleaner ctxCleaner(&ctx);
+ EVP_MD_CTX_init(&ctx);
+
+ size_t num_blocks = (output_len + digest_size_ - 1) / digest_size_;
+ UniquePtr<uint8_t[]> counter(new uint8_t[4]);
+ UniquePtr<uint8_t[]> digest_result(new uint8_t[digest_size_]);
+ if (counter.get() == nullptr || digest_result.get() == nullptr)
+ return false;
+ for (size_t block = 0; block < num_blocks; block++) {
+ switch (digest_type_) {
+ case KM_DIGEST_SHA1:
+ if (!EVP_DigestInit_ex(&ctx, EVP_sha1(), nullptr /* default digest */))
+ return false;
+ break;
+ case KM_DIGEST_SHA_2_256:
+ if (!EVP_DigestInit_ex(&ctx, EVP_sha256(), nullptr /* default digest */))
+ return false;
+ break;
+ default:
+ return false;
+ }
+
+ if (!EVP_DigestUpdate(&ctx, secret_key_.get(), secret_key_len_) ||
+ !Uint32ToBigEndianByteArray(block + start_counter_, counter.get()) ||
+ !EVP_DigestUpdate(&ctx, counter.get(), 4))
+ return false;
+
+ if (info != nullptr && info_len > 0) {
+ if (!EVP_DigestUpdate(&ctx, info, info_len))
+ return false;
+ }
+
+ /* OpenSSL does not accept size_t parameter. */
+ uint32_t uint32_digest_size_ = digest_size_;
+ if (!EVP_DigestFinal_ex(&ctx, digest_result.get(), &uint32_digest_size_) ||
+ uint32_digest_size_ != digest_size_)
+ return false;
+
+ size_t block_start = digest_size_ * block;
+ size_t block_length = min(digest_size_, output_len - block_start);
+ memcpy(output + block_start, digest_result.get(), block_length);
+ }
+ return true;
+}
+
+} // namespace keymaster
diff --git a/keymaster/iso18033kdf.h b/keymaster/iso18033kdf.h
new file mode 100644
index 0000000..40fd2d6
--- /dev/null
+++ b/keymaster/iso18033kdf.h
@@ -0,0 +1,68 @@
+/*
+ * 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_ISO18033KDF_H_
+#define SYSTEM_KEYMASTER_ISO18033KDF_H_
+
+#include "kdf.h"
+
+#include <hardware/keymaster_defs.h>
+
+#include <keymaster/serializable.h>
+
+#include <UniquePtr.h>
+
+namespace keymaster {
+
+/**
+ * A light implementation of ISO18033KDF as defined by ISO-18033-2 (www.shoup.net/iso/std6.pdf) and
+ * its slightly different variant ANSI-X9-42.
+ */
+class Iso18033Kdf : public Kdf {
+ public:
+ ~Iso18033Kdf() {}
+
+ bool Init(keymaster_digest_t digest_type, const uint8_t* secret, size_t secret_len) {
+ return Kdf::Init(digest_type, secret, secret_len, nullptr /* salt */, 0 /* salt_len */);
+ }
+
+ /**
+ * Generates ISO18033's derived key, as defined in ISO-18033-2 and ANSI-X9-42. In ISO 18033-2,
+ * KDF takes a secret and outputs:
+ *
+ * hash(secret || start_counter) || hash(secret|| start_counter + 1) || ...
+ *
+ * In ANSI-X9-42, KDF takes a secret and additional info, and outputs:
+ *
+ * hash(secret || start_counter || info) || hash(secret || start_counter + 1 || info) || ...
+ *
+ * Note that the KDFs are the same if the info field is considered optional. In both cases the
+ * length of the output is specified by the caller, and the counter is encoded as a 4-element
+ * byte array.
+ */
+ bool GenerateKey(const uint8_t* info, size_t info_len, uint8_t* output,
+ size_t output_len) override;
+
+ protected:
+ explicit Iso18033Kdf(uint32_t start_counter) : start_counter_(start_counter) {}
+
+ private:
+ uint32_t start_counter_;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_ISO18033KDF_H_
diff --git a/keymaster/kdf.cpp b/keymaster/kdf.cpp
new file mode 100644
index 0000000..e196a0c
--- /dev/null
+++ b/keymaster/kdf.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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 "kdf.h"
+
+namespace keymaster {
+
+Kdf::Kdf() : is_initialized_(false) {}
+
+bool Kdf::Init(keymaster_digest_t digest_type, const uint8_t* secret, size_t secret_len,
+ const uint8_t* salt, size_t salt_len) {
+ is_initialized_ = false;
+
+ switch (digest_type) {
+ case KM_DIGEST_SHA1:
+ digest_size_ = 20;
+ digest_type_ = digest_type;
+ break;
+ case KM_DIGEST_SHA_2_256:
+ digest_size_ = 32;
+ digest_type_ = digest_type;
+ break;
+ default:
+ 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;
+
+ salt_len_ = salt_len;
+ if (salt && salt_len > 0) {
+ salt_.reset(dup_buffer(salt, salt_len));
+ if (!salt_.get())
+ return false;
+ } else {
+ salt_.reset();
+ }
+
+ is_initialized_ = true;
+ return true;
+}
+
+bool Kdf::Uint32ToBigEndianByteArray(uint32_t number, uint8_t* output) {
+ if (!output)
+ return false;
+
+ output[0] = (number >> 24) & 0xff;
+ output[1] = (number >> 16) & 0xff;
+ output[2] = (number >> 8) & 0xff;
+ output[3] = (number)&0xff;
+ return true;
+}
+
+} // namespace keymaster
diff --git a/keymaster/kdf.h b/keymaster/kdf.h
new file mode 100644
index 0000000..b90d2bc
--- /dev/null
+++ b/keymaster/kdf.h
@@ -0,0 +1,53 @@
+/*
+ * 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_KDF_H_
+#define SYSTEM_KEYMASTER_KDF_H_
+
+#include <hardware/keymaster_defs.h>
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/serializable.h>
+
+#include <UniquePtr.h>
+
+namespace keymaster {
+
+/**
+ * A base class for wrapping different key derivation functions.
+ */
+class Kdf {
+ public:
+ virtual ~Kdf() { memset_s(secret_key_.get(), 0, secret_key_len_); };
+ Kdf();
+ bool Init(keymaster_digest_t digest_type, const uint8_t* secret, size_t secret_len,
+ const uint8_t* salt, size_t salt_len);
+ virtual bool GenerateKey(const uint8_t* info, size_t info_len, uint8_t* output,
+ size_t output_len) = 0;
+
+ protected:
+ bool Uint32ToBigEndianByteArray(uint32_t number, uint8_t* output);
+ UniquePtr<uint8_t[]> secret_key_;
+ size_t secret_key_len_;
+ UniquePtr<uint8_t[]> salt_;
+ size_t salt_len_;
+ bool is_initialized_;
+ keymaster_digest_t digest_type_;
+ size_t digest_size_;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_KDF_H_
diff --git a/keymaster/kdf1.h b/keymaster/kdf1.h
new file mode 100644
index 0000000..fab1ef7
--- /dev/null
+++ b/keymaster/kdf1.h
@@ -0,0 +1,40 @@
+/*
+ * 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_KDF1_H_
+#define SYSTEM_KEYMASTER_KDF1_H_
+
+#include "iso18033kdf.h"
+
+#include <hardware/keymaster_defs.h>
+
+#include <keymaster/serializable.h>
+
+#include <UniquePtr.h>
+
+namespace keymaster {
+
+/**
+ * Kdf1 is instance of Iso18033Kdf when the counter starts at 0.
+ */
+class Kdf1 : public Iso18033Kdf {
+ public:
+ Kdf1() : Iso18033Kdf(0) {}
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_KDF1_H_
diff --git a/keymaster/kdf1_test.cpp b/keymaster/kdf1_test.cpp
new file mode 100644
index 0000000..9c8b0d5
--- /dev/null
+++ b/keymaster/kdf1_test.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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 "kdf1.h"
+#include <gtest/gtest.h>
+#include <string.h>
+
+#include "android_keymaster_test_utils.h"
+
+using std::string;
+
+namespace keymaster {
+
+namespace test {
+
+struct Kdf1Test {
+ const char* key_hex;
+ const char* expected_output_hex;
+ keymaster_digest_t digest_type;
+};
+
+static const Kdf1Test kKdf1Tests[] = {
+ {"032e45326fa859a72ec235acff929b15d1372e30b207255f0611b8f785d764374152e0ac009e509e7ba30cd2f1778"
+ "e113b64e135cf4e2292c75efe5288edfda4",
+ "5f8de105b5e96b2e490ddecbd147dd1def7e3b8e0e6a26eb7b956ccb8b3bdc1ca975bc57c3989e8fbad31a224655d"
+ "800c46954840ff32052cdf0d640562bdfadfa263cfccf3c52b29f2af4a1869959bc77f854cf15bd7a25192985a842"
+ "dbff8e13efee5b7e7e55bbe4d389647c686a9a9ab3fb889b2d7767d3837eea4e0a2f04",
+ KM_DIGEST_SHA1}};
+
+TEST(Kdf1Test, Kdf1) {
+ for (auto& test : kKdf1Tests) {
+ const string key = hex2str(test.key_hex);
+ const string expected_output = hex2str(test.expected_output_hex);
+ size_t output_len = expected_output.size();
+ uint8_t output[output_len];
+
+ Kdf1 kdf1;
+ ASSERT_TRUE(
+ kdf1.Init(test.digest_type, reinterpret_cast<const uint8_t*>(key.data()), key.size()));
+ ASSERT_TRUE(kdf1.GenerateKey(nullptr, 0, output, output_len));
+ EXPECT_EQ(0, memcmp(output, expected_output.data(), output_len));
+ }
+}
+
+} // namespace test
+
+} // namespace keymaster
diff --git a/keymaster/kdf2.h b/keymaster/kdf2.h
new file mode 100644
index 0000000..1df97ef
--- /dev/null
+++ b/keymaster/kdf2.h
@@ -0,0 +1,40 @@
+/*
+ * 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_KDF2_H_
+#define SYSTEM_KEYMASTER_KDF2_H_
+
+#include "iso18033kdf.h"
+
+#include <hardware/keymaster_defs.h>
+
+#include <keymaster/serializable.h>
+
+#include <UniquePtr.h>
+
+namespace keymaster {
+
+/**
+ * Kdf2 is instance of Iso18033Kdf when the counter starts at 1.
+ */
+class Kdf2 : public Iso18033Kdf {
+ public:
+ Kdf2() : Iso18033Kdf(1) {}
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_KDF2_H_
diff --git a/keymaster/kdf2_test.cpp b/keymaster/kdf2_test.cpp
new file mode 100644
index 0000000..29ff40a
--- /dev/null
+++ b/keymaster/kdf2_test.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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 "kdf2.h"
+#include <gtest/gtest.h>
+#include <string.h>
+
+#include "android_keymaster_test_utils.h"
+
+using std::string;
+
+namespace keymaster {
+
+namespace test {
+
+struct Kdf2Test {
+ const char* key_hex;
+ const char* info_hex;
+ const char* expected_output_hex;
+ keymaster_digest_t digest_type;
+};
+
+static const Kdf2Test kKdf2Tests[] = {
+ {"032e45326fa859a72ec235acff929b15d1372e30b207255f0611b8f785d764374152e0ac009e509e7ba30cd2f1778"
+ "e113b64e135cf4e2292c75efe5288edfda4",
+ "",
+ "10a2403db42a8743cb989de86e668d168cbe6046e23ff26f741e87949a3bba1311ac179f819a3d18412e9eb45668f"
+ "2923c087c1299005f8d5fd42ca257bc93e8fee0c5a0d2a8aa70185401fbbd99379ec76c663e9a29d0b70f3fe261a5"
+ "9cdc24875a60b4aacb1319fa11c3365a8b79a44669f26fba933d012db213d7e3b16349",
+ KM_DIGEST_SHA_2_256},
+ {"032e45326fa859a72ec235acff929b15d1372e30b207255f0611b8f785d764374152e0ac009e509e7ba30cd2f1778"
+ "e113b64e135cf4e2292c75efe5288edfda4",
+ "",
+ "0e6a26eb7b956ccb8b3bdc1ca975bc57c3989e8fbad31a224655d800c46954840ff32052cdf0d640562bdfadfa263"
+ "cfccf3c52b29f2af4a1869959bc77f854cf15bd7a25192985a842dbff8e13efee5b7e7e55bbe4d389647c686a9a9a"
+ "b3fb889b2d7767d3837eea4e0a2f04b53ca8f50fb31225c1be2d0126c8c7a4753b0807",
+ KM_DIGEST_SHA1},
+ {"CA7C0F8C3FFA87A96E1B74AC8E6AF594347BB40A", "", "744AB703F5BC082E59185F6D049D2D367DB245C2",
+ KM_DIGEST_SHA1},
+ {"0499B502FC8B5BAFB0F4047E731D1F9FD8CD0D8881", "",
+ "03C62280C894E103C680B13CD4B4AE740A5EF0C72547292F82DC6B1777F47D63BA9D1EA73"
+ "2DBF386",
+ KM_DIGEST_SHA1},
+ {"5E10B967A95606853E528F04262AD18A4767C761163971391E17CB05A21668D4CE2B9F151617408042CE091958382"
+ "3FD346D1751FBE2341AF2EE0461B62F100FFAD4F723F70C18B38238ED183E9398C8CA517EE0CBBEFFF9C59471FE27"
+ "8093924089480DBC5A38E9A1A97D23038106847D0D22ECF85F49A861821199BAFCB0D74E6ACFFD7D142765EBF4C71"
+ "2414FE4B6AB957F4CB466B46601289BB82060428272842EE28F113CD11F39431CBFFD823254CE472E2105E49B3D7F"
+ "113B825076E6264585807BC46454665F27C5E4E1A4BD03470486322981FDC894CCA1E2930987C92C15A38BC42EB38"
+ "810E867C4432F07259EC00CDBBB0FB99E1727C706DA58DD",
+ "484D4143204B6579", "BC98EB018CB00EE26D1F97A15AE166912A7AC4C5", KM_DIGEST_SHA1},
+
+};
+
+TEST(Kdf2Test, Kdf2) {
+ for (auto& test : kKdf2Tests) {
+ const string key = hex2str(test.key_hex);
+ const string info = hex2str(test.info_hex);
+ const string expected_output = hex2str(test.expected_output_hex);
+ size_t output_len = expected_output.size();
+ uint8_t output[output_len];
+
+ Kdf2 kdf2;
+ ASSERT_TRUE(
+ kdf2.Init(test.digest_type, reinterpret_cast<const uint8_t*>(key.data()), key.size()));
+ ASSERT_TRUE(kdf2.GenerateKey(reinterpret_cast<const uint8_t*>(info.data()), info.size(),
+ output, output_len));
+ EXPECT_EQ(0, memcmp(output, expected_output.data(), output_len));
+ }
+}
+
+} // namespace test
+
+} // namespace keymaster
diff --git a/keymaster/kdf_test.cpp b/keymaster/kdf_test.cpp
new file mode 100644
index 0000000..f6f4a93
--- /dev/null
+++ b/keymaster/kdf_test.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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 "kdf.h"
+#include <gtest/gtest.h>
+
+namespace keymaster {
+
+namespace test {
+
+class ForTestAbstractKdf : public Kdf {
+ bool GenerateKey(const uint8_t* /* info */, size_t /* info_len */, uint8_t* /* output */,
+ size_t /* output_len */) {
+ return true;
+ }
+};
+
+TEST(KdfTest, Kdf) {
+ ForTestAbstractKdf kdf;
+ uint8_t key[128];
+ uint8_t salt[128];
+ ASSERT_TRUE(kdf.Init(KM_DIGEST_SHA1, key, 128, salt, 128));
+ ASSERT_TRUE(kdf.Init(KM_DIGEST_SHA_2_256, key, 128, salt, 128));
+ ASSERT_TRUE(kdf.Init(KM_DIGEST_SHA1, key, 128, nullptr, 0));
+ ASSERT_FALSE(kdf.Init(KM_DIGEST_MD5, key, 128, salt, 128));
+ ASSERT_FALSE(kdf.Init(KM_DIGEST_SHA1, nullptr, 0, salt, 128));
+ ASSERT_FALSE(kdf.Init(KM_DIGEST_SHA1, nullptr, 128, salt, 128));
+ ASSERT_FALSE(kdf.Init(KM_DIGEST_SHA1, key, 0, salt, 128));
+}
+
+} // namespace test
+
+} // namespace keymaster
diff --git a/keymaster/kem.h b/keymaster/kem.h
new file mode 100644
index 0000000..f2fa073
--- /dev/null
+++ b/keymaster/kem.h
@@ -0,0 +1,54 @@
+/*
+ * 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_KEM_H_
+#define SYSTEM_KEYMASTER_KEM_H_
+
+#include <keymaster/serializable.h>
+
+#include "openssl_utils.h"
+
+namespace keymaster {
+
+// Kem is an abstract class that provides an interface to a key encapsulation
+// mechansim primitive. A key encapsulation mechanism works just like a
+// public-key encryption scheme, except that the encryption algorithm takes no
+// input other than the recipient’s public key. Instead, the encryption algorithm
+// generates a pair (K, C0), where K is a bit string of some specified length,
+// and C0 is an encryption of K, that is, the decryption algorithm applied to C0
+// yields K.
+class Kem {
+ public:
+ virtual ~Kem(){};
+
+ // For a key encapsulation mechanism, the goal of encryption is to take the recipient's public
+ // key, and to generate a pair (K, C0), where K is a bit string of some specified length,
+ // and C0 is an encryption of K.
+ virtual bool Encrypt(const Buffer& peer_public_value, Buffer* output_clear_key,
+ Buffer* output_encrypted_key) = 0;
+ virtual bool Encrypt(const uint8_t* peer_public_value, size_t peer_public_value_len,
+ Buffer* output_clear_key, Buffer* output_encrypted_key) = 0;
+
+ // Decrypt takes an encrypted key, and outputs its clear text.
+ // Decrypt takes ownership of \p private_key.
+ virtual bool Decrypt(EC_KEY* private_key, const Buffer& encrypted_key, Buffer* output_key) = 0;
+ virtual bool Decrypt(EC_KEY* private_key, const uint8_t* encrypted_key,
+ size_t encrypted_key_len, Buffer* output_key) = 0;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_KEM_H_
diff --git a/keymaster/key.cpp b/keymaster/key.cpp
new file mode 100644
index 0000000..eb828e1
--- /dev/null
+++ b/keymaster/key.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2014 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 <assert.h>
+
+#include "key.h"
+
+#include <openssl/x509.h>
+
+#include "openssl_utils.h"
+
+namespace keymaster {
+
+Key::Key(const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+ keymaster_error_t* error) {
+ assert(error);
+ authorizations_.push_back(hw_enforced);
+ authorizations_.push_back(sw_enforced);
+ *error = KM_ERROR_OK;
+ if (authorizations_.is_valid() != AuthorizationSet::OK)
+ *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+}
+
+} // namespace keymaster
diff --git a/keymaster/key.h b/keymaster/key.h
new file mode 100644
index 0000000..9fb4063
--- /dev/null
+++ b/keymaster/key.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2014 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_KEY_H_
+#define SYSTEM_KEYMASTER_KEY_H_
+
+#include <UniquePtr.h>
+
+#include <hardware/keymaster_defs.h>
+
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/authorization_set.h>
+#include <keymaster/keymaster_context.h>
+
+namespace keymaster {
+
+class Key {
+ public:
+ virtual ~Key() {}
+
+ /**
+ * Return a copy of raw key material, in the specified format.
+ */
+ virtual keymaster_error_t formatted_key_material(keymaster_key_format_t format,
+ UniquePtr<uint8_t[]>* material,
+ size_t* size) const = 0;
+
+ /**
+ * Generate an attestation certificate chain.
+ */
+ virtual keymaster_error_t GenerateAttestation(
+ const KeymasterContext& /* context */, const AuthorizationSet& /* attest_params */,
+ const AuthorizationSet& /* tee_enforced */, const AuthorizationSet& /* sw_enforced */,
+ keymaster_cert_chain_t* /* certificate_chain */) const {
+ return KM_ERROR_INCOMPATIBLE_ALGORITHM;
+ }
+
+ const AuthorizationSet& authorizations() const { return authorizations_; }
+
+ protected:
+ Key(const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+ keymaster_error_t* error);
+
+ private:
+ AuthorizationSet authorizations_;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_KEY_H_
diff --git a/keymaster/key_blob_test.cpp b/keymaster/key_blob_test.cpp
new file mode 100644
index 0000000..1e590f0
--- /dev/null
+++ b/keymaster/key_blob_test.cpp
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2014 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 <algorithm>
+
+#include <gtest/gtest.h>
+
+#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 "android_keymaster_test_utils.h"
+#include "auth_encrypted_key_blob.h"
+#include "integrity_assured_key_blob.h"
+#include "ocb_utils.h"
+
+namespace keymaster {
+
+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};
+const uint8_t key_data[5] = {21, 22, 23, 24, 25};
+
+class KeyBlobTest : public testing::Test {
+ protected:
+ KeyBlobTest()
+ : master_key_(master_key_data, array_length(master_key_data)),
+ key_material_(key_data, array_length(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);
+ hw_enforced_.push_back(TAG_MIN_SECONDS_BETWEEN_OPS, 10);
+ hw_enforced_.push_back(TAG_ALL_USERS);
+ hw_enforced_.push_back(TAG_NO_AUTH_REQUIRED);
+ hw_enforced_.push_back(TAG_ORIGIN, KM_ORIGIN_GENERATED);
+
+ sw_enforced_.push_back(TAG_ACTIVE_DATETIME, 10);
+ sw_enforced_.push_back(TAG_ORIGINATION_EXPIRE_DATETIME, 100);
+ sw_enforced_.push_back(TAG_CREATION_DATETIME, 10);
+
+ 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 Decrypt() {
+ return OcbDecryptKey(hw_enforced_, sw_enforced_, hidden_, master_key_, ciphertext_, nonce_,
+ tag_, &decrypted_plaintext_);
+ }
+
+ keymaster_error_t Serialize() {
+ return SerializeAuthEncryptedBlob(ciphertext_, hw_enforced_, sw_enforced_, nonce_, tag_,
+ &serialized_blob_);
+ }
+
+ keymaster_error_t Deserialize() {
+ return DeserializeAuthEncryptedBlob(serialized_blob_, &ciphertext_, &hw_enforced_,
+ &sw_enforced_, &nonce_, &tag_);
+ }
+
+ AuthorizationSet hw_enforced_;
+ AuthorizationSet sw_enforced_;
+ AuthorizationSet hidden_;
+ Buffer nonce_, tag_;
+
+ KeymasterKeyBlob master_key_;
+ KeymasterKeyBlob key_material_;
+ KeymasterKeyBlob ciphertext_;
+ KeymasterKeyBlob decrypted_plaintext_;
+ KeymasterKeyBlob serialized_blob_;
+};
+
+TEST_F(KeyBlobTest, EncryptDecrypt) {
+ ASSERT_EQ(KM_ERROR_OK, Encrypt());
+ 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()));
+
+ ciphertext_.Clear();
+ nonce_.Clear();
+ tag_.Clear();
+ AuthorizationSet hw2;
+ AuthorizationSet sw2;
+
+ 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);
+
+ 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));
+}
+
+TEST_F(KeyBlobTest, WrongKeyLength) {
+ ASSERT_EQ(KM_ERROR_OK, Encrypt());
+ ASSERT_EQ(KM_ERROR_OK, Serialize());
+
+ // Modify the key length, shouldn't be able to parse.
+ serialized_blob_.writable_data()[1 /* version */ + 4 /* nonce len */ + 12 /* nonce */ + 3]++;
+
+ ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Deserialize());
+}
+
+TEST_F(KeyBlobTest, WrongNonce) {
+ ASSERT_EQ(KM_ERROR_OK, Encrypt());
+ 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());
+ 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.
+ ASSERT_EQ(KM_ERROR_OK, Deserialize());
+ ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Decrypt());
+}
+
+TEST_F(KeyBlobTest, WrongTag) {
+ 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());
+ 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.
+ ASSERT_EQ(KM_ERROR_OK, Deserialize());
+ ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Decrypt());
+}
+
+TEST_F(KeyBlobTest, WrongCiphertext) {
+ 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());
+ 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.
+ ASSERT_EQ(KM_ERROR_OK, Deserialize());
+ ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Decrypt());
+}
+
+TEST_F(KeyBlobTest, WrongMasterKey) {
+ ASSERT_EQ(KM_ERROR_OK, Encrypt());
+ ASSERT_EQ(KM_ERROR_OK, Serialize());
+
+ uint8_t wrong_master_data[] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ KeymasterKeyBlob wrong_master(wrong_master_data, array_length(wrong_master_data));
+
+ // 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_));
+}
+
+TEST_F(KeyBlobTest, WrongHwEnforced) {
+ ASSERT_EQ(KM_ERROR_OK, Encrypt());
+ ASSERT_EQ(KM_ERROR_OK, Serialize());
+
+ // Find enforced serialization data and modify it.
+ size_t hw_enforced_size = hw_enforced_.SerializedSize();
+ UniquePtr<uint8_t[]> hw_enforced_data(new uint8_t[hw_enforced_size]);
+ hw_enforced_.Serialize(hw_enforced_data.get(), hw_enforced_data.get() + hw_enforced_size);
+
+ auto hw_enforced_ptr =
+ 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.
+ ASSERT_EQ(KM_ERROR_OK, Deserialize());
+ ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Decrypt());
+}
+
+TEST_F(KeyBlobTest, WrongSwEnforced) {
+ ASSERT_EQ(KM_ERROR_OK, Encrypt());
+ 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);
+
+ 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))++;
+
+ // 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) {
+ ASSERT_EQ(KM_ERROR_OK, Encrypt());
+ ASSERT_EQ(KM_ERROR_OK, Serialize());
+
+ AuthorizationSet wrong_hidden;
+
+ // 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_));
+}
+
+TEST_F(KeyBlobTest, WrongRootOfTrust) {
+ ASSERT_EQ(KM_ERROR_OK, Encrypt());
+ ASSERT_EQ(KM_ERROR_OK, Serialize());
+
+ AuthorizationSet wrong_hidden;
+ wrong_hidden.push_back(TAG_ROOT_OF_TRUST, "bar", 2);
+ wrong_hidden.push_back(TAG_APPLICATION_ID, "my_app", 6);
+
+ // 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_));
+}
+
+TEST_F(KeyBlobTest, WrongAppId) {
+ ASSERT_EQ(KM_ERROR_OK, Encrypt());
+ ASSERT_EQ(KM_ERROR_OK, Serialize());
+
+ AuthorizationSet wrong_hidden;
+ wrong_hidden.push_back(TAG_ROOT_OF_TRUST, "foo", 3);
+ wrong_hidden.push_back(TAG_APPLICATION_ID, "your_app", 7);
+
+ // 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_));
+}
+
+// This test is especially useful when compiled for 32-bit mode and run under valgrind.
+TEST_F(KeyBlobTest, FuzzTest) {
+ time_t now = time(NULL);
+ std::cout << "Seeding rand() with " << now << " for fuzz test." << std::endl;
+ srand(now);
+
+ // Fill large buffer with random bytes.
+ const int kBufSize = 10000;
+ UniquePtr<uint8_t[]> buf(new uint8_t[kBufSize]);
+ for (size_t i = 0; i < kBufSize; ++i)
+ buf[i] = static_cast<uint8_t>(rand());
+
+ // Try to deserialize every offset with multiple methods.
+ size_t deserialize_auth_encrypted_success = 0;
+ for (size_t i = 0; i < kBufSize; ++i) {
+ keymaster_key_blob_t blob = {buf.get() + i, kBufSize - i};
+ KeymasterKeyBlob key_blob(blob);
+
+ // Integrity-assured blob.
+ ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB,
+ 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_);
+ 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_);
+ }
+ ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, error)
+ << "Somehow sucessfully parsed a blob with seed " << now << " at offset " << i;
+ }
+}
+
+TEST_F(KeyBlobTest, UnderflowTest) {
+ uint8_t buf[0];
+ keymaster_key_blob_t blob = {buf, 0};
+ KeymasterKeyBlob key_blob(blob);
+ EXPECT_NE(nullptr, key_blob.key_material);
+ EXPECT_EQ(0U, key_blob.key_material_size);
+
+ EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
+ 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_));
+}
+
+TEST_F(KeyBlobTest, DupBufferToolarge) {
+ uint8_t buf[0];
+ keymaster_key_blob_t blob = {buf, 0};
+ blob.key_material_size = 16 * 1024 * 1024 + 1;
+ KeymasterKeyBlob key_blob(blob);
+ EXPECT_EQ(nullptr, key_blob.key_material);
+ EXPECT_EQ(0U, key_blob.key_material_size);
+
+ ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB,
+ 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_));
+}
+
+} // namespace test
+} // namespace keymaster
diff --git a/keymaster/key_exchange.h b/keymaster/key_exchange.h
new file mode 100644
index 0000000..1019e20
--- /dev/null
+++ b/keymaster/key_exchange.h
@@ -0,0 +1,52 @@
+/*
+ * 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_KEY_EXCHANGE_H_
+#define SYSTEM_KEYMASTER_KEY_EXCHANGE_H_
+
+#include <openssl/ec.h>
+
+#include <keymaster/serializable.h>
+
+namespace keymaster {
+
+/**
+ * KeyExchange is an abstract class that provides an interface to a
+ * key-exchange primitive.
+ */
+class KeyExchange {
+ public:
+ virtual ~KeyExchange() {}
+
+ /**
+ * CalculateSharedKey computes the shared key between the local private key
+ * (which is implicitly known by a KeyExchange object) and a public value
+ * from the peer.
+ */
+ virtual bool CalculateSharedKey(const Buffer& peer_public_value, Buffer* shared_key) const = 0;
+ virtual bool CalculateSharedKey(const uint8_t* peer_public_value, size_t peer_public_value_len,
+ Buffer* shared_key) const = 0;
+
+ /**
+ * public_value writes to |public_value| the local public key which can be
+ * sent to a peer in order to complete a key exchange.
+ */
+ virtual bool public_value(Buffer* public_value) const = 0;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_KEY_EXCHANGE_H_
diff --git a/keymaster/keymaster0_engine.cpp b/keymaster/keymaster0_engine.cpp
new file mode 100644
index 0000000..bcd64e5
--- /dev/null
+++ b/keymaster/keymaster0_engine.cpp
@@ -0,0 +1,400 @@
+/*
+ * 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 "keymaster0_engine.h"
+
+#include <assert.h>
+
+#include <memory>
+
+#define LOG_TAG "Keymaster0Engine"
+#include <cutils/log.h>
+
+#include "keymaster/android_keymaster_utils.h"
+
+#include <openssl/bn.h>
+#include <openssl/ec_key.h>
+#include <openssl/ecdsa.h>
+
+#include "openssl_utils.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 */, NULL /* argp */, NULL /* new_func */,
+ keyblob_dup, keyblob_free);
+ ec_key_index_ = EC_KEY_get_ex_new_index(0 /* argl */, NULL /* argp */, NULL /* new_func */,
+ keyblob_dup, keyblob_free);
+
+ rsa_method_.common.references = 0;
+ rsa_method_.common.is_static = 1;
+ rsa_method_.app_data = nullptr;
+ rsa_method_.init = nullptr;
+ rsa_method_.finish = nullptr;
+ rsa_method_.size = nullptr;
+ rsa_method_.sign = nullptr;
+ rsa_method_.verify = nullptr;
+ rsa_method_.encrypt = nullptr;
+ rsa_method_.sign_raw = nullptr;
+ rsa_method_.decrypt = nullptr;
+ rsa_method_.verify_raw = nullptr;
+ rsa_method_.private_transform = Keymaster0Engine::rsa_private_transform;
+ rsa_method_.mod_exp = nullptr;
+ rsa_method_.bn_mod_exp = BN_mod_exp_mont;
+ rsa_method_.flags = RSA_FLAG_OPAQUE;
+ rsa_method_.keygen = nullptr;
+ rsa_method_.supports_digest = nullptr;
+
+ ENGINE_set_RSA_method(engine_, &rsa_method_, sizeof(rsa_method_));
+
+ if ((keymaster0_device_->flags & KEYMASTER_SUPPORTS_EC) != 0) {
+ supports_ec_ = true;
+
+ ecdsa_method_.common.references = 0;
+ ecdsa_method_.common.is_static = 1;
+ ecdsa_method_.app_data = nullptr;
+ ecdsa_method_.init = nullptr;
+ ecdsa_method_.finish = nullptr;
+ ecdsa_method_.group_order_size = nullptr;
+ ecdsa_method_.sign = Keymaster0Engine::ecdsa_sign;
+ ecdsa_method_.verify = nullptr;
+ 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 = 0;
+ if (keymaster0_device_->generate_keypair(keymaster0_device_, TYPE_RSA, ¶ms, &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 = 0;
+ if (keymaster0_device_->generate_keypair(keymaster0_device_, TYPE_EC, ¶ms, &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 = 0;
+ 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 == NULL) {
+ 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 == NULL) {
+ 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/keymaster/keymaster0_engine.h b/keymaster/keymaster0_engine.h
new file mode 100644
index 0000000..aedd85c
--- /dev/null
+++ b/keymaster/keymaster0_engine.h
@@ -0,0 +1,103 @@
+/*
+ * 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 {
+
+struct 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/keymaster/keymaster1_engine.cpp b/keymaster/keymaster1_engine.cpp
new file mode 100644
index 0000000..b20a434
--- /dev/null
+++ b/keymaster/keymaster1_engine.cpp
@@ -0,0 +1,408 @@
+/*
+ * 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 "keymaster1_engine.h"
+
+#include <assert.h>
+
+#include <algorithm>
+#include <memory>
+
+#define LOG_TAG "Keymaster1Engine"
+#include <cutils/log.h>
+
+#include "keymaster/android_keymaster_utils.h"
+
+#include <openssl/bn.h>
+#include <openssl/ec_key.h>
+#include <openssl/ecdsa.h>
+
+#include "openssl_err.h"
+#include "openssl_utils.h"
+
+using std::shared_ptr;
+using std::unique_ptr;
+
+namespace keymaster {
+
+Keymaster1Engine* Keymaster1Engine::instance_ = nullptr;
+
+Keymaster1Engine::Keymaster1Engine(const keymaster1_device_t* keymaster1_device)
+ : keymaster1_device_(keymaster1_device), engine_(ENGINE_new()),
+ rsa_index_(RSA_get_ex_new_index(0 /* argl */, NULL /* argp */, NULL /* new_func */,
+ Keymaster1Engine::duplicate_key_data,
+ Keymaster1Engine::free_key_data)),
+ ec_key_index_(EC_KEY_get_ex_new_index(0 /* argl */, NULL /* argp */, NULL /* 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);
+ assert(keymaster1_device);
+ assert(!instance_);
+
+ instance_ = this;
+
+ ENGINE_set_RSA_method(engine_.get(), &rsa_method_, sizeof(rsa_method_));
+ ENGINE_set_ECDSA_method(engine_.get(), &ecdsa_method_, sizeof(ecdsa_method_));
+}
+
+Keymaster1Engine::~Keymaster1Engine() {
+ keymaster1_device_->common.close(
+ reinterpret_cast<hw_device_t*>(const_cast<keymaster1_device_t*>(keymaster1_device_)));
+ instance_ = nullptr;
+}
+
+static void ConvertCharacteristics(keymaster_key_characteristics_t* characteristics,
+ 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);
+}
+
+keymaster_error_t Keymaster1Engine::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 = keymaster1_device_->generate_key(keymaster1_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);
+ return error;
+}
+
+keymaster_error_t Keymaster1Engine::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 = keymaster1_device_->import_key(keymaster1_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->key_material = dup_buffer(blob.key_material, blob.key_material_size);
+ output_key_blob->key_material_size = blob.key_material_size;
+
+ ConvertCharacteristics(characteristics, hw_enforced, sw_enforced);
+ return error;
+}
+
+keymaster_error_t Keymaster1Engine::DeleteKey(const KeymasterKeyBlob& blob) const {
+ 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;
+ return keymaster1_device_->delete_all_keys(keymaster1_device_);
+}
+
+RSA* Keymaster1Engine::BuildRsaKey(const KeymasterKeyBlob& blob,
+ const AuthorizationSet& additional_params,
+ keymaster_error_t* error) const {
+ // Create new RSA key (with engine methods) and add metadata
+ unique_ptr<RSA, RSA_Delete> rsa(RSA_new_method(engine_.get()));
+ if (!rsa) {
+ *error = TranslateLastOpenSslError();
+ return nullptr;
+ }
+
+ KeyData* key_data = new KeyData(blob, additional_params);
+ if (!RSA_set_ex_data(rsa.get(), rsa_index_, key_data)) {
+ *error = TranslateLastOpenSslError();
+ delete key_data;
+ return nullptr;
+ }
+
+ // 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 (!pkey) {
+ *error = TranslateLastOpenSslError();
+ return nullptr;
+ }
+
+ unique_ptr<RSA, RSA_Delete> public_rsa(EVP_PKEY_get1_RSA(pkey.get()));
+ if (!public_rsa) {
+ *error = TranslateLastOpenSslError();
+ return nullptr;
+ }
+
+ rsa->n = BN_dup(public_rsa->n);
+ rsa->e = BN_dup(public_rsa->e);
+ if (!rsa->n || !rsa->e) {
+ *error = TranslateLastOpenSslError();
+ return nullptr;
+ }
+
+ *error = KM_ERROR_OK;
+ return rsa.release();
+}
+
+EC_KEY* Keymaster1Engine::BuildEcKey(const KeymasterKeyBlob& blob,
+ const AuthorizationSet& additional_params,
+ keymaster_error_t* error) 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_.get()));
+ if (!ec_key) {
+ *error = TranslateLastOpenSslError();
+ return nullptr;
+ }
+
+ KeyData* key_data = new KeyData(blob, additional_params);
+ if (!EC_KEY_set_ex_data(ec_key.get(), ec_key_index_, key_data)) {
+ *error = TranslateLastOpenSslError();
+ delete key_data;
+ return nullptr;
+ }
+
+ // Copy public key into new EC key
+ unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(
+ GetKeymaster1PublicKey(blob, additional_params, error));
+ if (!pkey) {
+ *error = TranslateLastOpenSslError();
+ return nullptr;
+ }
+
+ unique_ptr<EC_KEY, EC_KEY_Delete> public_ec_key(EVP_PKEY_get1_EC_KEY(pkey.get()));
+ if (!public_ec_key) {
+ *error = TranslateLastOpenSslError();
+ 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()))) {
+ *error = TranslateLastOpenSslError();
+ return nullptr;
+ }
+
+ *error = KM_ERROR_OK;
+ return ec_key.release();
+}
+
+Keymaster1Engine::KeyData* Keymaster1Engine::GetData(EVP_PKEY* key) const {
+ switch (EVP_PKEY_type(key->type)) {
+ case EVP_PKEY_RSA: {
+ unique_ptr<RSA, RSA_Delete> rsa(EVP_PKEY_get1_RSA(key));
+ return GetData(rsa.get());
+ }
+
+ case EVP_PKEY_EC: {
+ unique_ptr<EC_KEY, EC_KEY_Delete> ec_key(EVP_PKEY_get1_EC_KEY(key));
+ return GetData(ec_key.get());
+ }
+
+ default:
+ return nullptr;
+ };
+}
+
+Keymaster1Engine::KeyData* Keymaster1Engine::GetData(const RSA* rsa) const {
+ 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;
+ 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 */,
+ void** from_d, int /* index */, long /* argl */,
+ void* /* argp */) {
+ KeyData* data = reinterpret_cast<KeyData*>(*from_d);
+ if (!data)
+ return 1;
+
+ // Default copy ctor is good.
+ *from_d = new KeyData(*data);
+ if (*from_d)
+ return 1;
+ return 0;
+}
+
+/* static */
+void Keymaster1Engine::free_key_data(void* /* parent */, void* ptr, CRYPTO_EX_DATA* /* data */,
+ int /* index*/, long /* argl */, void* /* argp */) {
+ delete reinterpret_cast<KeyData*>(ptr);
+}
+
+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;
+
+ size_t input_consumed;
+ // Note: devices are required to consume all input in a single update call for undigested
+ // signing operations and encryption operations. No need to loop here.
+ 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;
+
+ return device()->finish(device(), key_data->op_handle, &key_data->finish_params,
+ nullptr /* signature */, nullptr /* out_params */, output);
+}
+
+/* static */
+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 (padding != key_data->expected_openssl_padding) {
+ LOG_E("Expected sign_raw with padding %d but got padding %d",
+ key_data->expected_openssl_padding, padding);
+ return KM_ERROR_UNKNOWN_ERROR;
+ }
+
+ 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;
+ unique_ptr<uint8_t, Malloc_Delete> output_deleter(const_cast<uint8_t*>(output.data));
+
+ *out_len = std::min(output.data_length, max_out);
+ memcpy(out, output.data, *out_len);
+ return 1;
+}
+
+/* static */
+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 (padding != key_data->expected_openssl_padding) {
+ LOG_E("Expected sign_raw with padding %d but got padding %d",
+ key_data->expected_openssl_padding, padding);
+ return KM_ERROR_UNKNOWN_ERROR;
+ }
+
+ 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;
+ unique_ptr<uint8_t, Malloc_Delete> output_deleter(const_cast<uint8_t*>(output.data));
+
+ *out_len = std::min(output.data_length, max_out);
+ memcpy(out, output.data, *out_len);
+ return 1;
+}
+
+/* static */
+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;
+
+ // 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_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;
+ 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));
+ memcpy(sig, output.data, *sig_len);
+ return 1;
+}
+
+EVP_PKEY* Keymaster1Engine::GetKeymaster1PublicKey(const KeymasterKeyBlob& blob,
+ const AuthorizationSet& additional_params,
+ keymaster_error_t* error) const {
+ 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;
+
+ 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;
+
+ unique_ptr<uint8_t, Malloc_Delete> pub_key(const_cast<uint8_t*>(export_data.data));
+
+ const uint8_t* p = export_data.data;
+ return d2i_PUBKEY(nullptr /* allocate new struct */, &p, export_data.data_length);
+}
+
+RSA_METHOD Keymaster1Engine::BuildRsaMethod() {
+ RSA_METHOD method = {};
+
+ method.common.is_static = 1;
+ method.sign_raw = Keymaster1Engine::rsa_sign_raw;
+ method.decrypt = Keymaster1Engine::rsa_decrypt;
+ method.bn_mod_exp = BN_mod_exp_mont;
+ method.flags = RSA_FLAG_OPAQUE;
+
+ return method;
+}
+
+ECDSA_METHOD Keymaster1Engine::BuildEcdsaMethod() {
+ ECDSA_METHOD method = {};
+
+ method.common.is_static = 1;
+ method.sign = Keymaster1Engine::ecdsa_sign;
+ method.flags = ECDSA_FLAG_OPAQUE;
+
+ return method;
+}
+
+} // namespace keymaster
diff --git a/keymaster/keymaster1_engine.h b/keymaster/keymaster1_engine.h
new file mode 100644
index 0000000..9e2f13e
--- /dev/null
+++ b/keymaster/keymaster1_engine.h
@@ -0,0 +1,123 @@
+/*
+ * 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_KEYMASTER1_ENGINE_H_
+#define SYSTEM_KEYMASTER_KEYMASTER1_ENGINE_H_
+
+#include <memory>
+
+#include <openssl/ec.h>
+#include <openssl/engine.h>
+#include <openssl/ex_data.h>
+#include <openssl/rsa.h>
+
+#include <hardware/keymaster1.h>
+#include <hardware/keymaster_defs.h>
+
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/authorization_set.h>
+
+#include "openssl_utils.h"
+
+namespace keymaster {
+
+class Keymaster1Engine {
+ public:
+ /**
+ * Create a Keymaster1Engine, wrapping the provided keymaster1_device. The engine takes
+ * ownership of the device, and will close it during destruction.
+ */
+ explicit Keymaster1Engine(const keymaster1_device_t* keymaster1_device);
+ ~Keymaster1Engine();
+
+ keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
+ KeymasterKeyBlob* key_material, AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) const;
+
+ 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;
+ keymaster_error_t DeleteKey(const KeymasterKeyBlob& blob) const;
+ keymaster_error_t DeleteAllKeys() const;
+
+ struct KeyData {
+ KeyData(const KeymasterKeyBlob& blob, const AuthorizationSet& params)
+ : op_handle(0), begin_params(params), key_material(blob), error(KM_ERROR_OK),
+ expected_openssl_padding(-1) {}
+
+ keymaster_operation_handle_t op_handle;
+ AuthorizationSet begin_params;
+ AuthorizationSet finish_params;
+ KeymasterKeyBlob key_material;
+ keymaster_error_t error;
+ int expected_openssl_padding;
+ };
+
+ RSA* BuildRsaKey(const KeymasterKeyBlob& blob, const AuthorizationSet& additional_params,
+ keymaster_error_t* error) const;
+ EC_KEY* BuildEcKey(const KeymasterKeyBlob& blob, const AuthorizationSet& additional_params,
+ keymaster_error_t* error) const;
+
+ KeyData* GetData(EVP_PKEY* key) const;
+ KeyData* GetData(const RSA* rsa) const;
+ KeyData* GetData(const EC_KEY* rsa) const;
+
+ const keymaster1_device_t* device() const { return keymaster1_device_; }
+
+ EVP_PKEY* GetKeymaster1PublicKey(const KeymasterKeyBlob& blob,
+ const AuthorizationSet& additional_params,
+ keymaster_error_t* error) const;
+
+ private:
+ Keymaster1Engine(const Keymaster1Engine&); // Uncopyable
+ void operator=(const Keymaster1Engine&); // Unassignable
+
+ RSA_METHOD BuildRsaMethod();
+ ECDSA_METHOD BuildEcdsaMethod();
+ void ConfigureEngineForRsa();
+ void ConfigureEngineForEcdsa();
+
+ keymaster_error_t Keymaster1Finish(const KeyData* key_data, const keymaster_blob_t& input,
+ keymaster_blob_t* output);
+
+ static int duplicate_key_data(CRYPTO_EX_DATA* to, const CRYPTO_EX_DATA* from, void** from_d,
+ int index, long argl, void* argp);
+ static void free_key_data(void* parent, void* ptr, CRYPTO_EX_DATA* data, int index, long argl,
+ void* argp);
+
+ static int 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);
+ static int 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);
+ static int ecdsa_sign(const uint8_t* digest, size_t digest_len, uint8_t* sig,
+ unsigned int* sig_len, EC_KEY* ec_key);
+
+ const keymaster1_device_t* const keymaster1_device_;
+ const std::unique_ptr<ENGINE, ENGINE_Delete> engine_;
+ const int rsa_index_;
+ const int ec_key_index_;
+
+ const RSA_METHOD rsa_method_;
+ const ECDSA_METHOD ecdsa_method_;
+
+ static Keymaster1Engine* instance_;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_KEYMASTER1_ENGINE_H_
diff --git a/keymaster/keymaster_enforcement.cpp b/keymaster/keymaster_enforcement.cpp
new file mode 100644
index 0000000..7696d89
--- /dev/null
+++ b/keymaster/keymaster_enforcement.cpp
@@ -0,0 +1,574 @@
+/*
+ * Copyright (C) 2014 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/keymaster_enforcement.h>
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+
+#include <openssl/evp.h>
+
+#include <hardware/hw_auth_token.h>
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/logger.h>
+
+#include "List.h"
+
+using android::List;
+
+namespace keymaster {
+
+class AccessTimeMap {
+ public:
+ explicit AccessTimeMap(uint32_t max_size) : max_size_(max_size) {}
+
+ /* If the key is found, returns true and fills \p last_access_time. If not found returns
+ * false. */
+ bool LastKeyAccessTime(km_id_t keyid, uint32_t* last_access_time) const;
+
+ /* Updates the last key access time with the currentTime parameter. Adds the key if
+ * needed, returning false if key cannot be added because list is full. */
+ bool UpdateKeyAccessTime(km_id_t keyid, uint32_t current_time, uint32_t timeout);
+
+ private:
+ struct AccessTime {
+ km_id_t keyid;
+ uint32_t access_time;
+ uint32_t timeout;
+ };
+ android::List<AccessTime> last_access_list_;
+ const uint32_t max_size_;
+};
+
+class AccessCountMap {
+ public:
+ explicit AccessCountMap(uint32_t max_size) : max_size_(max_size) {}
+
+ /* If the key is found, returns true and fills \p count. If not found returns
+ * false. */
+ bool KeyAccessCount(km_id_t keyid, uint32_t* count) const;
+
+ /* Increments key access count, adding an entry if the key has never been used. Returns
+ * false if the list has reached maximum size. */
+ bool IncrementKeyAccessCount(km_id_t keyid);
+
+ private:
+ struct AccessCount {
+ km_id_t keyid;
+ uint64_t access_count;
+ };
+ android::List<AccessCount> access_count_list_;
+ const uint32_t max_size_;
+};
+
+bool is_public_key_algorithm(const AuthorizationSet& auth_set) {
+ keymaster_algorithm_t algorithm;
+ return auth_set.GetTagValue(TAG_ALGORITHM, &algorithm) &&
+ (algorithm == KM_ALGORITHM_RSA || algorithm == KM_ALGORITHM_EC);
+}
+
+static keymaster_error_t authorized_purpose(const keymaster_purpose_t purpose,
+ const AuthorizationSet& auth_set) {
+ switch (purpose) {
+ case KM_PURPOSE_VERIFY:
+ case KM_PURPOSE_ENCRYPT:
+ case KM_PURPOSE_SIGN:
+ case KM_PURPOSE_DECRYPT:
+ if (auth_set.Contains(TAG_PURPOSE, purpose))
+ return KM_ERROR_OK;
+ return KM_ERROR_INCOMPATIBLE_PURPOSE;
+
+ default:
+ return KM_ERROR_UNSUPPORTED_PURPOSE;
+ }
+}
+
+inline bool is_origination_purpose(keymaster_purpose_t purpose) {
+ return purpose == KM_PURPOSE_ENCRYPT || purpose == KM_PURPOSE_SIGN;
+}
+
+inline bool is_usage_purpose(keymaster_purpose_t purpose) {
+ return purpose == KM_PURPOSE_DECRYPT || purpose == KM_PURPOSE_VERIFY;
+}
+
+KeymasterEnforcement::KeymasterEnforcement(uint32_t max_access_time_map_size,
+ uint32_t max_access_count_map_size)
+ : access_time_map_(new (std::nothrow) AccessTimeMap(max_access_time_map_size)),
+ access_count_map_(new (std::nothrow) AccessCountMap(max_access_count_map_size)) {}
+
+KeymasterEnforcement::~KeymasterEnforcement() {
+ delete access_time_map_;
+ delete access_count_map_;
+}
+
+keymaster_error_t KeymasterEnforcement::AuthorizeOperation(const keymaster_purpose_t purpose,
+ const km_id_t keyid,
+ const AuthorizationSet& auth_set,
+ const AuthorizationSet& operation_params,
+ keymaster_operation_handle_t op_handle,
+ bool is_begin_operation) {
+ if (is_public_key_algorithm(auth_set)) {
+ switch (purpose) {
+ case KM_PURPOSE_ENCRYPT:
+ case KM_PURPOSE_VERIFY:
+ /* Public key operations are always authorized. */
+ return KM_ERROR_OK;
+
+ case KM_PURPOSE_DECRYPT:
+ case KM_PURPOSE_SIGN:
+ case KM_PURPOSE_DERIVE_KEY:
+ break;
+ };
+ };
+
+ if (is_begin_operation)
+ return AuthorizeBegin(purpose, keyid, auth_set, operation_params);
+ else
+ return AuthorizeUpdateOrFinish(auth_set, operation_params, op_handle);
+}
+
+// For update and finish the only thing to check is user authentication, and then only if it's not
+// timeout-based.
+keymaster_error_t
+KeymasterEnforcement::AuthorizeUpdateOrFinish(const AuthorizationSet& auth_set,
+ const AuthorizationSet& operation_params,
+ keymaster_operation_handle_t op_handle) {
+ int auth_type_index = -1;
+ for (size_t pos = 0; pos < auth_set.size(); ++pos) {
+ switch (auth_set[pos].tag) {
+ 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.
+ return KM_ERROR_OK;
+
+ case KM_TAG_USER_AUTH_TYPE:
+ auth_type_index = pos;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // Note that at this point we should be able to assume that authentication is required, because
+ // authentication is required if KM_TAG_NO_AUTH_REQUIRED is absent. However, there are legacy
+ // keys which have no authentication-related tags, so we assume that absence is equivalent to
+ // presence of KM_TAG_NO_AUTH_REQUIRED.
+ //
+ // So, if we found KM_TAG_USER_AUTH_TYPE or if we find KM_TAG_USER_SECURE_ID then authentication
+ // is required. If we find neither, then we assume authentication is not required and return
+ // success.
+ bool authentication_required = (auth_type_index != -1);
+ for (auto& param : auth_set) {
+ if (param.tag == KM_TAG_USER_SECURE_ID) {
+ authentication_required = true;
+ int auth_timeout_index = -1;
+ if (AuthTokenMatches(auth_set, operation_params, param.long_integer, auth_type_index,
+ auth_timeout_index, op_handle, false /* is_begin_operation */))
+ return KM_ERROR_OK;
+ }
+ }
+
+ if (authentication_required)
+ return KM_ERROR_KEY_USER_NOT_AUTHENTICATED;
+
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t KeymasterEnforcement::AuthorizeBegin(const keymaster_purpose_t purpose,
+ const km_id_t keyid,
+ const AuthorizationSet& auth_set,
+ const AuthorizationSet& operation_params) {
+ // Find some entries that may be needed to handle KM_TAG_USER_SECURE_ID
+ int auth_timeout_index = -1;
+ int auth_type_index = -1;
+ int no_auth_required_index = -1;
+ for (size_t pos = 0; pos < auth_set.size(); ++pos) {
+ switch (auth_set[pos].tag) {
+ case KM_TAG_AUTH_TIMEOUT:
+ auth_timeout_index = pos;
+ break;
+ case KM_TAG_USER_AUTH_TYPE:
+ auth_type_index = pos;
+ break;
+ case KM_TAG_NO_AUTH_REQUIRED:
+ no_auth_required_index = pos;
+ break;
+ default:
+ break;
+ }
+ }
+
+ keymaster_error_t error = authorized_purpose(purpose, auth_set);
+ 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;
+
+ bool update_access_count = false;
+ bool caller_nonce_authorized_by_key = false;
+ bool authentication_required = false;
+ bool auth_token_matched = false;
+
+ for (auto& param : auth_set) {
+
+ // 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;
+
+ switch (param.tag) {
+
+ case KM_TAG_ACTIVE_DATETIME:
+ if (!activation_date_valid(param.date_time))
+ return KM_ERROR_KEY_NOT_YET_VALID;
+ break;
+
+ case KM_TAG_ORIGINATION_EXPIRE_DATETIME:
+ if (is_origination_purpose(purpose) && expiration_date_passed(param.date_time))
+ return KM_ERROR_KEY_EXPIRED;
+ break;
+
+ case KM_TAG_USAGE_EXPIRE_DATETIME:
+ if (is_usage_purpose(purpose) && expiration_date_passed(param.date_time))
+ return KM_ERROR_KEY_EXPIRED;
+ break;
+
+ case KM_TAG_MIN_SECONDS_BETWEEN_OPS:
+ min_ops_timeout = param.integer;
+ if (!MinTimeBetweenOpsPassed(min_ops_timeout, keyid))
+ return KM_ERROR_KEY_RATE_LIMIT_EXCEEDED;
+ break;
+
+ case KM_TAG_MAX_USES_PER_BOOT:
+ update_access_count = true;
+ if (!MaxUsesPerBootNotExceeded(keyid, param.integer))
+ return KM_ERROR_KEY_MAX_OPS_EXCEEDED;
+ break;
+
+ case KM_TAG_USER_SECURE_ID:
+ if (no_auth_required_index != -1) {
+ // Key has both KM_TAG_USER_SECURE_ID and KM_TAG_NO_AUTH_REQUIRED
+ return KM_ERROR_INVALID_KEY_BLOB;
+ }
+
+ if (auth_timeout_index != -1) {
+ authentication_required = true;
+ if (AuthTokenMatches(auth_set, operation_params, param.long_integer,
+ auth_type_index, auth_timeout_index, 0 /* op_handle */,
+ true /* is_begin_operation */))
+ auth_token_matched = true;
+ }
+ break;
+
+ case KM_TAG_CALLER_NONCE:
+ caller_nonce_authorized_by_key = true;
+ break;
+
+ /* Tags should never be in key auths. */
+ case KM_TAG_INVALID:
+ case KM_TAG_AUTH_TOKEN:
+ case KM_TAG_ROOT_OF_TRUST:
+ case KM_TAG_APPLICATION_DATA:
+ return KM_ERROR_INVALID_KEY_BLOB;
+
+ /* Tags used for cryptographic parameters in keygen. Nothing to enforce. */
+ case KM_TAG_PURPOSE:
+ case KM_TAG_ALGORITHM:
+ case KM_TAG_KEY_SIZE:
+ case KM_TAG_BLOCK_MODE:
+ case KM_TAG_DIGEST:
+ case KM_TAG_MAC_LENGTH:
+ case KM_TAG_PADDING:
+ case KM_TAG_NONCE:
+ case KM_TAG_MIN_MAC_LENGTH:
+ case KM_TAG_KDF:
+ case KM_TAG_EC_CURVE:
+
+ /* Tags not used for operations. */
+ case KM_TAG_BLOB_USAGE_REQUIREMENTS:
+ case KM_TAG_EXPORTABLE:
+
+ /* Algorithm specific parameters not used for access control. */
+ case KM_TAG_RSA_PUBLIC_EXPONENT:
+ case KM_TAG_ECIES_SINGLE_HASH_MODE:
+
+ /* Informational tags. */
+ case KM_TAG_CREATION_DATETIME:
+ case KM_TAG_ORIGIN:
+ case KM_TAG_ROLLBACK_RESISTANT:
+
+ /* Tags handled when KM_TAG_USER_SECURE_ID is handled */
+ case KM_TAG_NO_AUTH_REQUIRED:
+ case KM_TAG_USER_AUTH_TYPE:
+ case KM_TAG_AUTH_TIMEOUT:
+
+ /* Tag to provide data to operations. */
+ case KM_TAG_ASSOCIATED_DATA:
+
+ /* Tags that are implicitly verified by secure side */
+ case KM_TAG_ALL_APPLICATIONS:
+ case KM_TAG_APPLICATION_ID:
+ case KM_TAG_OS_VERSION:
+ case KM_TAG_OS_PATCHLEVEL:
+
+ /* Ignored pending removal */
+ case KM_TAG_USER_ID:
+ case KM_TAG_ALL_USERS:
+
+ /* TODO(swillden): Handle these */
+ 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:
+ break;
+
+ case KM_TAG_BOOTLOADER_ONLY:
+ return KM_ERROR_INVALID_KEY_BLOB;
+ }
+ }
+
+ if (authentication_required && !auth_token_matched) {
+ LOG_E("Auth required but no matching auth token found", 0);
+ return KM_ERROR_KEY_USER_NOT_AUTHENTICATED;
+ }
+
+ if (!caller_nonce_authorized_by_key && is_origination_purpose(purpose) &&
+ operation_params.find(KM_TAG_NONCE) != -1)
+ return KM_ERROR_CALLER_NONCE_PROHIBITED;
+
+ if (min_ops_timeout != UINT32_MAX) {
+ if (!access_time_map_) {
+ LOG_S("Rate-limited keys table not allocated. Rate-limited keys disabled", 0);
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ }
+
+ if (!access_time_map_->UpdateKeyAccessTime(keyid, get_current_time(), min_ops_timeout)) {
+ LOG_E("Rate-limited keys table full. Entries will time out.", 0);
+ return KM_ERROR_TOO_MANY_OPERATIONS;
+ }
+ }
+
+ if (update_access_count) {
+ if (!access_count_map_) {
+ LOG_S("Usage-count limited keys tabel not allocated. Count-limited keys disabled", 0);
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ }
+
+ if (!access_count_map_->IncrementKeyAccessCount(keyid)) {
+ LOG_E("Usage count-limited keys table full, until reboot.", 0);
+ return KM_ERROR_TOO_MANY_OPERATIONS;
+ }
+ }
+
+ return KM_ERROR_OK;
+}
+
+class EvpMdCtx {
+ public:
+ EvpMdCtx() { EVP_MD_CTX_init(&ctx_); }
+ ~EvpMdCtx() { EVP_MD_CTX_cleanup(&ctx_); }
+
+ EVP_MD_CTX* get() { return &ctx_; }
+
+ private:
+ EVP_MD_CTX ctx_;
+};
+
+/* static */
+bool KeymasterEnforcement::CreateKeyId(const keymaster_key_blob_t& key_blob, km_id_t* keyid) {
+ EvpMdCtx ctx;
+
+ uint8_t hash[EVP_MAX_MD_SIZE];
+ unsigned int hash_len;
+ if (EVP_DigestInit_ex(ctx.get(), EVP_sha256(), nullptr /* ENGINE */) &&
+ EVP_DigestUpdate(ctx.get(), key_blob.key_material, key_blob.key_material_size) &&
+ EVP_DigestFinal_ex(ctx.get(), hash, &hash_len)) {
+ assert(hash_len >= sizeof(*keyid));
+ memcpy(keyid, hash, sizeof(*keyid));
+ return true;
+ }
+
+ return false;
+}
+
+bool KeymasterEnforcement::MinTimeBetweenOpsPassed(uint32_t min_time_between, const km_id_t keyid) {
+ if (!access_time_map_)
+ return false;
+
+ uint32_t last_access_time;
+ 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;
+
+ uint32_t key_access_count;
+ if (!access_count_map_->KeyAccessCount(keyid, &key_access_count))
+ return true;
+ return key_access_count < max_uses;
+}
+
+bool KeymasterEnforcement::AuthTokenMatches(const AuthorizationSet& auth_set,
+ const AuthorizationSet& operation_params,
+ const uint64_t user_secure_id,
+ const int auth_type_index, const int auth_timeout_index,
+ const keymaster_operation_handle_t op_handle,
+ bool is_begin_operation) const {
+ 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);
+ 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);
+ return false;
+ }
+
+ if (auth_type_index < 0 || auth_type_index > static_cast<int>(auth_set.size())) {
+ LOG_E("Auth required but no auth type found", 0);
+ return false;
+ }
+
+ 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;
+
+ 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);
+ return false;
+ }
+
+ 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_token_timed_out(auth_token, auth_set[auth_timeout_index].integer)) {
+ LOG_E("Auth token has timed out", 0);
+ return false;
+ }
+ }
+
+ // Survived the whole gauntlet. We have authentage!
+ return true;
+}
+
+bool AccessTimeMap::LastKeyAccessTime(km_id_t keyid, uint32_t* last_access_time) const {
+ for (auto& entry : last_access_list_)
+ if (entry.keyid == keyid) {
+ *last_access_time = entry.access_time;
+ return true;
+ }
+ return false;
+}
+
+bool AccessTimeMap::UpdateKeyAccessTime(km_id_t keyid, uint32_t current_time, uint32_t timeout) {
+ List<AccessTime>::iterator iter;
+ for (iter = last_access_list_.begin(); iter != last_access_list_.end();) {
+ if (iter->keyid == keyid) {
+ iter->access_time = current_time;
+ return true;
+ }
+
+ // Expire entry if possible.
+ assert(current_time >= iter->access_time);
+ if (current_time - iter->access_time >= iter->timeout)
+ iter = last_access_list_.erase(iter);
+ else
+ ++iter;
+ }
+
+ if (last_access_list_.size() >= max_size_)
+ return false;
+
+ AccessTime new_entry;
+ new_entry.keyid = keyid;
+ new_entry.access_time = current_time;
+ new_entry.timeout = timeout;
+ last_access_list_.push_front(new_entry);
+ return true;
+}
+
+bool AccessCountMap::KeyAccessCount(km_id_t keyid, uint32_t* count) const {
+ for (auto& entry : access_count_list_)
+ if (entry.keyid == keyid) {
+ *count = entry.access_count;
+ return true;
+ }
+ return false;
+}
+
+bool AccessCountMap::IncrementKeyAccessCount(km_id_t keyid) {
+ for (auto& entry : access_count_list_)
+ if (entry.keyid == keyid) {
+ // Note that the 'if' below will always be true because KM_TAG_MAX_USES_PER_BOOT is a
+ // uint32_t, and as soon as entry.access_count reaches the specified maximum value
+ // 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;
+ return true;
+ }
+
+ if (access_count_list_.size() >= max_size_)
+ return false;
+
+ AccessCount new_entry;
+ new_entry.keyid = keyid;
+ new_entry.access_count = 1;
+ access_count_list_.push_front(new_entry);
+ return true;
+}
+}; /* namespace keymaster */
diff --git a/keymaster/keymaster_enforcement_test.cpp b/keymaster/keymaster_enforcement_test.cpp
new file mode 100644
index 0000000..3874744
--- /dev/null
+++ b/keymaster/keymaster_enforcement_test.cpp
@@ -0,0 +1,872 @@
+/*
+ * Copyright (C) 2014 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 <errno.h>
+#include <stdio.h>
+#include <time.h>
+
+#include <keymaster/android_keymaster.h>
+#include <keymaster/authorization_set.h>
+#include <keymaster/keymaster_enforcement.h>
+
+#include "android_keymaster_test_utils.h"
+
+namespace keymaster {
+namespace test {
+
+class TestKeymasterEnforcement : public KeymasterEnforcement {
+ public:
+ TestKeymasterEnforcement()
+ : KeymasterEnforcement(3, 3), current_time_(10000), report_token_valid_(true) {}
+
+ keymaster_error_t AuthorizeOperation(const keymaster_purpose_t purpose, const km_id_t keyid,
+ const AuthorizationSet& auth_set) {
+ AuthorizationSet empty_set;
+ return KeymasterEnforcement::AuthorizeOperation(
+ purpose, keyid, auth_set, empty_set, 0 /* op_handle */, true /* is_begin_operation */);
+ }
+ using KeymasterEnforcement::AuthorizeOperation;
+
+ uint32_t get_current_time() const override { return current_time_; }
+ bool activation_date_valid(uint64_t activation_date) const override {
+ // Convert java date to time_t, non-portably.
+ time_t activation_time = activation_date / 1000;
+ return difftime(time(NULL), activation_time) >= 0;
+ }
+ bool expiration_date_passed(uint64_t expiration_date) const override {
+ // Convert jave date to time_t, non-portably.
+ time_t expiration_time = expiration_date / 1000;
+ return difftime(time(NULL), expiration_time) > 0;
+ }
+ bool auth_token_timed_out(const hw_auth_token_t& token, uint32_t timeout) const {
+ return current_time_ > ntoh(token.timestamp) + timeout;
+ }
+ bool ValidateTokenSignature(const hw_auth_token_t&) const override {
+ return report_token_valid_;
+ }
+
+ void tick(unsigned seconds = 1) { current_time_ += seconds; }
+ uint32_t current_time() { return current_time_; }
+ void set_report_token_valid(bool report_token_valid) {
+ report_token_valid_ = report_token_valid;
+ }
+
+ private:
+ uint32_t current_time_;
+ bool report_token_valid_;
+};
+
+class KeymasterBaseTest : public ::testing::Test {
+ protected:
+ KeymasterBaseTest() {
+ past_time = 0;
+
+ time_t t = time(NULL);
+ future_tm = localtime(&t);
+ future_tm->tm_year += 1;
+ future_time = static_cast<uint64_t>(mktime(future_tm)) * 1000;
+ sign_param = Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN);
+ }
+ virtual ~KeymasterBaseTest() {}
+
+ TestKeymasterEnforcement kmen;
+
+ tm past_tm;
+ tm* future_tm;
+ uint64_t past_time;
+ uint64_t future_time;
+ static const km_id_t key_id = 0xa;
+ static const uid_t uid = 0xf;
+ keymaster_key_param_t sign_param;
+};
+
+TEST_F(KeymasterBaseTest, TestValidKeyPeriodNoTags) {
+ keymaster_key_param_t params[] = {
+ sign_param,
+ };
+ AuthorizationSet single_auth_set(params, array_length(params));
+
+ keymaster_error_t kmer = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, single_auth_set);
+ ASSERT_EQ(KM_ERROR_OK, kmer);
+}
+
+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),
+ };
+
+ AuthorizationSet auth_set(params, array_length(params));
+
+ ASSERT_EQ(KM_ERROR_KEY_NOT_YET_VALID,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+
+ // Pubkey ops allowed.
+ ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestValidActiveTime) {
+ keymaster_key_param_t params[] = {
+ Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_ACTIVE_DATETIME, past_time),
+ };
+
+ AuthorizationSet auth_set(params, array_length(params));
+
+ keymaster_error_t kmer_valid_time = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
+ ASSERT_EQ(KM_ERROR_OK, kmer_valid_time);
+}
+
+TEST_F(KeymasterBaseTest, TestInvalidOriginationExpireTime) {
+ keymaster_key_param_t params[] = {
+ Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+ Authorization(TAG_ORIGINATION_EXPIRE_DATETIME, past_time),
+ };
+
+ AuthorizationSet auth_set(params, array_length(params));
+
+ ASSERT_EQ(KM_ERROR_KEY_EXPIRED, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+
+ // Pubkey ops allowed.
+ ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestInvalidOriginationExpireTimeOnUsgae) {
+ keymaster_key_param_t params[] = {
+ Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+ Authorization(TAG_ORIGINATION_EXPIRE_DATETIME, past_time),
+ };
+
+ AuthorizationSet auth_set(params, array_length(params));
+
+ keymaster_error_t kmer_invalid_origination =
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set);
+ ASSERT_EQ(KM_ERROR_OK, kmer_invalid_origination);
+}
+
+TEST_F(KeymasterBaseTest, TestValidOriginationExpireTime) {
+ keymaster_key_param_t params[] = {
+ Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+ Authorization(TAG_ORIGINATION_EXPIRE_DATETIME, future_time),
+ };
+
+ AuthorizationSet auth_set(params, array_length(params));
+
+ keymaster_error_t kmer_valid_origination =
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
+ ASSERT_EQ(KM_ERROR_OK, kmer_valid_origination);
+}
+
+TEST_F(KeymasterBaseTest, TestInvalidUsageExpireTime) {
+ keymaster_key_param_t params[] = {
+ Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES),
+ Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+ Authorization(TAG_USAGE_EXPIRE_DATETIME, past_time),
+ };
+
+ AuthorizationSet auth_set(params, array_length(params));
+
+ keymaster_error_t kmer_invalid_origination =
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set);
+ ASSERT_EQ(KM_ERROR_KEY_EXPIRED, kmer_invalid_origination);
+}
+
+TEST_F(KeymasterBaseTest, TestInvalidPubkeyUsageExpireTime) {
+ keymaster_key_param_t params[] = {
+ Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
+ Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+ Authorization(TAG_USAGE_EXPIRE_DATETIME, past_time),
+ };
+
+ AuthorizationSet auth_set(params, array_length(params));
+
+ keymaster_error_t kmer_invalid_origination =
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set);
+ // Pubkey ops allowed.
+ ASSERT_EQ(KM_ERROR_OK, kmer_invalid_origination);
+}
+
+TEST_F(KeymasterBaseTest, TestInvalidUsageExpireTimeOnOrigination) {
+ keymaster_key_param_t params[] = {
+ Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+ Authorization(TAG_USAGE_EXPIRE_DATETIME, past_time),
+ };
+
+ AuthorizationSet auth_set(params, array_length(params));
+
+ keymaster_error_t kmer_invalid_origination =
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
+ ASSERT_EQ(KM_ERROR_OK, kmer_invalid_origination);
+}
+
+TEST_F(KeymasterBaseTest, TestValidUsageExpireTime) {
+ keymaster_key_param_t params[] = {
+ Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+ Authorization(TAG_USAGE_EXPIRE_DATETIME, future_time),
+ };
+
+ AuthorizationSet auth_set(params, array_length(params));
+
+ keymaster_error_t kmer_valid_usage =
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set);
+ ASSERT_EQ(KM_ERROR_OK, kmer_valid_usage);
+}
+
+TEST_F(KeymasterBaseTest, TestValidSingleUseAccesses) {
+ keymaster_key_param_t params[] = {
+ Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+ };
+
+ AuthorizationSet auth_set(params, array_length(params));
+
+ keymaster_error_t kmer1 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
+ keymaster_error_t kmer2 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
+
+ ASSERT_EQ(KM_ERROR_OK, kmer1);
+ ASSERT_EQ(KM_ERROR_OK, kmer2);
+}
+
+TEST_F(KeymasterBaseTest, TestInvalidMaxOps) {
+ keymaster_key_param_t params[] = {
+ Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
+ Authorization(TAG_MAX_USES_PER_BOOT, 4),
+ };
+
+ AuthorizationSet auth_set(params, array_length(params));
+
+ ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+ ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+ ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+ ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+ ASSERT_EQ(KM_ERROR_KEY_MAX_OPS_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+ // Pubkey ops allowed.
+ ASSERT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestOverFlowMaxOpsTable) {
+ keymaster_key_param_t params[] = {
+ Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+ Authorization(TAG_MAX_USES_PER_BOOT, 2),
+ };
+
+ AuthorizationSet auth_set(params, array_length(params));
+
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, auth_set));
+
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 2 /* key_id */, auth_set));
+
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 3 /* key_id */, auth_set));
+
+ // Key 4 should fail, because table is full.
+ EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 4 /* key_id */, auth_set));
+
+ // Key 1 still works, because it's already in the table and hasn't reached max.
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, auth_set));
+
+ // Key 1 no longer works, because it's reached max.
+ EXPECT_EQ(KM_ERROR_KEY_MAX_OPS_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, auth_set));
+
+ // Key 4 should fail, because table is (still and forever) full.
+ EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 4 /* key_id */, auth_set));
+
+ // Pubkey ops allowed.
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 4 /* key_id */, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestInvalidTimeBetweenOps) {
+ keymaster_key_param_t params[] = {
+ Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA), Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+ Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 10),
+ };
+
+ AuthorizationSet auth_set(params, array_length(params));
+
+ keymaster_error_t kmer1 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
+ keymaster_error_t kmer2 = kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set);
+ keymaster_error_t kmer3 = kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set);
+
+ ASSERT_EQ(KM_ERROR_OK, kmer1);
+ kmen.tick(2);
+ ASSERT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED, kmer2);
+
+ // Allowed because it's a pubkey op.
+ ASSERT_EQ(KM_ERROR_OK, kmer3);
+}
+
+TEST_F(KeymasterBaseTest, TestValidTimeBetweenOps) {
+ keymaster_key_param_t params[] = {
+ Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+ Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 2),
+ };
+
+ AuthorizationSet auth_set(params, array_length(params));
+
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set));
+ kmen.tick();
+ EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+ kmen.tick();
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestOptTimeoutTableOverflow) {
+ keymaster_key_param_t params[] = {
+ Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES),
+ Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, 4),
+ Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+ };
+
+ AuthorizationSet auth_set(params, array_length(params));
+
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
+
+ kmen.tick();
+
+ // Key 1 fails because it's too soon
+ EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
+
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set));
+
+ kmen.tick();
+
+ // Key 1 fails because it's too soon
+ EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
+ // Key 2 fails because it's too soon
+ EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set));
+
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, auth_set));
+
+ kmen.tick();
+
+ // Key 1 fails because it's too soon
+ EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
+ // Key 2 fails because it's too soon
+ EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set));
+ // Key 3 fails because it's too soon
+ EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, auth_set));
+ // Key 4 fails because the table is full
+ EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 4 /* key_id */, auth_set));
+
+ kmen.tick();
+
+ // Key 4 succeeds because key 1 expired.
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 4 /* key_id */, auth_set));
+
+ // Key 1 fails because the table is full... and key 1 is no longer in it.
+ EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
+ // Key 2 fails because it's too soon
+ EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set));
+ // Key 3 fails because it's too soon
+ EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, auth_set));
+
+ kmen.tick();
+
+ // Key 1 succeeds because key 2 expired
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
+ // Key 2 fails because the table is full... and key 2 is no longer in it.
+ EXPECT_EQ(KM_ERROR_TOO_MANY_OPERATIONS,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set));
+ // Key 3 fails because it's too soon
+ EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, auth_set));
+ // Key 4 fails because it's too soon
+ EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 4 /* key_id */, auth_set));
+
+ kmen.tick(4);
+
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 2 /* key_id */, auth_set));
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 3 /* key_id */, auth_set));
+}
+
+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),
+ };
+
+ AuthorizationSet auth_set(params, array_length(params));
+
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, auth_set));
+
+ kmen.tick();
+
+ // Key 1 fails because it's too soon
+ EXPECT_EQ(KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, 1 /* key_id */, auth_set));
+ // Too soo, but pubkey ops allowed.
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, 1 /* key_id */, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestInvalidPurpose) {
+ keymaster_purpose_t invalidPurpose1 = static_cast<keymaster_purpose_t>(-1);
+ keymaster_purpose_t invalidPurpose2 = static_cast<keymaster_purpose_t>(4);
+
+ AuthorizationSet auth_set(
+ AuthorizationSetBuilder().Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY));
+
+ EXPECT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE,
+ kmen.AuthorizeOperation(invalidPurpose1, key_id, auth_set));
+ EXPECT_EQ(KM_ERROR_UNSUPPORTED_PURPOSE,
+ kmen.AuthorizeOperation(invalidPurpose2, key_id, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestIncompatiblePurposeSymmetricKey) {
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set));
+
+ EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE,
+ kmen.AuthorizeOperation(KM_PURPOSE_ENCRYPT, key_id, auth_set));
+ EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE,
+ kmen.AuthorizeOperation(KM_PURPOSE_DECRYPT, key_id, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestIncompatiblePurposeAssymmetricKey) {
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set));
+
+ // This one is allowed because it's a pubkey op.
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_ENCRYPT, key_id, auth_set));
+ EXPECT_EQ(KM_ERROR_INCOMPATIBLE_PURPOSE,
+ kmen.AuthorizeOperation(KM_PURPOSE_DECRYPT, key_id, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestInvalidCallerNonce) {
+ AuthorizationSet no_caller_nonce(AuthorizationSetBuilder()
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_ENCRYPT)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_DECRYPT)
+ .Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES));
+ AuthorizationSet caller_nonce(AuthorizationSetBuilder()
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_ENCRYPT)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_DECRYPT)
+ .Authorization(TAG_ALGORITHM, KM_ALGORITHM_HMAC)
+ .Authorization(TAG_CALLER_NONCE));
+ AuthorizationSet begin_params(AuthorizationSetBuilder().Authorization(TAG_NONCE, "foo", 3));
+
+ EXPECT_EQ(KM_ERROR_OK,
+ kmen.AuthorizeOperation(KM_PURPOSE_ENCRYPT, key_id, caller_nonce, begin_params,
+ 0 /* challenge */, true /* is_begin_operation */));
+ EXPECT_EQ(KM_ERROR_OK,
+ kmen.AuthorizeOperation(KM_PURPOSE_DECRYPT, key_id, caller_nonce, begin_params,
+ 0 /* challenge */, true /* is_begin_operation */));
+ EXPECT_EQ(KM_ERROR_CALLER_NONCE_PROHIBITED,
+ kmen.AuthorizeOperation(KM_PURPOSE_ENCRYPT, key_id, no_caller_nonce, begin_params,
+ 0 /* challenge */, true /* is_begin_operation */));
+ EXPECT_EQ(KM_ERROR_OK,
+ kmen.AuthorizeOperation(KM_PURPOSE_DECRYPT, key_id, no_caller_nonce, begin_params,
+ 0 /* challenge */, true /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestBootloaderOnly) {
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
+ .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+ .Authorization(TAG_BOOTLOADER_ONLY));
+ EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+
+ // Pubkey ops allowed.
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestInvalidTag) {
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_INVALID)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestAuthPerOpSuccess) {
+ hw_auth_token_t token;
+ memset(&token, 0, sizeof(token));
+ token.version = HW_AUTH_TOKEN_VERSION;
+ token.challenge = 99;
+ token.user_id = 9;
+ token.authenticator_id = 0;
+ token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+ token.timestamp = 0;
+
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_USER_SECURE_ID, token.user_id)
+ .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ AuthorizationSet op_params;
+ op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+ EXPECT_EQ(KM_ERROR_OK,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+ false /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestAuthPerOpInvalidTokenSignature) {
+ hw_auth_token_t token;
+ memset(&token, 0, sizeof(token));
+ token.version = HW_AUTH_TOKEN_VERSION;
+ token.challenge = 99;
+ token.user_id = 9;
+ token.authenticator_id = 0;
+ token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+ token.timestamp = 0;
+
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_ALGORITHM, KM_ALGORITHM_EC)
+ .Authorization(TAG_USER_SECURE_ID, token.user_id)
+ .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ AuthorizationSet op_params;
+ op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+ kmen.set_report_token_valid(false);
+ EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+ false /* is_begin_operation */));
+ // Pubkey ops allowed.
+ EXPECT_EQ(KM_ERROR_OK,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params,
+ token.challenge, false /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestAuthPerOpWrongChallenge) {
+ hw_auth_token_t token;
+ memset(&token, 0, sizeof(token));
+ token.version = HW_AUTH_TOKEN_VERSION;
+ token.challenge = 99;
+ token.user_id = 9;
+ token.authenticator_id = 0;
+ token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+ token.timestamp = 0;
+
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_USER_SECURE_ID, token.user_id)
+ .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ AuthorizationSet op_params;
+ op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+ EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
+ token.challenge + 1 /* doesn't match token */,
+ false /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestAuthPerOpNoAuthType) {
+ hw_auth_token_t token;
+ memset(&token, 0, sizeof(token));
+ token.version = HW_AUTH_TOKEN_VERSION;
+ token.challenge = 99;
+ token.user_id = 9;
+ token.authenticator_id = 0;
+ token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+ token.timestamp = 0;
+
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+ .Authorization(TAG_USER_SECURE_ID, token.user_id)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ AuthorizationSet op_params;
+ op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+ EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+ false /* is_begin_operation */));
+ // Pubkey ops allowed.
+ EXPECT_EQ(KM_ERROR_OK,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params,
+ token.challenge, false /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestAuthPerOpWrongAuthType) {
+ hw_auth_token_t token;
+ memset(&token, 0, sizeof(token));
+ token.version = HW_AUTH_TOKEN_VERSION;
+ token.challenge = 99;
+ token.user_id = 9;
+ token.authenticator_id = 0;
+ token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+ token.timestamp = 0;
+
+ AuthorizationSet auth_set(
+ AuthorizationSetBuilder()
+ .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+ .Authorization(TAG_USER_SECURE_ID, token.user_id)
+ .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_FINGERPRINT /* doesn't match token */)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ AuthorizationSet op_params;
+ op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+ EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+ false /* is_begin_operation */));
+ // Pubkey ops allowed.
+ EXPECT_EQ(KM_ERROR_OK,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params,
+ token.challenge, false /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestAuthPerOpWrongSid) {
+ hw_auth_token_t token;
+ memset(&token, 0, sizeof(token));
+ token.version = HW_AUTH_TOKEN_VERSION;
+ token.challenge = 99;
+ token.user_id = 9;
+ token.authenticator_id = 0;
+ token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+ token.timestamp = 0;
+
+ AuthorizationSet auth_set(
+ AuthorizationSetBuilder()
+ .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+ .Authorization(TAG_USER_SECURE_ID, token.user_id + 1 /* doesn't match token */)
+ .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ AuthorizationSet op_params;
+ op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+ EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+ false /* is_begin_operation */));
+ // Pubkey op allowed.
+ EXPECT_EQ(KM_ERROR_OK,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params,
+ token.challenge, false /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestAuthPerOpSuccessAlternateSid) {
+ hw_auth_token_t token;
+ memset(&token, 0, sizeof(token));
+ token.version = HW_AUTH_TOKEN_VERSION;
+ token.challenge = 99;
+ token.user_id = 9;
+ token.authenticator_id = 10;
+ token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+ token.timestamp = 0;
+
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_USER_SECURE_ID, token.authenticator_id)
+ .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ AuthorizationSet op_params;
+ op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+ EXPECT_EQ(KM_ERROR_OK,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+ false /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestAuthPerOpMissingToken) {
+ hw_auth_token_t token;
+ memset(&token, 0, sizeof(token));
+ token.version = HW_AUTH_TOKEN_VERSION;
+ token.challenge = 99;
+ token.user_id = 9;
+ token.authenticator_id = 0;
+ token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+ token.timestamp = 0;
+
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+ .Authorization(TAG_USER_SECURE_ID, token.user_id)
+ .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ AuthorizationSet op_params;
+
+ // During begin we can skip the auth token
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
+ token.challenge, true /* is_begin_operation */));
+ // Afterwards we must have authentication
+ EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+ false /* is_begin_operation */));
+ // Pubkey ops allowed
+ EXPECT_EQ(KM_ERROR_OK,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params,
+ token.challenge, false /* is_begin_operation */));
+
+ auth_set.Reinitialize(AuthorizationSetBuilder()
+ .Authorization(TAG_ALGORITHM, KM_ALGORITHM_AES)
+ .Authorization(TAG_USER_SECURE_ID, token.user_id)
+ .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN)
+ .build());
+
+ EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params,
+ token.challenge, false /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestAuthAndNoAuth) {
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_USER_SECURE_ID, 1)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set));
+}
+
+TEST_F(KeymasterBaseTest, TestTimedAuthSuccess) {
+ hw_auth_token_t token;
+ memset(&token, 0, sizeof(token));
+ token.version = HW_AUTH_TOKEN_VERSION;
+ token.challenge = 99;
+ token.user_id = 9;
+ token.authenticator_id = 0;
+ token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+ token.timestamp = hton(kmen.current_time());
+
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+ .Authorization(TAG_USER_SECURE_ID, token.user_id)
+ .Authorization(TAG_AUTH_TIMEOUT, 1)
+ .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ AuthorizationSet op_params;
+ op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+ EXPECT_EQ(KM_ERROR_OK,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
+ 0 /* irrelevant */, false /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestTimedAuthTimedOut) {
+ hw_auth_token_t token;
+ memset(&token, 0, sizeof(token));
+ token.version = HW_AUTH_TOKEN_VERSION;
+ token.challenge = 99;
+ token.user_id = 9;
+ token.authenticator_id = 0;
+ token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+ token.timestamp = hton(static_cast<uint64_t>(kmen.current_time()));
+
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+ .Authorization(TAG_USER_SECURE_ID, token.user_id)
+ .Authorization(TAG_AUTH_TIMEOUT, 1)
+ .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ AuthorizationSet op_params;
+ op_params.push_back(Authorization(TAG_AUTH_TOKEN, &token, sizeof(token)));
+
+ EXPECT_EQ(KM_ERROR_OK,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
+ 0 /* irrelevant */, false /* is_begin_operation */));
+
+ kmen.tick(1);
+
+ // token still good
+ EXPECT_EQ(KM_ERROR_OK,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
+ 0 /* irrelevant */, false /* is_begin_operation */));
+
+ kmen.tick(1);
+
+ // token expired, not allowed during begin.
+ EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
+ 0 /* irrelevant */, true /* is_begin_operation */));
+
+ // token expired, afterwards it's okay.
+ EXPECT_EQ(KM_ERROR_OK,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params,
+ 0 /* irrelevant */, false /* is_begin_operation */));
+
+ // Pubkey ops allowed.
+ EXPECT_EQ(KM_ERROR_OK,
+ kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params,
+ 0 /* irrelevant */, true /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestTimedAuthMissingToken) {
+ hw_auth_token_t token;
+ memset(&token, 0, sizeof(token));
+ token.version = HW_AUTH_TOKEN_VERSION;
+ token.challenge = 99;
+ token.user_id = 9;
+ token.authenticator_id = 0;
+ token.authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD));
+ token.timestamp = hton(static_cast<uint64_t>(kmen.current_time()));
+
+ AuthorizationSet auth_set(AuthorizationSetBuilder()
+ .Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA)
+ .Authorization(TAG_USER_SECURE_ID, token.user_id)
+ .Authorization(TAG_AUTH_TIMEOUT, 1)
+ .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_ANY)
+ .Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN));
+
+ AuthorizationSet op_params;
+
+ // Unlike auth-per-op, must have the auth token during begin.
+ EXPECT_EQ(KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+ true /* is_begin_operation */));
+
+ // Later we don't check (though begin would fail, so there wouldn't be a later).
+ EXPECT_EQ(KM_ERROR_OK,
+ kmen.AuthorizeOperation(KM_PURPOSE_SIGN, key_id, auth_set, op_params, token.challenge,
+ false /* is_begin_operation */));
+
+ // Pubkey ops allowed.
+ EXPECT_EQ(KM_ERROR_OK, kmen.AuthorizeOperation(KM_PURPOSE_VERIFY, key_id, auth_set, op_params,
+ token.challenge, true /* is_begin_operation */));
+}
+
+TEST_F(KeymasterBaseTest, TestCreateKeyId) {
+ keymaster_key_blob_t blob = {reinterpret_cast<const uint8_t*>("foobar"), 6};
+
+ km_id_t key_id = 0;
+ EXPECT_TRUE(KeymasterEnforcement::CreateKeyId(blob, &key_id));
+ EXPECT_NE(0U, key_id);
+}
+
+}; /* namespace test */
+}; /* namespace keymaster */
diff --git a/keymaster/keymaster_tags.cpp b/keymaster/keymaster_tags.cpp
new file mode 100644
index 0000000..ce7156f
--- /dev/null
+++ b/keymaster/keymaster_tags.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2014 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/keymaster_tags.h>
+
+namespace keymaster {
+
+#ifdef KEYMASTER_NAME_TAGS
+const char* StringifyTag(keymaster_tag_t tag) {
+ switch (tag) {
+ case KM_TAG_INVALID:
+ return "KM_TAG_INVALID";
+ case KM_TAG_PURPOSE:
+ return "KM_TAG_PURPOSE";
+ case KM_TAG_ALGORITHM:
+ return "KM_TAG_ALGORITHM";
+ case KM_TAG_KEY_SIZE:
+ return "KM_TAG_KEY_SIZE";
+ case KM_TAG_BLOCK_MODE:
+ return "KM_TAG_BLOCK_MODE";
+ case KM_TAG_DIGEST:
+ return "KM_TAG_DIGEST";
+ case KM_TAG_PADDING:
+ return "KM_TAG_PADDING";
+ case KM_TAG_CALLER_NONCE:
+ return "KM_TAG_CALLER_NONCE";
+ case KM_TAG_MIN_MAC_LENGTH:
+ return "KM_TAG_MIN_MAC_LENGTH";
+ case KM_TAG_RSA_PUBLIC_EXPONENT:
+ return "KM_TAG_RSA_PUBLIC_EXPONENT";
+ case KM_TAG_BLOB_USAGE_REQUIREMENTS:
+ return "KM_TAG_BLOB_USAGE_REQUIREMENTS";
+ case KM_TAG_BOOTLOADER_ONLY:
+ return "KM_TAG_BOOTLOADER_ONLY";
+ case KM_TAG_ACTIVE_DATETIME:
+ return "KM_TAG_ACTIVE_DATETIME";
+ case KM_TAG_ORIGINATION_EXPIRE_DATETIME:
+ return "KM_TAG_ORIGINATION_EXPIRE_DATETIME";
+ case KM_TAG_USAGE_EXPIRE_DATETIME:
+ return "KM_TAG_USAGE_EXPIRE_DATETIME";
+ case KM_TAG_MIN_SECONDS_BETWEEN_OPS:
+ return "KM_TAG_MIN_SECONDS_BETWEEN_OPS";
+ case KM_TAG_MAX_USES_PER_BOOT:
+ return "KM_TAG_MAX_USES_PER_BOOT";
+ case KM_TAG_ALL_USERS:
+ return "KM_TAG_ALL_USERS";
+ case KM_TAG_USER_ID:
+ return "KM_TAG_USER_ID";
+ case KM_TAG_USER_SECURE_ID:
+ return "KM_TAG_USER_SECURE_ID";
+ case KM_TAG_NO_AUTH_REQUIRED:
+ return "KM_TAG_NO_AUTH_REQUIRED";
+ case KM_TAG_USER_AUTH_TYPE:
+ return "KM_TAG_USER_AUTH_TYPE";
+ case KM_TAG_AUTH_TIMEOUT:
+ return "KM_TAG_AUTH_TIMEOUT";
+ case KM_TAG_ALL_APPLICATIONS:
+ return "KM_TAG_ALL_APPLICATIONS";
+ case KM_TAG_APPLICATION_ID:
+ return "KM_TAG_APPLICATION_ID";
+ case KM_TAG_APPLICATION_DATA:
+ return "KM_TAG_APPLICATION_DATA";
+ case KM_TAG_CREATION_DATETIME:
+ return "KM_TAG_CREATION_DATETIME";
+ case KM_TAG_ORIGIN:
+ return "KM_TAG_ORIGIN";
+ case KM_TAG_ROLLBACK_RESISTANT:
+ return "KM_TAG_ROLLBACK_RESISTANT";
+ case KM_TAG_ROOT_OF_TRUST:
+ return "KM_TAG_ROOT_OF_TRUST";
+ case KM_TAG_ASSOCIATED_DATA:
+ return "KM_TAG_ASSOCIATED_DATA";
+ case KM_TAG_NONCE:
+ return "KM_TAG_NONCE";
+ case KM_TAG_AUTH_TOKEN:
+ return "KM_TAG_AUTH_TOKEN";
+ case KM_TAG_MAC_LENGTH:
+ return "KM_TAG_MAC_LENGTH";
+ case KM_TAG_KDF:
+ return "KM_TAG_KDF";
+ case KM_TAG_EC_CURVE:
+ return "KM_TAG_EC_CURVE";
+ case KM_TAG_ECIES_SINGLE_HASH_MODE:
+ return "KM_TAG_ECIES_SINGLE_HASH_MODE";
+ case KM_TAG_OS_VERSION:
+ return "KM_TAG_OS_VERSION";
+ case KM_TAG_OS_PATCHLEVEL:
+ return "KM_TAG_OS_PATCHLEVEL";
+ case KM_TAG_EXPORTABLE:
+ return "KM_TAG_EXPORTABLE";
+ case KM_TAG_UNIQUE_ID:
+ return "KM_TAG_UNIQUE_ID";
+ case KM_TAG_INCLUDE_UNIQUE_ID:
+ return "KM_TAG_INCLUDE_UNIQUE_ID";
+ case KM_TAG_RESET_SINCE_ID_ROTATION:
+ return "KM_TAG_RESET_SINCE_ID_ROTATION";
+ case KM_TAG_ALLOW_WHILE_ON_BODY:
+ return "KM_TAG_ALLOW_WHILE_ON_BODY";
+ }
+ return "<Unknown>";
+}
+#endif // KEYMASTER_NAME_TAGS
+
+// DEFINE_KEYMASTER_TAG is used to create TypedTag instances for each non-enum keymaster tag.
+#define DEFINE_KEYMASTER_TAG(type, name) TypedTag<type, KM_##name> name
+
+DEFINE_KEYMASTER_TAG(KM_INVALID, TAG_INVALID);
+DEFINE_KEYMASTER_TAG(KM_UINT, TAG_KEY_SIZE);
+DEFINE_KEYMASTER_TAG(KM_UINT, TAG_MAC_LENGTH);
+DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_CALLER_NONCE);
+DEFINE_KEYMASTER_TAG(KM_UINT, TAG_MIN_MAC_LENGTH);
+DEFINE_KEYMASTER_TAG(KM_ULONG, TAG_RSA_PUBLIC_EXPONENT);
+DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_ECIES_SINGLE_HASH_MODE);
+DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_INCLUDE_UNIQUE_ID);
+DEFINE_KEYMASTER_TAG(KM_DATE, TAG_ACTIVE_DATETIME);
+DEFINE_KEYMASTER_TAG(KM_DATE, TAG_ORIGINATION_EXPIRE_DATETIME);
+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_BOOL, TAG_ALL_USERS);
+DEFINE_KEYMASTER_TAG(KM_UINT, TAG_USER_ID);
+DEFINE_KEYMASTER_TAG(KM_ULONG_REP, TAG_USER_SECURE_ID);
+DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_NO_AUTH_REQUIRED);
+DEFINE_KEYMASTER_TAG(KM_UINT, TAG_AUTH_TIMEOUT);
+DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_ALLOW_WHILE_ON_BODY);
+DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_ALL_APPLICATIONS);
+DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_APPLICATION_ID);
+DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_APPLICATION_DATA);
+DEFINE_KEYMASTER_TAG(KM_DATE, TAG_CREATION_DATETIME);
+DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_ROLLBACK_RESISTANT);
+DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_ROOT_OF_TRUST);
+DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_ASSOCIATED_DATA);
+DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_NONCE);
+DEFINE_KEYMASTER_TAG(KM_BYTES, TAG_AUTH_TOKEN);
+DEFINE_KEYMASTER_TAG(KM_BOOL, TAG_BOOTLOADER_ONLY);
+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_ENUM_TAG is used to create TypedEnumTag instances for each enum keymaster tag.
+
+#define DEFINE_KEYMASTER_ENUM_TAG(type, name, enumtype) TypedEnumTag<type, KM_##name, enumtype> name
+
+DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_PURPOSE, keymaster_purpose_t);
+DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_ALGORITHM, keymaster_algorithm_t);
+DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_BLOCK_MODE, keymaster_block_mode_t);
+DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_DIGEST, keymaster_digest_t);
+DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_DIGEST_OLD, keymaster_digest_t);
+DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM_REP, TAG_PADDING, keymaster_padding_t);
+DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_PADDING_OLD, keymaster_padding_t);
+DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_BLOB_USAGE_REQUIREMENTS,
+ keymaster_key_blob_usage_requirements_t);
+DEFINE_KEYMASTER_ENUM_TAG(KM_ENUM, TAG_ORIGIN, keymaster_key_origin_t);
+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);
+
+} // namespace keymaster
diff --git a/keymaster/km0_sw_rsa_512.blob b/keymaster/km0_sw_rsa_512.blob
new file mode 100644
index 0000000..7fee81c
--- /dev/null
+++ b/keymaster/km0_sw_rsa_512.blob
Binary files differ
diff --git a/keymaster/km1_sw_ecdsa_256.blob b/keymaster/km1_sw_ecdsa_256.blob
new file mode 100644
index 0000000..5b9a6f4
--- /dev/null
+++ b/keymaster/km1_sw_ecdsa_256.blob
Binary files differ
diff --git a/keymaster/km1_sw_rsa_512.blob b/keymaster/km1_sw_rsa_512.blob
new file mode 100644
index 0000000..db1730a
--- /dev/null
+++ b/keymaster/km1_sw_rsa_512.blob
Binary files differ
diff --git a/keymaster/km1_sw_rsa_512_unversioned.blob b/keymaster/km1_sw_rsa_512_unversioned.blob
new file mode 100644
index 0000000..e4f6a11
--- /dev/null
+++ b/keymaster/km1_sw_rsa_512_unversioned.blob
Binary files differ
diff --git a/keymaster/logger.cpp b/keymaster/logger.cpp
new file mode 100644
index 0000000..f86a68f
--- /dev/null
+++ b/keymaster/logger.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2014 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/logger.h>
+
+namespace keymaster {
+
+Logger* Logger::instance_ = 0;
+
+/* static */
+int Logger::Log(LogLevel level, const char* fmt, va_list args) {
+ if (!instance_)
+ return 0;
+ return instance_->log_msg(level, fmt, args);
+}
+
+/* static */
+int Logger::Log(LogLevel level, const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ int result = Log(level, fmt, args);
+ va_end(args);
+ return result;
+}
+
+/* static */
+int Logger::Debug(const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ int result = Log(DEBUG_LVL, fmt, args);
+ va_end(args);
+ return result;
+}
+
+/* static */
+int Logger::Info(const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ int result = Log(INFO_LVL, fmt, args);
+ va_end(args);
+ return result;
+}
+/* static */
+int Logger::Warning(const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ int result = Log(WARNING_LVL, fmt, args);
+ va_end(args);
+ return result;
+}
+/* static */
+int Logger::Error(const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ int result = Log(ERROR_LVL, fmt, args);
+ va_end(args);
+ return result;
+}
+/* static */
+int Logger::Severe(const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ int result = Log(SEVERE_LVL, fmt, args);
+ va_end(args);
+ return result;
+}
+
+
+} // namespace keymaster
diff --git a/keymaster/nist_curve_key_exchange.cpp b/keymaster/nist_curve_key_exchange.cpp
new file mode 100644
index 0000000..0dd3a54
--- /dev/null
+++ b/keymaster/nist_curve_key_exchange.cpp
@@ -0,0 +1,127 @@
+/*
+ * 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 "nist_curve_key_exchange.h"
+
+#include <openssl/ec.h>
+#include <openssl/ecdh.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+
+#include "openssl_err.h"
+
+namespace keymaster {
+
+NistCurveKeyExchange::NistCurveKeyExchange(EC_KEY* private_key, keymaster_error_t* error)
+ : private_key_(private_key) {
+ if (!private_key_.get() || !EC_KEY_check_key(private_key_.get())) {
+ *error = KM_ERROR_INVALID_ARGUMENT;
+ return;
+ }
+ *error = ExtractPublicKey();
+}
+
+/* static */
+NistCurveKeyExchange* NistCurveKeyExchange::GenerateKeyExchange(keymaster_ec_curve_t curve) {
+ int curve_name;
+ switch (curve) {
+ case KM_EC_CURVE_P_224:
+ curve_name = NID_secp224r1;
+ break;
+ case KM_EC_CURVE_P_256:
+ curve_name = NID_X9_62_prime256v1;
+ break;
+ case KM_EC_CURVE_P_384:
+ curve_name = NID_secp384r1;
+ break;
+ case KM_EC_CURVE_P_521:
+ curve_name = NID_secp521r1;
+ break;
+ default:
+ LOG_E("Not a NIST curve: %d", curve);
+ return nullptr;
+ }
+
+ UniquePtr<EC_KEY, EC_KEY_Delete> key(EC_KEY_new_by_curve_name(curve_name));
+ if (!key.get() || !EC_KEY_generate_key(key.get())) {
+ return nullptr;
+ }
+ keymaster_error_t error;
+ NistCurveKeyExchange* key_exchange = new NistCurveKeyExchange(key.release(), &error);
+ if (error != KM_ERROR_OK) {
+ return nullptr;
+ }
+ return key_exchange;
+}
+
+keymaster_error_t NistCurveKeyExchange::ExtractPublicKey() {
+ const EC_GROUP* group = EC_KEY_get0_group(private_key_.get());
+ size_t field_len_bits;
+ keymaster_error_t error = ec_get_group_size(group, &field_len_bits);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ shared_secret_len_ = (field_len_bits + 7) / 8;
+ public_key_len_ = 1 + 2 * shared_secret_len_;
+ public_key_.reset(new uint8_t[public_key_len_]);
+ if (EC_POINT_point2oct(group, EC_KEY_get0_public_key(private_key_.get()),
+ POINT_CONVERSION_UNCOMPRESSED, public_key_.get(), public_key_len_,
+ nullptr /* ctx */) != public_key_len_) {
+ return TranslateLastOpenSslError();
+ }
+ return KM_ERROR_OK;
+}
+
+bool NistCurveKeyExchange::CalculateSharedKey(const Buffer& peer_public_value,
+ Buffer* out_result) const {
+
+ return CalculateSharedKey(peer_public_value.peek_read(), peer_public_value.available_read(),
+ out_result);
+}
+
+bool NistCurveKeyExchange::CalculateSharedKey(const uint8_t* peer_public_value,
+ size_t peer_public_value_len,
+ Buffer* out_result) const {
+ const EC_GROUP* group = EC_KEY_get0_group(private_key_.get());
+ UniquePtr<EC_POINT, EC_POINT_Delete> point(EC_POINT_new(group));
+ if (!point.get() ||
+ !EC_POINT_oct2point(/* also test if point is on curve */
+ group, point.get(), peer_public_value, peer_public_value_len,
+ nullptr /* ctx */) ||
+ !EC_POINT_is_on_curve(group, point.get(), nullptr /* ctx */)) {
+ LOG_E("Can't convert peer public value to point: %d", TranslateLastOpenSslError());
+ return false;
+ }
+
+ UniquePtr<uint8_t[]> result(new uint8_t[shared_secret_len_]);
+ if (ECDH_compute_key(result.get(), shared_secret_len_, point.get(), private_key_.get(),
+ nullptr /* kdf */) != static_cast<int>(shared_secret_len_)) {
+ LOG_E("Can't compute ECDH shared key: %d", TranslateLastOpenSslError());
+ return false;
+ }
+
+ out_result->Reinitialize(result.get(), shared_secret_len_);
+ return true;
+}
+
+bool NistCurveKeyExchange::public_value(Buffer* public_value) const {
+ if (public_key_.get() != nullptr && public_key_len_ != 0) {
+ return public_value->Reinitialize(public_key_.get(), public_key_len_);
+ }
+ return false;
+}
+
+} // namespace keymaster
\ No newline at end of file
diff --git a/keymaster/nist_curve_key_exchange.h b/keymaster/nist_curve_key_exchange.h
new file mode 100644
index 0000000..0a93882
--- /dev/null
+++ b/keymaster/nist_curve_key_exchange.h
@@ -0,0 +1,72 @@
+/*
+ * 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_NIST_CURVE_KEY_EXCHANGE_H_
+#define SYSTEM_KEYMASTER_NIST_CURVE_KEY_EXCHANGE_H_
+
+#include "key_exchange.h"
+
+#include <keymaster/authorization_set.h>
+#include <hardware/keymaster_defs.h>
+
+#include <UniquePtr.h>
+
+#include "openssl_utils.h"
+
+namespace keymaster {
+
+/**
+ * NistCurveKeyExchange implements a KeyExchange using elliptic-curve
+ * Diffie-Hellman on NIST curves: P-224, P-256, P-384 and P-521.
+ */
+class NistCurveKeyExchange : public KeyExchange {
+ public:
+ ~NistCurveKeyExchange() override {}
+
+ /**
+ * NistCurveKeyExchange takes ownership of \p private_key.
+ */
+ NistCurveKeyExchange(EC_KEY* private_key, keymaster_error_t* error);
+
+ /**
+ * GenerateKeyExchange generates a new public/private key pair on a NIST curve and returns
+ * a new key exchange object.
+ */
+ static NistCurveKeyExchange* GenerateKeyExchange(keymaster_ec_curve_t curve);
+
+ /**
+ * KeyExchange interface.
+ */
+ bool CalculateSharedKey(const uint8_t* peer_public_value, size_t peer_public_value_len,
+ Buffer* shared_key) const override;
+ bool CalculateSharedKey(const Buffer& peer_public_value, Buffer* shared_key) const override;
+ bool public_value(Buffer* public_value) const override;
+
+ /* Caller takes ownership of \p private_key. */
+ EC_KEY* private_key() { return private_key_.release(); }
+
+ private:
+ keymaster_error_t ExtractPublicKey();
+
+ UniquePtr<EC_KEY, EC_KEY_Delete> private_key_;
+ UniquePtr<uint8_t[]> public_key_;
+ size_t public_key_len_;
+ size_t shared_secret_len_;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_NIST_CURVE_KEY_EXCHANGE_H_
\ No newline at end of file
diff --git a/keymaster/nist_curve_key_exchange_test.cpp b/keymaster/nist_curve_key_exchange_test.cpp
new file mode 100644
index 0000000..39ea38b
--- /dev/null
+++ b/keymaster/nist_curve_key_exchange_test.cpp
@@ -0,0 +1,219 @@
+/*
+ * 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 "nist_curve_key_exchange.h"
+
+#include <gtest/gtest.h>
+#include <openssl/evp.h>
+
+#include <hardware/keymaster_defs.h>
+#include <keymaster/android_keymaster_utils.h>
+
+#include "android_keymaster_test_utils.h"
+
+using std::string;
+
+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};
+
+/**
+ * SharedKey just tests that the basic key exchange identity holds: that both
+ * parties end up with the same key.
+ */
+TEST(NistCurveKeyExchange, SharedKey) {
+ for (auto& curve : kEcCurves) {
+ AuthorizationSet kex_description(
+ AuthorizationSetBuilder().Authorization(TAG_EC_CURVE, curve));
+ for (size_t j = 0; j < 5; j++) {
+ NistCurveKeyExchange* alice_keyex = NistCurveKeyExchange::GenerateKeyExchange(curve);
+ NistCurveKeyExchange* bob_keyex = NistCurveKeyExchange::GenerateKeyExchange(curve);
+
+ ASSERT_TRUE(alice_keyex != nullptr);
+ ASSERT_TRUE(bob_keyex != nullptr);
+
+ Buffer alice_public_value;
+ ASSERT_TRUE(alice_keyex->public_value(&alice_public_value));
+ Buffer bob_public_value;
+ ASSERT_TRUE(bob_keyex->public_value(&bob_public_value));
+
+ Buffer alice_shared, bob_shared;
+ ASSERT_TRUE(alice_keyex->CalculateSharedKey(bob_public_value, &alice_shared));
+ ASSERT_TRUE(bob_keyex->CalculateSharedKey(alice_public_value, &bob_shared));
+ EXPECT_EQ(alice_shared.available_read(), bob_shared.available_read());
+ EXPECT_EQ(0, memcmp(alice_shared.peek_read(), bob_shared.peek_read(),
+ alice_shared.available_read()));
+ }
+ }
+}
+
+/*
+ * This test tries a key agreement with a false public key (i.e. with
+ * 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"
+ "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac",
+};
+
+TEST(NistCurveKeyExchange, InvalidPublicKey) {
+ for (auto& curve : kEcCurves) {
+ AuthorizationSet kex_description(
+ AuthorizationSetBuilder().Authorization(TAG_EC_CURVE, curve));
+ KeyExchange* key_exchange = NistCurveKeyExchange::GenerateKeyExchange(curve);
+ ASSERT_TRUE(key_exchange != nullptr);
+
+ string peer_public_key = hex2str(kInvalidPublicKeys[0]);
+ Buffer computed_shared_secret;
+ ASSERT_FALSE(key_exchange->CalculateSharedKey(
+ reinterpret_cast<const uint8_t*>(peer_public_key.data()), peer_public_key.size(),
+ &computed_shared_secret));
+ }
+}
+
+/**
+ * Test that key exchange fails when peer public key is the point at infinity.
+ */
+TEST(NistCurveKeyExchange, TestInfinity) {
+ for (auto& curve : kEcCurves) {
+ /* Obtain the point at infinity */
+ EC_GROUP* group = ec_get_group(curve);
+ EC_POINT* point_at_infinity = EC_POINT_new(group);
+ EC_POINT_set_to_infinity(group, point_at_infinity);
+ EXPECT_EQ(1, EC_POINT_is_on_curve(group, point_at_infinity, nullptr));
+ size_t field_len_in_bits;
+ ec_get_group_size(group, &field_len_in_bits);
+ size_t field_len = (field_len_in_bits + 7) / 8;
+ size_t public_key_len = (field_len * 2) + 1;
+ uint8_t* public_key = new uint8_t[public_key_len];
+ public_key_len = EC_POINT_point2oct(group, point_at_infinity, POINT_CONVERSION_UNCOMPRESSED,
+ public_key, public_key_len, nullptr /* ctx */);
+
+ /* Perform the key exchange */
+ AuthorizationSet kex_description(
+ AuthorizationSetBuilder().Authorization(TAG_EC_CURVE, curve));
+ NistCurveKeyExchange* key_exchange = NistCurveKeyExchange::GenerateKeyExchange(curve);
+ ASSERT_TRUE(key_exchange != nullptr);
+ Buffer computed_shared_secret;
+ /* It should fail */
+ ASSERT_FALSE(key_exchange->CalculateSharedKey(reinterpret_cast<const uint8_t*>(public_key),
+ public_key_len, &computed_shared_secret));
+
+ /* Explicitly test that ECDH_compute_key fails when the public key is the point at infinity
+ */
+ UniquePtr<uint8_t[]> result(new uint8_t[field_len]);
+ EXPECT_EQ(-1 /* error */, ECDH_compute_key(result.get(), field_len, point_at_infinity,
+ key_exchange->private_key(), nullptr /* kdf */));
+ }
+}
+
+/* Test vectors for P-256, downloaded from NIST. */
+struct NistCurveTest {
+ const keymaster_ec_curve_t curve;
+ const char* peer_public_key;
+ const char* my_private_key;
+ const char* shared_secret;
+};
+
+static const NistCurveTest kNistCurveTests[] = {
+ {
+ KM_EC_CURVE_P_256,
+ "04" // uncompressed public key
+ "700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287"
+ "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac",
+ // https://tools.ietf.org/html/rfc5915
+ "30770201010420" // DER-encodeded EC private key header
+ "7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534" // private key
+ "a00a06082a8648ce3d030107a144034200" // DER-encoded curve OID,
+ "04"
+ "ead218590119e8876b29146ff89ca61770c4edbbf97d38ce385ed281d8a6b230"
+ "28af61281fd35e2fa7002523acc85a429cb06ee6648325389f59edfce1405141",
+ "46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b",
+ },
+ {
+ KM_EC_CURVE_P_256, "04"
+ "809f04289c64348c01515eb03d5ce7ac1a8cb9498f5caa50197e58d43a86a7ae"
+ "b29d84e811197f25eba8f5194092cb6ff440e26d4421011372461f579271cda3",
+ // https://tools.ietf.org/html/rfc5915
+ "30770201010420" // DER-encodeded EC private key header
+ "38f65d6dce47676044d58ce5139582d568f64bb16098d179dbab07741dd5caf5" // private key
+ "a00a06082a8648ce3d030107a144034200" // DER-encoded curve OID,
+ "04"
+ "119f2f047902782ab0c9e27a54aff5eb9b964829ca99c06b02ddba95b0a3f6d0"
+ "8f52b726664cac366fc98ac7a012b2682cbd962e5acb544671d41b9445704d1d",
+ "057d636096cb80b67a8c038c890e887d1adfa4195e9b3ce241c8a778c59cda67",
+ },
+ {
+ KM_EC_CURVE_P_256, "04"
+ "df3989b9fa55495719b3cf46dccd28b5153f7808191dd518eff0c3cff2b705ed"
+ "422294ff46003429d739a33206c8752552c8ba54a270defc06e221e0feaf6ac4",
+ // https://tools.ietf.org/html/rfc5915
+ "30770201010420" // DER-encodeded EC private key header
+ "207c43a79bfee03db6f4b944f53d2fb76cc49ef1c9c4d34d51b6c65c4db6932d" // private key
+ "a00a06082a8648ce3d030107a144034200" // DER-encoded curve OID,
+ "04"
+ "24277c33f450462dcb3d4801d57b9ced05188f16c28eda873258048cd1607e0d"
+ "c4789753e2b1f63b32ff014ec42cd6a69fac81dfe6d0d6fd4af372ae27c46f88",
+ "96441259534b80f6aee3d287a6bb17b5094dd4277d9e294f8fe73e48bf2a0024",
+ },
+};
+
+/**
+ * Test that key exchange works with NIST test vectors.
+ */
+TEST(NistCurveKeyExchange, NistTestVectors) {
+ for (auto& test : kNistCurveTests) {
+ string private_key = hex2str(test.my_private_key);
+ string shared_secret = hex2str(test.shared_secret);
+
+ const uint8_t* private_key_data = reinterpret_cast<const uint8_t*>(private_key.data());
+ UniquePtr<EC_KEY, EC_KEY_Delete> ec_key(
+ d2i_ECPrivateKey(nullptr, &private_key_data, private_key.size()));
+ ASSERT_TRUE(ec_key.get() && EC_KEY_check_key(ec_key.get()));
+
+ keymaster_error_t error;
+ NistCurveKeyExchange* key_exchange = new NistCurveKeyExchange(ec_key.release(), &error);
+ EXPECT_EQ(KM_ERROR_OK, error);
+ ASSERT_TRUE(key_exchange != nullptr);
+
+ Buffer computed_shared_secret;
+ string peer_public_key = hex2str(test.peer_public_key);
+ ASSERT_TRUE(key_exchange->CalculateSharedKey(
+ reinterpret_cast<const uint8_t*>(peer_public_key.data()), peer_public_key.size(),
+ &computed_shared_secret));
+ EXPECT_EQ(shared_secret.size(), computed_shared_secret.available_read());
+ EXPECT_EQ(0, memcmp(shared_secret.data(), computed_shared_secret.peek_read(),
+ shared_secret.size()));
+
+ for (size_t i = 0; i < peer_public_key.size(); i++) {
+ // randomly flip some bits in the peer public key to make it invalid
+ peer_public_key[i] ^= 0xff;
+ ASSERT_FALSE(key_exchange->CalculateSharedKey(
+ reinterpret_cast<const uint8_t*>(peer_public_key.data()), peer_public_key.size(),
+ &computed_shared_secret));
+ }
+ }
+}
+
+} // namespace test
+} // namespace keymaster
diff --git a/keymaster/ocb.c b/keymaster/ocb.c
new file mode 100644
index 0000000..461fe9d
--- /dev/null
+++ b/keymaster/ocb.c
@@ -0,0 +1,1480 @@
+/*------------------------------------------------------------------------
+/ OCB Version 3 Reference Code (Optimized C) Last modified 12-JUN-2013
+/-------------------------------------------------------------------------
+/ Copyright (c) 2013 Ted Krovetz.
+/
+/ Permission to use, copy, modify, and/or distribute this software for any
+/ purpose with or without fee is hereby granted, provided that the above
+/ copyright notice and this permission notice appear in all copies.
+/
+/ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+/ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+/ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+/ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+/ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+/ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+/ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+/
+/ Phillip Rogaway holds patents relevant to OCB. See the following for
+/ his patent grant: http://www.cs.ucdavis.edu/~rogaway/ocb/grant.htm
+/
+/ Special thanks to Keegan McAllister for suggesting several good improvements
+/
+/ Comments are welcome: Ted Krovetz <ted@krovetz.net> - Dedicated to Laurel K
+/------------------------------------------------------------------------- */
+
+/* ----------------------------------------------------------------------- */
+/* Usage notes */
+/* ----------------------------------------------------------------------- */
+
+/* - When AE_PENDING is passed as the 'final' parameter of any function,
+/ the length parameters must be a multiple of (BPI*16).
+/ - When available, SSE or AltiVec registers are used to manipulate data.
+/ So, when on machines with these facilities, all pointers passed to
+/ any function should be 16-byte aligned.
+/ - Plaintext and ciphertext pointers may be equal (ie, plaintext gets
+/ encrypted in-place), but no other pair of pointers may be equal.
+/ - This code assumes all x86 processors have SSE2 and SSSE3 instructions
+/ when compiling under MSVC. If untrue, alter the #define.
+/ - This code is tested for C99 and recent versions of GCC and MSVC. */
+
+/* ----------------------------------------------------------------------- */
+/* User configuration options */
+/* ----------------------------------------------------------------------- */
+
+/* Set the AES key length to use and length of authentication tag to produce.
+/ Setting either to 0 requires the value be set at runtime via ae_init().
+/ Some optimizations occur for each when set to a fixed value. */
+#define OCB_KEY_LEN 16 /* 0, 16, 24 or 32. 0 means set in ae_init */
+#define OCB_TAG_LEN 16 /* 0 to 16. 0 means set in ae_init */
+
+/* This implementation has built-in support for multiple AES APIs. Set any
+/ one of the following to non-zero to specify which to use. */
+#define USE_OPENSSL_AES 1 /* http://openssl.org */
+#define USE_REFERENCE_AES 0 /* Internet search: rijndael-alg-fst.c */
+#define USE_AES_NI 0 /* Uses compiler's intrinsics */
+
+/* During encryption and decryption, various "L values" are required.
+/ The L values can be precomputed during initialization (requiring extra
+/ space in ae_ctx), generated as needed (slightly slowing encryption and
+/ decryption), or some combination of the two. L_TABLE_SZ specifies how many
+/ L values to precompute. L_TABLE_SZ must be at least 3. L_TABLE_SZ*16 bytes
+/ are used for L values in ae_ctx. Plaintext and ciphertexts shorter than
+/ 2^L_TABLE_SZ blocks need no L values calculated dynamically. */
+#define L_TABLE_SZ 16
+
+/* Set L_TABLE_SZ_IS_ENOUGH non-zero iff you know that all plaintexts
+/ will be shorter than 2^(L_TABLE_SZ+4) bytes in length. This results
+/ in better performance. */
+#define L_TABLE_SZ_IS_ENOUGH 1
+
+/* ----------------------------------------------------------------------- */
+/* Includes and compiler specific definitions */
+/* ----------------------------------------------------------------------- */
+
+#include "ae.h"
+#include <stdlib.h>
+#include <string.h>
+
+/* Define standard sized integers */
+#if defined(_MSC_VER) && (_MSC_VER < 1600)
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+typedef __int64 int64_t;
+#else
+#include <stdint.h>
+#endif
+
+/* Compiler-specific intrinsics and fixes: bswap64, ntz */
+#if _MSC_VER
+#define inline __inline /* MSVC doesn't recognize "inline" in C */
+#define restrict __restrict /* MSVC doesn't recognize "restrict" in C */
+#define __SSE2__ (_M_IX86 || _M_AMD64 || _M_X64) /* Assume SSE2 */
+#define __SSSE3__ (_M_IX86 || _M_AMD64 || _M_X64) /* Assume SSSE3 */
+#include <intrin.h>
+#pragma intrinsic(_byteswap_uint64, _BitScanForward, memcpy)
+#define bswap64(x) _byteswap_uint64(x)
+static inline unsigned ntz(unsigned x) {
+ _BitScanForward(&x, x);
+ return x;
+}
+#elif __GNUC__
+#define inline __inline__ /* No "inline" in GCC ansi C mode */
+#define restrict __restrict__ /* No "restrict" in GCC ansi C mode */
+#define bswap64(x) __builtin_bswap64(x) /* Assuming GCC 4.3+ */
+#define ntz(x) __builtin_ctz((unsigned)(x)) /* Assuming GCC 3.4+ */
+#else /* Assume some C99 features: stdint.h, inline, restrict */
+#define bswap32(x) \
+ ((((x)&0xff000000u) >> 24) | (((x)&0x00ff0000u) >> 8) | (((x)&0x0000ff00u) << 8) | \
+ (((x)&0x000000ffu) << 24))
+
+static inline uint64_t bswap64(uint64_t x) {
+ union {
+ uint64_t u64;
+ uint32_t u32[2];
+ } in, out;
+ in.u64 = x;
+ out.u32[0] = bswap32(in.u32[1]);
+ out.u32[1] = bswap32(in.u32[0]);
+ return out.u64;
+}
+
+#if (L_TABLE_SZ <= 9) && (L_TABLE_SZ_IS_ENOUGH) /* < 2^13 byte texts */
+static inline unsigned ntz(unsigned x) {
+ static const unsigned char tz_table[] = {
+ 0, 2, 3, 2, 4, 2, 3, 2, 5, 2, 3, 2, 4, 2, 3, 2, 6, 2, 3, 2, 4, 2, 3, 2, 5, 2,
+ 3, 2, 4, 2, 3, 2, 7, 2, 3, 2, 4, 2, 3, 2, 5, 2, 3, 2, 4, 2, 3, 2, 6, 2, 3, 2,
+ 4, 2, 3, 2, 5, 2, 3, 2, 4, 2, 3, 2, 8, 2, 3, 2, 4, 2, 3, 2, 5, 2, 3, 2, 4, 2,
+ 3, 2, 6, 2, 3, 2, 4, 2, 3, 2, 5, 2, 3, 2, 4, 2, 3, 2, 7, 2, 3, 2, 4, 2, 3, 2,
+ 5, 2, 3, 2, 4, 2, 3, 2, 6, 2, 3, 2, 4, 2, 3, 2, 5, 2, 3, 2, 4, 2, 3, 2};
+ return tz_table[x / 4];
+}
+#else /* From http://supertech.csail.mit.edu/papers/debruijn.pdf */
+static inline unsigned ntz(unsigned x) {
+ static const unsigned char tz_table[32] = {0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20,
+ 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19,
+ 16, 7, 26, 12, 18, 6, 11, 5, 10, 9};
+ return tz_table[((uint32_t)((x & -x) * 0x077CB531u)) >> 27];
+}
+#endif
+#endif
+
+/* ----------------------------------------------------------------------- */
+/* Define blocks and operations -- Patch if incorrect on your compiler. */
+/* ----------------------------------------------------------------------- */
+
+#if __SSE2__ && !KEYMASTER_CLANG_TEST_BUILD
+#include <xmmintrin.h> /* SSE instructions and _mm_malloc */
+#include <emmintrin.h> /* SSE2 instructions */
+typedef __m128i block;
+#define xor_block(x, y) _mm_xor_si128(x, y)
+#define zero_block() _mm_setzero_si128()
+#define unequal_blocks(x, y) (_mm_movemask_epi8(_mm_cmpeq_epi8(x, y)) != 0xffff)
+#if __SSSE3__ || USE_AES_NI
+#include <tmmintrin.h> /* SSSE3 instructions */
+#define swap_if_le(b) \
+ _mm_shuffle_epi8(b, _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15))
+#else
+static inline block swap_if_le(block b) {
+ block a = _mm_shuffle_epi32(b, _MM_SHUFFLE(0, 1, 2, 3));
+ a = _mm_shufflehi_epi16(a, _MM_SHUFFLE(2, 3, 0, 1));
+ a = _mm_shufflelo_epi16(a, _MM_SHUFFLE(2, 3, 0, 1));
+ return _mm_xor_si128(_mm_srli_epi16(a, 8), _mm_slli_epi16(a, 8));
+}
+#endif
+static inline block gen_offset(uint64_t KtopStr[3], unsigned bot) {
+ block hi = _mm_load_si128((__m128i*)(KtopStr + 0)); /* hi = B A */
+ block lo = _mm_loadu_si128((__m128i*)(KtopStr + 1)); /* lo = C B */
+ __m128i lshift = _mm_cvtsi32_si128(bot);
+ __m128i rshift = _mm_cvtsi32_si128(64 - bot);
+ lo = _mm_xor_si128(_mm_sll_epi64(hi, lshift), _mm_srl_epi64(lo, rshift));
+#if __SSSE3__ || USE_AES_NI
+ return _mm_shuffle_epi8(lo, _mm_set_epi8(8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7));
+#else
+ return swap_if_le(_mm_shuffle_epi32(lo, _MM_SHUFFLE(1, 0, 3, 2)));
+#endif
+}
+static inline block double_block(block bl) {
+ const __m128i mask = _mm_set_epi32(135, 1, 1, 1);
+ __m128i tmp = _mm_srai_epi32(bl, 31);
+ tmp = _mm_and_si128(tmp, mask);
+ tmp = _mm_shuffle_epi32(tmp, _MM_SHUFFLE(2, 1, 0, 3));
+ bl = _mm_slli_epi32(bl, 1);
+ return _mm_xor_si128(bl, tmp);
+}
+#elif __ALTIVEC__
+#include <altivec.h>
+typedef vector unsigned block;
+#define xor_block(x, y) vec_xor(x, y)
+#define zero_block() vec_splat_u32(0)
+#define unequal_blocks(x, y) vec_any_ne(x, y)
+#define swap_if_le(b) (b)
+#if __PPC64__
+block gen_offset(uint64_t KtopStr[3], unsigned bot) {
+ union {
+ uint64_t u64[2];
+ block bl;
+ } rval;
+ rval.u64[0] = (KtopStr[0] << bot) | (KtopStr[1] >> (64 - bot));
+ rval.u64[1] = (KtopStr[1] << bot) | (KtopStr[2] >> (64 - bot));
+ return rval.bl;
+}
+#else
+/* Special handling: Shifts are mod 32, and no 64-bit types */
+block gen_offset(uint64_t KtopStr[3], unsigned bot) {
+ const vector unsigned k32 = {32, 32, 32, 32};
+ vector unsigned hi = *(vector unsigned*)(KtopStr + 0);
+ vector unsigned lo = *(vector unsigned*)(KtopStr + 2);
+ vector unsigned bot_vec;
+ if (bot < 32) {
+ lo = vec_sld(hi, lo, 4);
+ } else {
+ vector unsigned t = vec_sld(hi, lo, 4);
+ lo = vec_sld(hi, lo, 8);
+ hi = t;
+ bot = bot - 32;
+ }
+ if (bot == 0)
+ return hi;
+ *(unsigned*)&bot_vec = bot;
+ vector unsigned lshift = vec_splat(bot_vec, 0);
+ vector unsigned rshift = vec_sub(k32, lshift);
+ hi = vec_sl(hi, lshift);
+ lo = vec_sr(lo, rshift);
+ return vec_xor(hi, lo);
+}
+#endif
+static inline block double_block(block b) {
+ const vector unsigned char mask = {135, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
+ const vector unsigned char perm = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0};
+ const vector unsigned char shift7 = vec_splat_u8(7);
+ const vector unsigned char shift1 = vec_splat_u8(1);
+ vector unsigned char c = (vector unsigned char)b;
+ vector unsigned char t = vec_sra(c, shift7);
+ t = vec_and(t, mask);
+ t = vec_perm(t, t, perm);
+ c = vec_sl(c, shift1);
+ return (block)vec_xor(c, t);
+}
+#elif __ARM_NEON__
+#include <arm_neon.h>
+typedef int8x16_t block; /* Yay! Endian-neutral reads! */
+#define xor_block(x, y) veorq_s8(x, y)
+#define zero_block() vdupq_n_s8(0)
+static inline int unequal_blocks(block a, block b) {
+ int64x2_t t = veorq_s64((int64x2_t)a, (int64x2_t)b);
+ return (vgetq_lane_s64(t, 0) | vgetq_lane_s64(t, 1)) != 0;
+}
+#define swap_if_le(b) (b) /* Using endian-neutral int8x16_t */
+/* KtopStr is reg correct by 64 bits, return mem correct */
+block gen_offset(uint64_t KtopStr[3], unsigned bot) {
+ const union {
+ unsigned x;
+ unsigned char endian;
+ } little = {1};
+ const int64x2_t k64 = {-64, -64};
+ uint64x2_t hi = *(uint64x2_t*)(KtopStr + 0); /* hi = A B */
+ uint64x2_t lo = *(uint64x2_t*)(KtopStr + 1); /* hi = B C */
+ int64x2_t ls = vdupq_n_s64(bot);
+ int64x2_t rs = vqaddq_s64(k64, ls);
+ block rval = (block)veorq_u64(vshlq_u64(hi, ls), vshlq_u64(lo, rs));
+ if (little.endian)
+ rval = vrev64q_s8(rval);
+ return rval;
+}
+static inline block double_block(block b) {
+ const block mask = {135, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
+ block tmp = vshrq_n_s8(b, 7);
+ tmp = vandq_s8(tmp, mask);
+ tmp = vextq_s8(tmp, tmp, 1); /* Rotate high byte to end */
+ b = vshlq_n_s8(b, 1);
+ return veorq_s8(tmp, b);
+}
+#else
+typedef struct { uint64_t l, r; } block;
+static inline block xor_block(block x, block y) {
+ x.l ^= y.l;
+ x.r ^= y.r;
+ return x;
+}
+static inline block zero_block(void) {
+ const block t = {0, 0};
+ return t;
+}
+#define unequal_blocks(x, y) ((((x).l ^ (y).l) | ((x).r ^ (y).r)) != 0)
+static inline block swap_if_le(block b) {
+ const union {
+ unsigned x;
+ unsigned char endian;
+ } little = {1};
+ if (little.endian) {
+ block r;
+ r.l = bswap64(b.l);
+ r.r = bswap64(b.r);
+ return r;
+ } else
+ return b;
+}
+
+/* KtopStr is reg correct by 64 bits, return mem correct */
+block gen_offset(uint64_t KtopStr[3], unsigned bot) {
+ block rval;
+ if (bot != 0) {
+ rval.l = (KtopStr[0] << bot) | (KtopStr[1] >> (64 - bot));
+ rval.r = (KtopStr[1] << bot) | (KtopStr[2] >> (64 - bot));
+ } else {
+ rval.l = KtopStr[0];
+ rval.r = KtopStr[1];
+ }
+ return swap_if_le(rval);
+}
+
+#if __GNUC__ && __arm__
+static inline block double_block(block b) {
+ __asm__("adds %1,%1,%1\n\t"
+ "adcs %H1,%H1,%H1\n\t"
+ "adcs %0,%0,%0\n\t"
+ "adcs %H0,%H0,%H0\n\t"
+ "it cs\n\t"
+ "eorcs %1,%1,#135"
+ : "+r"(b.l), "+r"(b.r)
+ :
+ : "cc");
+ return b;
+}
+#else
+static inline block double_block(block b) {
+ uint64_t t = (uint64_t)((int64_t)b.l >> 63);
+ b.l = (b.l + b.l) ^ (b.r >> 63);
+ b.r = (b.r + b.r) ^ (t & 135);
+ return b;
+}
+#endif
+
+#endif
+
+/* ----------------------------------------------------------------------- */
+/* AES - Code uses OpenSSL API. Other implementations get mapped to it. */
+/* ----------------------------------------------------------------------- */
+
+/*---------------*/
+#if USE_OPENSSL_AES
+/*---------------*/
+
+#include <openssl/aes.h> /* http://openssl.org/ */
+
+/* How to ECB encrypt an array of blocks, in place */
+static inline void AES_ecb_encrypt_blks(block* blks, unsigned nblks, AES_KEY* key) {
+ while (nblks) {
+ --nblks;
+ AES_encrypt((unsigned char*)(blks + nblks), (unsigned char*)(blks + nblks), key);
+ }
+}
+
+static inline void AES_ecb_decrypt_blks(block* blks, unsigned nblks, AES_KEY* key) {
+ while (nblks) {
+ --nblks;
+ AES_decrypt((unsigned char*)(blks + nblks), (unsigned char*)(blks + nblks), key);
+ }
+}
+
+#define BPI 4 /* Number of blocks in buffer per ECB call */
+
+/*-------------------*/
+#elif USE_REFERENCE_AES
+/*-------------------*/
+
+#include "rijndael-alg-fst.h" /* Barreto's Public-Domain Code */
+#if (OCB_KEY_LEN == 0)
+typedef struct {
+ uint32_t rd_key[60];
+ int rounds;
+} AES_KEY;
+#define ROUNDS(ctx) ((ctx)->rounds)
+#define AES_set_encrypt_key(x, y, z) \
+ do { \
+ rijndaelKeySetupEnc((z)->rd_key, x, y); \
+ (z)->rounds = y / 32 + 6; \
+ } while (0)
+#define AES_set_decrypt_key(x, y, z) \
+ do { \
+ rijndaelKeySetupDec((z)->rd_key, x, y); \
+ (z)->rounds = y / 32 + 6; \
+ } while (0)
+#else
+typedef struct { uint32_t rd_key[OCB_KEY_LEN + 28]; } AES_KEY;
+#define ROUNDS(ctx) (6 + OCB_KEY_LEN / 4)
+#define AES_set_encrypt_key(x, y, z) rijndaelKeySetupEnc((z)->rd_key, x, y)
+#define AES_set_decrypt_key(x, y, z) rijndaelKeySetupDec((z)->rd_key, x, y)
+#endif
+#define AES_encrypt(x, y, z) rijndaelEncrypt((z)->rd_key, ROUNDS(z), x, y)
+#define AES_decrypt(x, y, z) rijndaelDecrypt((z)->rd_key, ROUNDS(z), x, y)
+
+static void AES_ecb_encrypt_blks(block* blks, unsigned nblks, AES_KEY* key) {
+ while (nblks) {
+ --nblks;
+ AES_encrypt((unsigned char*)(blks + nblks), (unsigned char*)(blks + nblks), key);
+ }
+}
+
+void AES_ecb_decrypt_blks(block* blks, unsigned nblks, AES_KEY* key) {
+ while (nblks) {
+ --nblks;
+ AES_decrypt((unsigned char*)(blks + nblks), (unsigned char*)(blks + nblks), key);
+ }
+}
+
+#define BPI 4 /* Number of blocks in buffer per ECB call */
+
+/*----------*/
+#elif USE_AES_NI
+/*----------*/
+
+#include <wmmintrin.h>
+
+#if (OCB_KEY_LEN == 0)
+typedef struct {
+ __m128i rd_key[15];
+ int rounds;
+} AES_KEY;
+#define ROUNDS(ctx) ((ctx)->rounds)
+#else
+typedef struct { __m128i rd_key[7 + OCB_KEY_LEN / 4]; } AES_KEY;
+#define ROUNDS(ctx) (6 + OCB_KEY_LEN / 4)
+#endif
+
+#define EXPAND_ASSIST(v1, v2, v3, v4, shuff_const, aes_const) \
+ v2 = _mm_aeskeygenassist_si128(v4, aes_const); \
+ v3 = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(v3), _mm_castsi128_ps(v1), 16)); \
+ v1 = _mm_xor_si128(v1, v3); \
+ v3 = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(v3), _mm_castsi128_ps(v1), 140)); \
+ v1 = _mm_xor_si128(v1, v3); \
+ v2 = _mm_shuffle_epi32(v2, shuff_const); \
+ v1 = _mm_xor_si128(v1, v2)
+
+#define EXPAND192_STEP(idx, aes_const) \
+ EXPAND_ASSIST(x0, x1, x2, x3, 85, aes_const); \
+ x3 = _mm_xor_si128(x3, _mm_slli_si128(x3, 4)); \
+ x3 = _mm_xor_si128(x3, _mm_shuffle_epi32(x0, 255)); \
+ kp[idx] = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(tmp), _mm_castsi128_ps(x0), 68)); \
+ kp[idx + 1] = \
+ _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(x0), _mm_castsi128_ps(x3), 78)); \
+ EXPAND_ASSIST(x0, x1, x2, x3, 85, (aes_const * 2)); \
+ x3 = _mm_xor_si128(x3, _mm_slli_si128(x3, 4)); \
+ x3 = _mm_xor_si128(x3, _mm_shuffle_epi32(x0, 255)); \
+ kp[idx + 2] = x0; \
+ tmp = x3
+
+static void AES_128_Key_Expansion(const unsigned char* userkey, void* key) {
+ __m128i x0, x1, x2;
+ __m128i* kp = (__m128i*)key;
+ kp[0] = x0 = _mm_loadu_si128((__m128i*)userkey);
+ x2 = _mm_setzero_si128();
+ EXPAND_ASSIST(x0, x1, x2, x0, 255, 1);
+ kp[1] = x0;
+ EXPAND_ASSIST(x0, x1, x2, x0, 255, 2);
+ kp[2] = x0;
+ EXPAND_ASSIST(x0, x1, x2, x0, 255, 4);
+ kp[3] = x0;
+ EXPAND_ASSIST(x0, x1, x2, x0, 255, 8);
+ kp[4] = x0;
+ EXPAND_ASSIST(x0, x1, x2, x0, 255, 16);
+ kp[5] = x0;
+ EXPAND_ASSIST(x0, x1, x2, x0, 255, 32);
+ kp[6] = x0;
+ EXPAND_ASSIST(x0, x1, x2, x0, 255, 64);
+ kp[7] = x0;
+ EXPAND_ASSIST(x0, x1, x2, x0, 255, 128);
+ kp[8] = x0;
+ EXPAND_ASSIST(x0, x1, x2, x0, 255, 27);
+ kp[9] = x0;
+ EXPAND_ASSIST(x0, x1, x2, x0, 255, 54);
+ kp[10] = x0;
+}
+
+static void AES_192_Key_Expansion(const unsigned char* userkey, void* key) {
+ __m128i x0, x1, x2, x3, tmp, *kp = (__m128i*)key;
+ kp[0] = x0 = _mm_loadu_si128((__m128i*)userkey);
+ tmp = x3 = _mm_loadu_si128((__m128i*)(userkey + 16));
+ x2 = _mm_setzero_si128();
+ EXPAND192_STEP(1, 1);
+ EXPAND192_STEP(4, 4);
+ EXPAND192_STEP(7, 16);
+ EXPAND192_STEP(10, 64);
+}
+
+static void AES_256_Key_Expansion(const unsigned char* userkey, void* key) {
+ __m128i x0, x1, x2, x3, *kp = (__m128i*)key;
+ kp[0] = x0 = _mm_loadu_si128((__m128i*)userkey);
+ kp[1] = x3 = _mm_loadu_si128((__m128i*)(userkey + 16));
+ x2 = _mm_setzero_si128();
+ EXPAND_ASSIST(x0, x1, x2, x3, 255, 1);
+ kp[2] = x0;
+ EXPAND_ASSIST(x3, x1, x2, x0, 170, 1);
+ kp[3] = x3;
+ EXPAND_ASSIST(x0, x1, x2, x3, 255, 2);
+ kp[4] = x0;
+ EXPAND_ASSIST(x3, x1, x2, x0, 170, 2);
+ kp[5] = x3;
+ EXPAND_ASSIST(x0, x1, x2, x3, 255, 4);
+ kp[6] = x0;
+ EXPAND_ASSIST(x3, x1, x2, x0, 170, 4);
+ kp[7] = x3;
+ EXPAND_ASSIST(x0, x1, x2, x3, 255, 8);
+ kp[8] = x0;
+ EXPAND_ASSIST(x3, x1, x2, x0, 170, 8);
+ kp[9] = x3;
+ EXPAND_ASSIST(x0, x1, x2, x3, 255, 16);
+ kp[10] = x0;
+ EXPAND_ASSIST(x3, x1, x2, x0, 170, 16);
+ kp[11] = x3;
+ EXPAND_ASSIST(x0, x1, x2, x3, 255, 32);
+ kp[12] = x0;
+ EXPAND_ASSIST(x3, x1, x2, x0, 170, 32);
+ kp[13] = x3;
+ EXPAND_ASSIST(x0, x1, x2, x3, 255, 64);
+ kp[14] = x0;
+}
+
+static int AES_set_encrypt_key(const unsigned char* userKey, const int bits, AES_KEY* key) {
+ if (bits == 128) {
+ AES_128_Key_Expansion(userKey, key);
+ } else if (bits == 192) {
+ AES_192_Key_Expansion(userKey, key);
+ } else if (bits == 256) {
+ AES_256_Key_Expansion(userKey, key);
+ }
+#if (OCB_KEY_LEN == 0)
+ key->rounds = 6 + bits / 32;
+#endif
+ return 0;
+}
+
+static void AES_set_decrypt_key_fast(AES_KEY* dkey, const AES_KEY* ekey) {
+ int j = 0;
+ int i = ROUNDS(ekey);
+#if (OCB_KEY_LEN == 0)
+ dkey->rounds = i;
+#endif
+ dkey->rd_key[i--] = ekey->rd_key[j++];
+ while (i)
+ dkey->rd_key[i--] = _mm_aesimc_si128(ekey->rd_key[j++]);
+ dkey->rd_key[i] = ekey->rd_key[j];
+}
+
+static int AES_set_decrypt_key(const unsigned char* userKey, const int bits, AES_KEY* key) {
+ AES_KEY temp_key;
+ AES_set_encrypt_key(userKey, bits, &temp_key);
+ AES_set_decrypt_key_fast(key, &temp_key);
+ return 0;
+}
+
+static inline void AES_encrypt(const unsigned char* in, unsigned char* out, const AES_KEY* key) {
+ int j, rnds = ROUNDS(key);
+ const __m128i* sched = ((__m128i*)(key->rd_key));
+ __m128i tmp = _mm_load_si128((__m128i*)in);
+ tmp = _mm_xor_si128(tmp, sched[0]);
+ for (j = 1; j < rnds; j++)
+ tmp = _mm_aesenc_si128(tmp, sched[j]);
+ tmp = _mm_aesenclast_si128(tmp, sched[j]);
+ _mm_store_si128((__m128i*)out, tmp);
+}
+
+static inline void AES_decrypt(const unsigned char* in, unsigned char* out, const AES_KEY* key) {
+ int j, rnds = ROUNDS(key);
+ const __m128i* sched = ((__m128i*)(key->rd_key));
+ __m128i tmp = _mm_load_si128((__m128i*)in);
+ tmp = _mm_xor_si128(tmp, sched[0]);
+ for (j = 1; j < rnds; j++)
+ tmp = _mm_aesdec_si128(tmp, sched[j]);
+ tmp = _mm_aesdeclast_si128(tmp, sched[j]);
+ _mm_store_si128((__m128i*)out, tmp);
+}
+
+static inline void AES_ecb_encrypt_blks(block* blks, unsigned nblks, AES_KEY* key) {
+ unsigned i, j, rnds = ROUNDS(key);
+ const __m128i* sched = ((__m128i*)(key->rd_key));
+ for (i = 0; i < nblks; ++i)
+ blks[i] = _mm_xor_si128(blks[i], sched[0]);
+ for (j = 1; j < rnds; ++j)
+ for (i = 0; i < nblks; ++i)
+ blks[i] = _mm_aesenc_si128(blks[i], sched[j]);
+ for (i = 0; i < nblks; ++i)
+ blks[i] = _mm_aesenclast_si128(blks[i], sched[j]);
+}
+
+static inline void AES_ecb_decrypt_blks(block* blks, unsigned nblks, AES_KEY* key) {
+ unsigned i, j, rnds = ROUNDS(key);
+ const __m128i* sched = ((__m128i*)(key->rd_key));
+ for (i = 0; i < nblks; ++i)
+ blks[i] = _mm_xor_si128(blks[i], sched[0]);
+ for (j = 1; j < rnds; ++j)
+ for (i = 0; i < nblks; ++i)
+ blks[i] = _mm_aesdec_si128(blks[i], sched[j]);
+ for (i = 0; i < nblks; ++i)
+ blks[i] = _mm_aesdeclast_si128(blks[i], sched[j]);
+}
+
+#define BPI 8 /* Number of blocks in buffer per ECB call */
+/* Set to 4 for Westmere, 8 for Sandy Bridge */
+
+#endif
+
+/* ----------------------------------------------------------------------- */
+/* Define OCB context structure. */
+/* ----------------------------------------------------------------------- */
+
+/*------------------------------------------------------------------------
+/ Each item in the OCB context is stored either "memory correct" or
+/ "register correct". On big-endian machines, this is identical. On
+/ little-endian machines, one must choose whether the byte-string
+/ is in the correct order when it resides in memory or in registers.
+/ It must be register correct whenever it is to be manipulated
+/ arithmetically, but must be memory correct whenever it interacts
+/ with the plaintext or ciphertext.
+/------------------------------------------------------------------------- */
+
+struct _ae_ctx {
+ block offset; /* Memory correct */
+ block checksum; /* Memory correct */
+ block Lstar; /* Memory correct */
+ block Ldollar; /* Memory correct */
+ block L[L_TABLE_SZ]; /* Memory correct */
+ block ad_checksum; /* Memory correct */
+ block ad_offset; /* Memory correct */
+ block cached_Top; /* Memory correct */
+ uint64_t KtopStr[3]; /* Register correct, each item */
+ uint32_t ad_blocks_processed;
+ uint32_t blocks_processed;
+ AES_KEY decrypt_key;
+ AES_KEY encrypt_key;
+#if (OCB_TAG_LEN == 0)
+ unsigned tag_len;
+#endif
+};
+
+/* ----------------------------------------------------------------------- */
+/* L table lookup (or on-the-fly generation) */
+/* ----------------------------------------------------------------------- */
+
+#if L_TABLE_SZ_IS_ENOUGH
+#define getL(_ctx, _tz) ((_ctx)->L[_tz])
+#else
+static block getL(const ae_ctx* ctx, unsigned tz) {
+ if (tz < L_TABLE_SZ)
+ return ctx->L[tz];
+ else {
+ unsigned i;
+ /* Bring L[MAX] into registers, make it register correct */
+ block rval = swap_if_le(ctx->L[L_TABLE_SZ - 1]);
+ rval = double_block(rval);
+ for (i = L_TABLE_SZ; i < tz; i++)
+ rval = double_block(rval);
+ return swap_if_le(rval); /* To memory correct */
+ }
+}
+#endif
+
+/* ----------------------------------------------------------------------- */
+/* Public functions */
+/* ----------------------------------------------------------------------- */
+
+/* 32-bit SSE2 and Altivec systems need to be forced to allocate memory
+ on 16-byte alignments. (I believe all major 64-bit systems do already.) */
+
+ae_ctx* ae_allocate(void* misc) {
+ void* p;
+ (void)misc; /* misc unused in this implementation */
+#if (__SSE2__ && !_M_X64 && !_M_AMD64 && !__amd64__)
+ p = _mm_malloc(sizeof(ae_ctx), 16);
+#elif(__ALTIVEC__ && !__PPC64__)
+ if (posix_memalign(&p, 16, sizeof(ae_ctx)) != 0)
+ p = NULL;
+#else
+ p = malloc(sizeof(ae_ctx));
+#endif
+ return (ae_ctx*)p;
+}
+
+void ae_free(ae_ctx* ctx) {
+#if (__SSE2__ && !_M_X64 && !_M_AMD64 && !__amd64__)
+ _mm_free(ctx);
+#else
+ free(ctx);
+#endif
+}
+
+/* ----------------------------------------------------------------------- */
+
+int ae_clear(ae_ctx* ctx) /* Zero ae_ctx and undo initialization */
+{
+ memset(ctx, 0, sizeof(ae_ctx));
+ return AE_SUCCESS;
+}
+
+int ae_ctx_sizeof(void) {
+ return (int)sizeof(ae_ctx);
+}
+
+/* ----------------------------------------------------------------------- */
+
+int ae_init(ae_ctx* ctx, const void* key, int key_len, int nonce_len, int tag_len) {
+ unsigned i;
+ block tmp_blk;
+
+ if (nonce_len != 12)
+ return AE_NOT_SUPPORTED;
+
+/* Initialize encryption & decryption keys */
+#if (OCB_KEY_LEN > 0)
+ key_len = OCB_KEY_LEN;
+#endif
+ AES_set_encrypt_key((unsigned char*)key, key_len * 8, &ctx->encrypt_key);
+#if USE_AES_NI
+ AES_set_decrypt_key_fast(&ctx->decrypt_key, &ctx->encrypt_key);
+#else
+ AES_set_decrypt_key((unsigned char*)key, (int)(key_len * 8), &ctx->decrypt_key);
+#endif
+
+ /* Zero things that need zeroing */
+ ctx->cached_Top = ctx->ad_checksum = zero_block();
+ ctx->ad_blocks_processed = 0;
+
+ /* Compute key-dependent values */
+ AES_encrypt((unsigned char*)&ctx->cached_Top, (unsigned char*)&ctx->Lstar, &ctx->encrypt_key);
+ tmp_blk = swap_if_le(ctx->Lstar);
+ tmp_blk = double_block(tmp_blk);
+ ctx->Ldollar = swap_if_le(tmp_blk);
+ tmp_blk = double_block(tmp_blk);
+ ctx->L[0] = swap_if_le(tmp_blk);
+ for (i = 1; i < L_TABLE_SZ; i++) {
+ tmp_blk = double_block(tmp_blk);
+ ctx->L[i] = swap_if_le(tmp_blk);
+ }
+
+#if (OCB_TAG_LEN == 0)
+ ctx->tag_len = tag_len;
+#else
+ (void)tag_len; /* Suppress var not used error */
+#endif
+
+ return AE_SUCCESS;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static block gen_offset_from_nonce(ae_ctx* ctx, const void* nonce) {
+ const union {
+ unsigned x;
+ unsigned char endian;
+ } little = {1};
+ union {
+ uint32_t u32[4];
+ uint8_t u8[16];
+ block bl;
+ } tmp;
+ unsigned idx;
+
+/* Replace cached nonce Top if needed */
+#if (OCB_TAG_LEN > 0)
+ if (little.endian)
+ tmp.u32[0] = 0x01000000 + ((OCB_TAG_LEN * 8 % 128) << 1);
+ else
+ tmp.u32[0] = 0x00000001 + ((OCB_TAG_LEN * 8 % 128) << 25);
+#else
+ if (little.endian)
+ tmp.u32[0] = 0x01000000 + ((ctx->tag_len * 8 % 128) << 1);
+ else
+ tmp.u32[0] = 0x00000001 + ((ctx->tag_len * 8 % 128) << 25);
+#endif
+ tmp.u32[1] = ((uint32_t*)nonce)[0];
+ tmp.u32[2] = ((uint32_t*)nonce)[1];
+ tmp.u32[3] = ((uint32_t*)nonce)[2];
+ idx = (unsigned)(tmp.u8[15] & 0x3f); /* Get low 6 bits of nonce */
+ tmp.u8[15] = tmp.u8[15] & 0xc0; /* Zero low 6 bits of nonce */
+ if (unequal_blocks(tmp.bl, ctx->cached_Top)) { /* Cached? */
+ ctx->cached_Top = tmp.bl; /* Update cache, KtopStr */
+ AES_encrypt(tmp.u8, (unsigned char*)&ctx->KtopStr, &ctx->encrypt_key);
+ if (little.endian) { /* Make Register Correct */
+ ctx->KtopStr[0] = bswap64(ctx->KtopStr[0]);
+ ctx->KtopStr[1] = bswap64(ctx->KtopStr[1]);
+ }
+ ctx->KtopStr[2] = ctx->KtopStr[0] ^ (ctx->KtopStr[0] << 8) ^ (ctx->KtopStr[1] >> 56);
+ }
+ return gen_offset(ctx->KtopStr, idx);
+}
+
+static void process_ad(ae_ctx* ctx, const void* ad, int ad_len, int final) {
+ union {
+ uint32_t u32[4];
+ uint8_t u8[16];
+ block bl;
+ } tmp;
+ block ad_offset, ad_checksum;
+ const block* adp = (block*)ad;
+ unsigned i, k, tz, remaining;
+
+ ad_offset = ctx->ad_offset;
+ ad_checksum = ctx->ad_checksum;
+ i = ad_len / (BPI * 16);
+ if (i) {
+ unsigned ad_block_num = ctx->ad_blocks_processed;
+ do {
+ block ta[BPI], oa[BPI];
+ ad_block_num += BPI;
+ tz = ntz(ad_block_num);
+ oa[0] = xor_block(ad_offset, ctx->L[0]);
+ ta[0] = xor_block(oa[0], adp[0]);
+ oa[1] = xor_block(oa[0], ctx->L[1]);
+ ta[1] = xor_block(oa[1], adp[1]);
+ oa[2] = xor_block(ad_offset, ctx->L[1]);
+ ta[2] = xor_block(oa[2], adp[2]);
+#if BPI == 4
+ ad_offset = xor_block(oa[2], getL(ctx, tz));
+ ta[3] = xor_block(ad_offset, adp[3]);
+#elif BPI == 8
+ oa[3] = xor_block(oa[2], ctx->L[2]);
+ ta[3] = xor_block(oa[3], adp[3]);
+ oa[4] = xor_block(oa[1], ctx->L[2]);
+ ta[4] = xor_block(oa[4], adp[4]);
+ oa[5] = xor_block(oa[0], ctx->L[2]);
+ ta[5] = xor_block(oa[5], adp[5]);
+ oa[6] = xor_block(ad_offset, ctx->L[2]);
+ ta[6] = xor_block(oa[6], adp[6]);
+ ad_offset = xor_block(oa[6], getL(ctx, tz));
+ ta[7] = xor_block(ad_offset, adp[7]);
+#endif
+ AES_ecb_encrypt_blks(ta, BPI, &ctx->encrypt_key);
+ ad_checksum = xor_block(ad_checksum, ta[0]);
+ ad_checksum = xor_block(ad_checksum, ta[1]);
+ ad_checksum = xor_block(ad_checksum, ta[2]);
+ ad_checksum = xor_block(ad_checksum, ta[3]);
+#if (BPI == 8)
+ ad_checksum = xor_block(ad_checksum, ta[4]);
+ ad_checksum = xor_block(ad_checksum, ta[5]);
+ ad_checksum = xor_block(ad_checksum, ta[6]);
+ ad_checksum = xor_block(ad_checksum, ta[7]);
+#endif
+ adp += BPI;
+ } while (--i);
+ ctx->ad_blocks_processed = ad_block_num;
+ ctx->ad_offset = ad_offset;
+ ctx->ad_checksum = ad_checksum;
+ }
+
+ if (final) {
+ block ta[BPI];
+
+ /* Process remaining associated data, compute its tag contribution */
+ remaining = ((unsigned)ad_len) % (BPI * 16);
+ if (remaining) {
+ k = 0;
+#if (BPI == 8)
+ if (remaining >= 64) {
+ tmp.bl = xor_block(ad_offset, ctx->L[0]);
+ ta[0] = xor_block(tmp.bl, adp[0]);
+ tmp.bl = xor_block(tmp.bl, ctx->L[1]);
+ ta[1] = xor_block(tmp.bl, adp[1]);
+ ad_offset = xor_block(ad_offset, ctx->L[1]);
+ ta[2] = xor_block(ad_offset, adp[2]);
+ ad_offset = xor_block(ad_offset, ctx->L[2]);
+ ta[3] = xor_block(ad_offset, adp[3]);
+ remaining -= 64;
+ k = 4;
+ }
+#endif
+ if (remaining >= 32) {
+ ad_offset = xor_block(ad_offset, ctx->L[0]);
+ ta[k] = xor_block(ad_offset, adp[k]);
+ ad_offset = xor_block(ad_offset, getL(ctx, ntz(k + 2)));
+ ta[k + 1] = xor_block(ad_offset, adp[k + 1]);
+ remaining -= 32;
+ k += 2;
+ }
+ if (remaining >= 16) {
+ ad_offset = xor_block(ad_offset, ctx->L[0]);
+ ta[k] = xor_block(ad_offset, adp[k]);
+ remaining = remaining - 16;
+ ++k;
+ }
+ if (remaining) {
+ ad_offset = xor_block(ad_offset, ctx->Lstar);
+ tmp.bl = zero_block();
+ memcpy(tmp.u8, adp + k, remaining);
+ tmp.u8[remaining] = (unsigned char)0x80u;
+ ta[k] = xor_block(ad_offset, tmp.bl);
+ ++k;
+ }
+ AES_ecb_encrypt_blks(ta, k, &ctx->encrypt_key);
+ switch (k) {
+#if (BPI == 8)
+ case 8:
+ ad_checksum = xor_block(ad_checksum, ta[7]);
+ case 7:
+ ad_checksum = xor_block(ad_checksum, ta[6]);
+ case 6:
+ ad_checksum = xor_block(ad_checksum, ta[5]);
+ case 5:
+ ad_checksum = xor_block(ad_checksum, ta[4]);
+#endif
+ case 4:
+ ad_checksum = xor_block(ad_checksum, ta[3]);
+ case 3:
+ ad_checksum = xor_block(ad_checksum, ta[2]);
+ case 2:
+ ad_checksum = xor_block(ad_checksum, ta[1]);
+ case 1:
+ ad_checksum = xor_block(ad_checksum, ta[0]);
+ }
+ ctx->ad_checksum = ad_checksum;
+ }
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+
+int ae_encrypt(ae_ctx* ctx, const void* nonce, const void* pt, int pt_len, const void* ad,
+ int ad_len, void* ct, void* tag, int final) {
+ union {
+ uint32_t u32[4];
+ uint8_t u8[16];
+ block bl;
+ } tmp;
+ block offset, checksum;
+ unsigned i, k;
+ block* ctp = (block*)ct;
+ const block* ptp = (block*)pt;
+
+ /* Non-null nonce means start of new message, init per-message values */
+ if (nonce) {
+ ctx->offset = gen_offset_from_nonce(ctx, nonce);
+ ctx->ad_offset = ctx->checksum = zero_block();
+ ctx->ad_blocks_processed = ctx->blocks_processed = 0;
+ if (ad_len >= 0)
+ ctx->ad_checksum = zero_block();
+ }
+
+ /* Process associated data */
+ if (ad_len > 0)
+ process_ad(ctx, ad, ad_len, final);
+
+ /* Encrypt plaintext data BPI blocks at a time */
+ offset = ctx->offset;
+ checksum = ctx->checksum;
+ i = pt_len / (BPI * 16);
+ if (i) {
+ block oa[BPI];
+ unsigned block_num = ctx->blocks_processed;
+ oa[BPI - 1] = offset;
+ do {
+ block ta[BPI];
+ block_num += BPI;
+ oa[0] = xor_block(oa[BPI - 1], ctx->L[0]);
+ ta[0] = xor_block(oa[0], ptp[0]);
+ checksum = xor_block(checksum, ptp[0]);
+ oa[1] = xor_block(oa[0], ctx->L[1]);
+ ta[1] = xor_block(oa[1], ptp[1]);
+ checksum = xor_block(checksum, ptp[1]);
+ oa[2] = xor_block(oa[1], ctx->L[0]);
+ ta[2] = xor_block(oa[2], ptp[2]);
+ checksum = xor_block(checksum, ptp[2]);
+#if BPI == 4
+ oa[3] = xor_block(oa[2], getL(ctx, ntz(block_num)));
+ ta[3] = xor_block(oa[3], ptp[3]);
+ checksum = xor_block(checksum, ptp[3]);
+#elif BPI == 8
+ oa[3] = xor_block(oa[2], ctx->L[2]);
+ ta[3] = xor_block(oa[3], ptp[3]);
+ checksum = xor_block(checksum, ptp[3]);
+ oa[4] = xor_block(oa[1], ctx->L[2]);
+ ta[4] = xor_block(oa[4], ptp[4]);
+ checksum = xor_block(checksum, ptp[4]);
+ oa[5] = xor_block(oa[0], ctx->L[2]);
+ ta[5] = xor_block(oa[5], ptp[5]);
+ checksum = xor_block(checksum, ptp[5]);
+ oa[6] = xor_block(oa[7], ctx->L[2]);
+ ta[6] = xor_block(oa[6], ptp[6]);
+ checksum = xor_block(checksum, ptp[6]);
+ oa[7] = xor_block(oa[6], getL(ctx, ntz(block_num)));
+ ta[7] = xor_block(oa[7], ptp[7]);
+ checksum = xor_block(checksum, ptp[7]);
+#endif
+ AES_ecb_encrypt_blks(ta, BPI, &ctx->encrypt_key);
+ ctp[0] = xor_block(ta[0], oa[0]);
+ ctp[1] = xor_block(ta[1], oa[1]);
+ ctp[2] = xor_block(ta[2], oa[2]);
+ ctp[3] = xor_block(ta[3], oa[3]);
+#if (BPI == 8)
+ ctp[4] = xor_block(ta[4], oa[4]);
+ ctp[5] = xor_block(ta[5], oa[5]);
+ ctp[6] = xor_block(ta[6], oa[6]);
+ ctp[7] = xor_block(ta[7], oa[7]);
+#endif
+ ptp += BPI;
+ ctp += BPI;
+ } while (--i);
+ ctx->offset = offset = oa[BPI - 1];
+ ctx->blocks_processed = block_num;
+ ctx->checksum = checksum;
+ }
+
+ if (final) {
+ block ta[BPI + 1], oa[BPI];
+
+ /* Process remaining plaintext and compute its tag contribution */
+ unsigned remaining = ((unsigned)pt_len) % (BPI * 16);
+ k = 0; /* How many blocks in ta[] need ECBing */
+ if (remaining) {
+#if (BPI == 8)
+ if (remaining >= 64) {
+ oa[0] = xor_block(offset, ctx->L[0]);
+ ta[0] = xor_block(oa[0], ptp[0]);
+ checksum = xor_block(checksum, ptp[0]);
+ oa[1] = xor_block(oa[0], ctx->L[1]);
+ ta[1] = xor_block(oa[1], ptp[1]);
+ checksum = xor_block(checksum, ptp[1]);
+ oa[2] = xor_block(oa[1], ctx->L[0]);
+ ta[2] = xor_block(oa[2], ptp[2]);
+ checksum = xor_block(checksum, ptp[2]);
+ offset = oa[3] = xor_block(oa[2], ctx->L[2]);
+ ta[3] = xor_block(offset, ptp[3]);
+ checksum = xor_block(checksum, ptp[3]);
+ remaining -= 64;
+ k = 4;
+ }
+#endif
+ if (remaining >= 32) {
+ oa[k] = xor_block(offset, ctx->L[0]);
+ ta[k] = xor_block(oa[k], ptp[k]);
+ checksum = xor_block(checksum, ptp[k]);
+ offset = oa[k + 1] = xor_block(oa[k], ctx->L[1]);
+ ta[k + 1] = xor_block(offset, ptp[k + 1]);
+ checksum = xor_block(checksum, ptp[k + 1]);
+ remaining -= 32;
+ k += 2;
+ }
+ if (remaining >= 16) {
+ offset = oa[k] = xor_block(offset, ctx->L[0]);
+ ta[k] = xor_block(offset, ptp[k]);
+ checksum = xor_block(checksum, ptp[k]);
+ remaining -= 16;
+ ++k;
+ }
+ if (remaining) {
+ tmp.bl = zero_block();
+ memcpy(tmp.u8, ptp + k, remaining);
+ tmp.u8[remaining] = (unsigned char)0x80u;
+ checksum = xor_block(checksum, tmp.bl);
+ ta[k] = offset = xor_block(offset, ctx->Lstar);
+ ++k;
+ }
+ }
+ offset = xor_block(offset, ctx->Ldollar); /* Part of tag gen */
+ ta[k] = xor_block(offset, checksum); /* Part of tag gen */
+ AES_ecb_encrypt_blks(ta, k + 1, &ctx->encrypt_key);
+ offset = xor_block(ta[k], ctx->ad_checksum); /* Part of tag gen */
+ if (remaining) {
+ --k;
+ tmp.bl = xor_block(tmp.bl, ta[k]);
+ memcpy(ctp + k, tmp.u8, remaining);
+ }
+ switch (k) {
+#if (BPI == 8)
+ case 7:
+ ctp[6] = xor_block(ta[6], oa[6]);
+ case 6:
+ ctp[5] = xor_block(ta[5], oa[5]);
+ case 5:
+ ctp[4] = xor_block(ta[4], oa[4]);
+ case 4:
+ ctp[3] = xor_block(ta[3], oa[3]);
+#endif
+ case 3:
+ ctp[2] = xor_block(ta[2], oa[2]);
+ case 2:
+ ctp[1] = xor_block(ta[1], oa[1]);
+ case 1:
+ ctp[0] = xor_block(ta[0], oa[0]);
+ }
+
+ /* Tag is placed at the correct location
+ */
+ if (tag) {
+#if (OCB_TAG_LEN == 16)
+ *(block*)tag = offset;
+#elif(OCB_TAG_LEN > 0)
+ memcpy((char*)tag, &offset, OCB_TAG_LEN);
+#else
+ memcpy((char*)tag, &offset, ctx->tag_len);
+#endif
+ } else {
+#if (OCB_TAG_LEN > 0)
+ memcpy((char*)ct + pt_len, &offset, OCB_TAG_LEN);
+ pt_len += OCB_TAG_LEN;
+#else
+ memcpy((char*)ct + pt_len, &offset, ctx->tag_len);
+ pt_len += ctx->tag_len;
+#endif
+ }
+ }
+ return (int)pt_len;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* Compare two regions of memory, taking a constant amount of time for a
+ given buffer size -- under certain assumptions about the compiler
+ and machine, of course.
+
+ Use this to avoid timing side-channel attacks.
+
+ Returns 0 for memory regions with equal contents; non-zero otherwise. */
+static int constant_time_memcmp(const void* av, const void* bv, size_t n) {
+ const uint8_t* a = (const uint8_t*)av;
+ const uint8_t* b = (const uint8_t*)bv;
+ uint8_t result = 0;
+ size_t i;
+
+ for (i = 0; i < n; i++) {
+ result |= *a ^ *b;
+ a++;
+ b++;
+ }
+
+ return (int)result;
+}
+
+int ae_decrypt(ae_ctx* ctx, const void* nonce, const void* ct, int ct_len, const void* ad,
+ int ad_len, void* pt, const void* tag, int final) {
+ union {
+ uint32_t u32[4];
+ uint8_t u8[16];
+ block bl;
+ } tmp;
+ block offset, checksum;
+ unsigned i, k;
+ block* ctp = (block*)ct;
+ block* ptp = (block*)pt;
+
+ /* Reduce ct_len tag bundled in ct */
+ if ((final) && (!tag))
+#if (OCB_TAG_LEN > 0)
+ ct_len -= OCB_TAG_LEN;
+#else
+ ct_len -= ctx->tag_len;
+#endif
+
+ /* Non-null nonce means start of new message, init per-message values */
+ if (nonce) {
+ ctx->offset = gen_offset_from_nonce(ctx, nonce);
+ ctx->ad_offset = ctx->checksum = zero_block();
+ ctx->ad_blocks_processed = ctx->blocks_processed = 0;
+ if (ad_len >= 0)
+ ctx->ad_checksum = zero_block();
+ }
+
+ /* Process associated data */
+ if (ad_len > 0)
+ process_ad(ctx, ad, ad_len, final);
+
+ /* Encrypt plaintext data BPI blocks at a time */
+ offset = ctx->offset;
+ checksum = ctx->checksum;
+ i = ct_len / (BPI * 16);
+ if (i) {
+ block oa[BPI];
+ unsigned block_num = ctx->blocks_processed;
+ oa[BPI - 1] = offset;
+ do {
+ block ta[BPI];
+ block_num += BPI;
+ oa[0] = xor_block(oa[BPI - 1], ctx->L[0]);
+ ta[0] = xor_block(oa[0], ctp[0]);
+ oa[1] = xor_block(oa[0], ctx->L[1]);
+ ta[1] = xor_block(oa[1], ctp[1]);
+ oa[2] = xor_block(oa[1], ctx->L[0]);
+ ta[2] = xor_block(oa[2], ctp[2]);
+#if BPI == 4
+ oa[3] = xor_block(oa[2], getL(ctx, ntz(block_num)));
+ ta[3] = xor_block(oa[3], ctp[3]);
+#elif BPI == 8
+ oa[3] = xor_block(oa[2], ctx->L[2]);
+ ta[3] = xor_block(oa[3], ctp[3]);
+ oa[4] = xor_block(oa[1], ctx->L[2]);
+ ta[4] = xor_block(oa[4], ctp[4]);
+ oa[5] = xor_block(oa[0], ctx->L[2]);
+ ta[5] = xor_block(oa[5], ctp[5]);
+ oa[6] = xor_block(oa[7], ctx->L[2]);
+ ta[6] = xor_block(oa[6], ctp[6]);
+ oa[7] = xor_block(oa[6], getL(ctx, ntz(block_num)));
+ ta[7] = xor_block(oa[7], ctp[7]);
+#endif
+ AES_ecb_decrypt_blks(ta, BPI, &ctx->decrypt_key);
+ ptp[0] = xor_block(ta[0], oa[0]);
+ checksum = xor_block(checksum, ptp[0]);
+ ptp[1] = xor_block(ta[1], oa[1]);
+ checksum = xor_block(checksum, ptp[1]);
+ ptp[2] = xor_block(ta[2], oa[2]);
+ checksum = xor_block(checksum, ptp[2]);
+ ptp[3] = xor_block(ta[3], oa[3]);
+ checksum = xor_block(checksum, ptp[3]);
+#if (BPI == 8)
+ ptp[4] = xor_block(ta[4], oa[4]);
+ checksum = xor_block(checksum, ptp[4]);
+ ptp[5] = xor_block(ta[5], oa[5]);
+ checksum = xor_block(checksum, ptp[5]);
+ ptp[6] = xor_block(ta[6], oa[6]);
+ checksum = xor_block(checksum, ptp[6]);
+ ptp[7] = xor_block(ta[7], oa[7]);
+ checksum = xor_block(checksum, ptp[7]);
+#endif
+ ptp += BPI;
+ ctp += BPI;
+ } while (--i);
+ ctx->offset = offset = oa[BPI - 1];
+ ctx->blocks_processed = block_num;
+ ctx->checksum = checksum;
+ }
+
+ if (final) {
+ block ta[BPI + 1], oa[BPI];
+
+ /* Process remaining plaintext and compute its tag contribution */
+ unsigned remaining = ((unsigned)ct_len) % (BPI * 16);
+ k = 0; /* How many blocks in ta[] need ECBing */
+ if (remaining) {
+#if (BPI == 8)
+ if (remaining >= 64) {
+ oa[0] = xor_block(offset, ctx->L[0]);
+ ta[0] = xor_block(oa[0], ctp[0]);
+ oa[1] = xor_block(oa[0], ctx->L[1]);
+ ta[1] = xor_block(oa[1], ctp[1]);
+ oa[2] = xor_block(oa[1], ctx->L[0]);
+ ta[2] = xor_block(oa[2], ctp[2]);
+ offset = oa[3] = xor_block(oa[2], ctx->L[2]);
+ ta[3] = xor_block(offset, ctp[3]);
+ remaining -= 64;
+ k = 4;
+ }
+#endif
+ if (remaining >= 32) {
+ oa[k] = xor_block(offset, ctx->L[0]);
+ ta[k] = xor_block(oa[k], ctp[k]);
+ offset = oa[k + 1] = xor_block(oa[k], ctx->L[1]);
+ ta[k + 1] = xor_block(offset, ctp[k + 1]);
+ remaining -= 32;
+ k += 2;
+ }
+ if (remaining >= 16) {
+ offset = oa[k] = xor_block(offset, ctx->L[0]);
+ ta[k] = xor_block(offset, ctp[k]);
+ remaining -= 16;
+ ++k;
+ }
+ if (remaining) {
+ block pad;
+ offset = xor_block(offset, ctx->Lstar);
+ AES_encrypt((unsigned char*)&offset, tmp.u8, &ctx->encrypt_key);
+ pad = tmp.bl;
+ memcpy(tmp.u8, ctp + k, remaining);
+ tmp.bl = xor_block(tmp.bl, pad);
+ tmp.u8[remaining] = (unsigned char)0x80u;
+ memcpy(ptp + k, tmp.u8, remaining);
+ checksum = xor_block(checksum, tmp.bl);
+ }
+ }
+ AES_ecb_decrypt_blks(ta, k, &ctx->decrypt_key);
+ switch (k) {
+#if (BPI == 8)
+ case 7:
+ ptp[6] = xor_block(ta[6], oa[6]);
+ checksum = xor_block(checksum, ptp[6]);
+ case 6:
+ ptp[5] = xor_block(ta[5], oa[5]);
+ checksum = xor_block(checksum, ptp[5]);
+ case 5:
+ ptp[4] = xor_block(ta[4], oa[4]);
+ checksum = xor_block(checksum, ptp[4]);
+ case 4:
+ ptp[3] = xor_block(ta[3], oa[3]);
+ checksum = xor_block(checksum, ptp[3]);
+#endif
+ case 3:
+ ptp[2] = xor_block(ta[2], oa[2]);
+ checksum = xor_block(checksum, ptp[2]);
+ case 2:
+ ptp[1] = xor_block(ta[1], oa[1]);
+ checksum = xor_block(checksum, ptp[1]);
+ case 1:
+ ptp[0] = xor_block(ta[0], oa[0]);
+ checksum = xor_block(checksum, ptp[0]);
+ }
+
+ /* Calculate expected tag */
+ offset = xor_block(offset, ctx->Ldollar);
+ tmp.bl = xor_block(offset, checksum);
+ AES_encrypt(tmp.u8, tmp.u8, &ctx->encrypt_key);
+ tmp.bl = xor_block(tmp.bl, ctx->ad_checksum); /* Full tag */
+
+ /* Compare with proposed tag, change ct_len if invalid */
+ if ((OCB_TAG_LEN == 16) && tag) {
+ if (unequal_blocks(tmp.bl, *(block*)tag))
+ ct_len = AE_INVALID;
+ } else {
+#if (OCB_TAG_LEN > 0)
+ int len = OCB_TAG_LEN;
+#else
+ int len = ctx->tag_len;
+#endif
+ if (tag) {
+ if (constant_time_memcmp(tag, tmp.u8, len) != 0)
+ ct_len = AE_INVALID;
+ } else {
+ if (constant_time_memcmp((char*)ct + ct_len, tmp.u8, len) != 0)
+ ct_len = AE_INVALID;
+ }
+ }
+ }
+ return ct_len;
+}
+
+/* ----------------------------------------------------------------------- */
+/* Simple test program */
+/* ----------------------------------------------------------------------- */
+
+#if 0
+
+#include <stdio.h>
+#include <time.h>
+
+#if __GNUC__
+#define ALIGN(n) __attribute__((aligned(n)))
+#elif _MSC_VER
+#define ALIGN(n) __declspec(align(n))
+#else /* Not GNU/Microsoft: delete alignment uses. */
+#define ALIGN(n)
+#endif
+
+static void pbuf(void *p, unsigned len, const void *s)
+{
+ unsigned i;
+ if (s)
+ printf("%s", (char *)s);
+ for (i = 0; i < len; i++)
+ printf("%02X", (unsigned)(((unsigned char *)p)[i]));
+ printf("\n");
+}
+
+static void vectors(ae_ctx *ctx, int len)
+{
+ ALIGN(16) char pt[128];
+ ALIGN(16) char ct[144];
+ ALIGN(16) char nonce[] = {0,1,2,3,4,5,6,7,8,9,10,11};
+ int i;
+ for (i=0; i < 128; i++) pt[i] = i;
+ i = ae_encrypt(ctx,nonce,pt,len,pt,len,ct,NULL,AE_FINALIZE);
+ printf("P=%d,A=%d: ",len,len); pbuf(ct, i, NULL);
+ i = ae_encrypt(ctx,nonce,pt,0,pt,len,ct,NULL,AE_FINALIZE);
+ printf("P=%d,A=%d: ",0,len); pbuf(ct, i, NULL);
+ i = ae_encrypt(ctx,nonce,pt,len,pt,0,ct,NULL,AE_FINALIZE);
+ printf("P=%d,A=%d: ",len,0); pbuf(ct, i, NULL);
+}
+
+void validate()
+{
+ ALIGN(16) char pt[1024];
+ ALIGN(16) char ct[1024];
+ ALIGN(16) char tag[16];
+ ALIGN(16) char nonce[12] = {0,};
+ ALIGN(16) char key[32] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31};
+ ae_ctx ctx;
+ char *val_buf, *next;
+ int i, len;
+
+ val_buf = (char *)malloc(22400 + 16);
+ next = val_buf = (char *)(((size_t)val_buf + 16) & ~((size_t)15));
+
+ if (0) {
+ ae_init(&ctx, key, 16, 12, 16);
+ /* pbuf(&ctx, sizeof(ctx), "CTX: "); */
+ vectors(&ctx,0);
+ vectors(&ctx,8);
+ vectors(&ctx,16);
+ vectors(&ctx,24);
+ vectors(&ctx,32);
+ vectors(&ctx,40);
+ }
+
+ memset(key,0,32);
+ memset(pt,0,128);
+ ae_init(&ctx, key, OCB_KEY_LEN, 12, OCB_TAG_LEN);
+
+ /* RFC Vector test */
+ for (i = 0; i < 128; i++) {
+ int first = ((i/3)/(BPI*16))*(BPI*16);
+ int second = first;
+ int third = i - (first + second);
+
+ nonce[11] = i;
+
+ if (0) {
+ ae_encrypt(&ctx,nonce,pt,i,pt,i,ct,NULL,AE_FINALIZE);
+ memcpy(next,ct,(size_t)i+OCB_TAG_LEN);
+ next = next+i+OCB_TAG_LEN;
+
+ ae_encrypt(&ctx,nonce,pt,i,pt,0,ct,NULL,AE_FINALIZE);
+ memcpy(next,ct,(size_t)i+OCB_TAG_LEN);
+ next = next+i+OCB_TAG_LEN;
+
+ ae_encrypt(&ctx,nonce,pt,0,pt,i,ct,NULL,AE_FINALIZE);
+ memcpy(next,ct,OCB_TAG_LEN);
+ next = next+OCB_TAG_LEN;
+ } else {
+ ae_encrypt(&ctx,nonce,pt,first,pt,first,ct,NULL,AE_PENDING);
+ ae_encrypt(&ctx,NULL,pt+first,second,pt+first,second,ct+first,NULL,AE_PENDING);
+ ae_encrypt(&ctx,NULL,pt+first+second,third,pt+first+second,third,ct+first+second,NULL,AE_FINALIZE);
+ memcpy(next,ct,(size_t)i+OCB_TAG_LEN);
+ next = next+i+OCB_TAG_LEN;
+
+ ae_encrypt(&ctx,nonce,pt,first,pt,0,ct,NULL,AE_PENDING);
+ ae_encrypt(&ctx,NULL,pt+first,second,pt,0,ct+first,NULL,AE_PENDING);
+ ae_encrypt(&ctx,NULL,pt+first+second,third,pt,0,ct+first+second,NULL,AE_FINALIZE);
+ memcpy(next,ct,(size_t)i+OCB_TAG_LEN);
+ next = next+i+OCB_TAG_LEN;
+
+ ae_encrypt(&ctx,nonce,pt,0,pt,first,ct,NULL,AE_PENDING);
+ ae_encrypt(&ctx,NULL,pt,0,pt+first,second,ct,NULL,AE_PENDING);
+ ae_encrypt(&ctx,NULL,pt,0,pt+first+second,third,ct,NULL,AE_FINALIZE);
+ memcpy(next,ct,OCB_TAG_LEN);
+ next = next+OCB_TAG_LEN;
+ }
+
+ }
+ nonce[11] = 0;
+ ae_encrypt(&ctx,nonce,NULL,0,val_buf,next-val_buf,ct,tag,AE_FINALIZE);
+ pbuf(tag,OCB_TAG_LEN,0);
+
+
+ /* Encrypt/Decrypt test */
+ for (i = 0; i < 128; i++) {
+ int first = ((i/3)/(BPI*16))*(BPI*16);
+ int second = first;
+ int third = i - (first + second);
+
+ nonce[11] = i%128;
+
+ if (1) {
+ len = ae_encrypt(&ctx,nonce,val_buf,i,val_buf,i,ct,tag,AE_FINALIZE);
+ len = ae_encrypt(&ctx,nonce,val_buf,i,val_buf,-1,ct,tag,AE_FINALIZE);
+ len = ae_decrypt(&ctx,nonce,ct,len,val_buf,-1,pt,tag,AE_FINALIZE);
+ if (len == -1) { printf("Authentication error: %d\n", i); return; }
+ if (len != i) { printf("Length error: %d\n", i); return; }
+ if (memcmp(val_buf,pt,i)) { printf("Decrypt error: %d\n", i); return; }
+ } else {
+ len = ae_encrypt(&ctx,nonce,val_buf,i,val_buf,i,ct,NULL,AE_FINALIZE);
+ ae_decrypt(&ctx,nonce,ct,first,val_buf,first,pt,NULL,AE_PENDING);
+ ae_decrypt(&ctx,NULL,ct+first,second,val_buf+first,second,pt+first,NULL,AE_PENDING);
+ len = ae_decrypt(&ctx,NULL,ct+first+second,len-(first+second),val_buf+first+second,third,pt+first+second,NULL,AE_FINALIZE);
+ if (len == -1) { printf("Authentication error: %d\n", i); return; }
+ if (memcmp(val_buf,pt,i)) { printf("Decrypt error: %d\n", i); return; }
+ }
+
+ }
+ printf("Decrypt: PASS\n");
+}
+
+int main()
+{
+ validate();
+ return 0;
+}
+#endif
+
+#if USE_AES_NI
+char infoString[] = "OCB3 (AES-NI)";
+#elif USE_REFERENCE_AES
+char infoString[] = "OCB3 (Reference)";
+#elif USE_OPENSSL_AES
+char infoString[] = "OCB3 (OpenSSL)";
+#endif
diff --git a/keymaster/ocb_utils.cpp b/keymaster/ocb_utils.cpp
new file mode 100644
index 0000000..7038da0
--- /dev/null
+++ b/keymaster/ocb_utils.cpp
@@ -0,0 +1,194 @@
+/*
+ * 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 "ocb_utils.h"
+
+#include <assert.h>
+
+#include <new>
+
+#include <openssl/aes.h>
+#include <openssl/sha.h>
+
+#include <hardware/keymaster_defs.h>
+#include <keymaster/authorization_set.h>
+#include <keymaster/android_keymaster_utils.h>
+
+#include "openssl_err.h"
+
+namespace keymaster {
+
+class AeCtx {
+ public:
+ AeCtx() : ctx_(ae_allocate(NULL)) {}
+ ~AeCtx() {
+ ae_clear(ctx_);
+ ae_free(ctx_);
+ }
+
+ ae_ctx* get() { return ctx_; }
+
+ private:
+ ae_ctx* ctx_;
+};
+
+static keymaster_error_t BuildDerivationData(const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ const AuthorizationSet& hidden,
+ UniquePtr<uint8_t[]>* derivation_data,
+ size_t* derivation_data_length) {
+ *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;
+
+ uint8_t* buf = derivation_data->get();
+ uint8_t* end = derivation_data->get() + *derivation_data_length;
+ buf = hidden.Serialize(buf, end);
+ buf = hw_enforced.Serialize(buf, end);
+ buf = sw_enforced.Serialize(buf, end);
+
+ return KM_ERROR_OK;
+}
+
+static keymaster_error_t InitializeKeyWrappingContext(const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ const AuthorizationSet& hidden,
+ const KeymasterKeyBlob& master_key,
+ AeCtx* ctx) {
+ size_t derivation_data_length;
+ 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;
+
+ 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;
+ 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;
+ Eraser derived_key_eraser(derived_key.get(), AES_BLOCK_SIZE);
+
+ if (!ctx->get() || !hash_buf.get() || !derived_key.get())
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ // Hash derivation data.
+ Eraser sha256_ctx_eraser(sha256_ctx);
+ SHA256_Init(&sha256_ctx);
+ SHA256_Update(&sha256_ctx, derivation_data.get(), derivation_data_length);
+ SHA256_Final(hash_buf.get(), &sha256_ctx);
+
+ // Encrypt hash with master key to build derived key.
+ AES_KEY aes_key;
+ Eraser aes_key_eraser(AES_KEY);
+ if (0 !=
+ AES_set_encrypt_key(master_key.key_material, master_key.key_material_size * 8, &aes_key))
+ return TranslateLastOpenSslError();
+
+ AES_encrypt(hash_buf.get(), derived_key.get(), &aes_key);
+
+ // Set up AES OCB context using derived key.
+ if (ae_init(ctx->get(), derived_key.get(), AES_BLOCK_SIZE /* key length */, OCB_NONCE_LENGTH,
+ OCB_TAG_LENGTH) != AE_SUCCESS) {
+ memset_s(ctx->get(), 0, ae_ctx_sizeof());
+ return KM_ERROR_UNKNOWN_ERROR;
+ }
+
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t OcbEncryptKey(const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced, const AuthorizationSet& hidden,
+ const KeymasterKeyBlob& master_key,
+ const KeymasterKeyBlob& plaintext, const Buffer& nonce,
+ KeymasterKeyBlob* ciphertext, Buffer* tag) {
+ assert(ciphertext && tag);
+
+ if (nonce.available_read() != OCB_NONCE_LENGTH)
+ return KM_ERROR_INVALID_ARGUMENT;
+
+ AeCtx ctx;
+ 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 (!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, NULL /* additional data */,
+ 0 /* additional data length */, ciphertext->writable_data(),
+ tag->peek_write(), 1 /* final */);
+ if (ae_err < 0) {
+ 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;
+ assert(ae_err == static_cast<int>(plaintext.key_material_size));
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t OcbDecryptKey(const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced, const AuthorizationSet& hidden,
+ const KeymasterKeyBlob& master_key,
+ const KeymasterKeyBlob& ciphertext, const Buffer& nonce,
+ const Buffer& tag, KeymasterKeyBlob* plaintext) {
+ assert(plaintext);
+
+ if (nonce.available_read() != OCB_NONCE_LENGTH || tag.available_read() != OCB_TAG_LENGTH)
+ return KM_ERROR_INVALID_ARGUMENT;
+
+ AeCtx ctx;
+ 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 (!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, NULL /* additional data */,
+ 0 /* additional data length */, plaintext->writable_data(),
+ tag.peek_read(), 1 /* final */);
+ if (ae_err == AE_INVALID) {
+ // Authentication failed! Decryption probably succeeded(ish), but we don't want to return
+ // any data when the authentication fails, so clear it.
+ plaintext->Clear();
+ LOG_E("Failed to validate authentication tag during key decryption", 0);
+ return KM_ERROR_INVALID_KEY_BLOB;
+ } else if (ae_err < 0) {
+ LOG_E("Failed to decrypt key, error: %d", ae_err);
+ return KM_ERROR_UNKNOWN_ERROR;
+ }
+ assert(ae_err == static_cast<int>(ciphertext.key_material_size));
+ return KM_ERROR_OK;
+}
+
+} // namespace keymaster
diff --git a/keymaster/ocb_utils.h b/keymaster/ocb_utils.h
new file mode 100644
index 0000000..bae1e08
--- /dev/null
+++ b/keymaster/ocb_utils.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2014 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_OCB_UTILS_H_
+#define SYSTEM_KEYMASTER_OCB_UTILS_H_
+
+#include "ae.h"
+
+#include <hardware/keymaster_defs.h>
+
+#include <keymaster/serializable.h>
+
+namespace keymaster {
+
+class AuthorizationSet;
+struct KeymasterKeyBlob;
+
+static const int OCB_NONCE_LENGTH = 12;
+static const int OCB_TAG_LENGTH = 16;
+
+keymaster_error_t OcbEncryptKey(const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced, const AuthorizationSet& hidden,
+ const KeymasterKeyBlob& master_key,
+ const KeymasterKeyBlob& plaintext, const Buffer& nonce,
+ KeymasterKeyBlob* ciphertext, Buffer* tag);
+
+keymaster_error_t OcbDecryptKey(const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced, const AuthorizationSet& hidden,
+ const KeymasterKeyBlob& master_key,
+ const KeymasterKeyBlob& ciphertext, const Buffer& nonce,
+ const Buffer& tag, KeymasterKeyBlob* plaintext);
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_OCB_UTILS_H_
diff --git a/keymaster/openssl_err.cpp b/keymaster/openssl_err.cpp
new file mode 100644
index 0000000..078b8e3
--- /dev/null
+++ b/keymaster/openssl_err.cpp
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2014 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_err.h"
+
+#include <openssl/err.h>
+#include <openssl/evp.h>
+
+#if defined(OPENSSL_IS_BORINGSSL)
+#include <openssl/asn1.h>
+#include <openssl/cipher.h>
+#include <openssl/pkcs8.h>
+#include <openssl/x509v3.h>
+#endif
+
+#include <hardware/keymaster_defs.h>
+#include <keymaster/logger.h>
+
+namespace keymaster {
+
+static keymaster_error_t TranslateEvpError(int reason);
+#if defined(OPENSSL_IS_BORINGSSL)
+static keymaster_error_t TranslateASN1Error(int reason);
+static keymaster_error_t TranslateCipherError(int reason);
+static keymaster_error_t TranslatePKCS8Error(int reason);
+static keymaster_error_t TranslateX509v3Error(int reason);
+static keymaster_error_t TranslateRsaError(int reason);
+#endif
+
+keymaster_error_t TranslateLastOpenSslError(bool log_message) {
+ unsigned long error = ERR_peek_last_error();
+
+ if (log_message) {
+ LOG_D("%s", ERR_error_string(error, NULL));
+ }
+
+ int reason = ERR_GET_REASON(error);
+
+ /* Handle global error reasons */
+ switch (reason) {
+ case ERR_R_MALLOC_FAILURE:
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ case ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED:
+ case ERR_R_PASSED_NULL_PARAMETER:
+ case ERR_R_INTERNAL_ERROR:
+ case ERR_R_OVERFLOW:
+ return KM_ERROR_UNKNOWN_ERROR;
+ default:
+ break;
+ }
+
+ switch (ERR_GET_LIB(error)) {
+ case ERR_LIB_USER:
+ return static_cast<keymaster_error_t>(reason);
+ case ERR_LIB_EVP:
+ return TranslateEvpError(reason);
+#if defined(OPENSSL_IS_BORINGSSL)
+ case ERR_LIB_ASN1:
+ return TranslateASN1Error(reason);
+ case ERR_LIB_CIPHER:
+ return TranslateCipherError(reason);
+ case ERR_LIB_PKCS8:
+ return TranslatePKCS8Error(reason);
+ case ERR_LIB_X509V3:
+ return TranslateX509v3Error(reason);
+ case ERR_LIB_RSA:
+ return TranslateRsaError(reason);
+#else
+ case ERR_LIB_ASN1:
+ LOG_E("ASN.1 parsing error %d", reason);
+ return KM_ERROR_INVALID_ARGUMENT;
+#endif
+ }
+
+ LOG_E("Openssl error %d, %d", ERR_GET_LIB(error), reason);
+ return KM_ERROR_UNKNOWN_ERROR;
+}
+
+#if defined(OPENSSL_IS_BORINGSSL)
+
+keymaster_error_t TranslatePKCS8Error(int reason) {
+ switch (reason) {
+ case PKCS8_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM:
+ case PKCS8_R_UNKNOWN_CIPHER:
+ return KM_ERROR_UNSUPPORTED_ALGORITHM;
+
+ case PKCS8_R_PRIVATE_KEY_ENCODE_ERROR:
+ case PKCS8_R_PRIVATE_KEY_DECODE_ERROR:
+ return KM_ERROR_INVALID_KEY_BLOB;
+
+ case PKCS8_R_ENCODE_ERROR:
+ return KM_ERROR_INVALID_ARGUMENT;
+
+ default:
+ return KM_ERROR_UNKNOWN_ERROR;
+ }
+}
+
+keymaster_error_t TranslateCipherError(int reason) {
+ switch (reason) {
+ case CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH:
+ case CIPHER_R_WRONG_FINAL_BLOCK_LENGTH:
+ return KM_ERROR_INVALID_INPUT_LENGTH;
+
+ case CIPHER_R_UNSUPPORTED_KEY_SIZE:
+ case CIPHER_R_BAD_KEY_LENGTH:
+ return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+
+ case CIPHER_R_BAD_DECRYPT:
+ return KM_ERROR_INVALID_ARGUMENT;
+
+ case CIPHER_R_INVALID_KEY_LENGTH:
+ return KM_ERROR_INVALID_KEY_BLOB;
+
+ default:
+ return KM_ERROR_UNKNOWN_ERROR;
+ }
+}
+
+keymaster_error_t TranslateASN1Error(int reason) {
+ switch (reason) {
+#if !defined(OPENSSL_IS_BORINGSSL)
+ case ASN1_R_UNSUPPORTED_CIPHER:
+ return KM_ERROR_UNSUPPORTED_ALGORITHM;
+
+ case ASN1_R_ERROR_LOADING_SECTION:
+ return KM_ERROR_INVALID_KEY_BLOB;
+#endif
+
+ case ASN1_R_ENCODE_ERROR:
+ return KM_ERROR_INVALID_ARGUMENT;
+
+ default:
+ return KM_ERROR_UNKNOWN_ERROR;
+ }
+}
+
+keymaster_error_t TranslateX509v3Error(int reason) {
+ switch (reason) {
+ case X509V3_R_UNKNOWN_OPTION:
+ return KM_ERROR_UNSUPPORTED_ALGORITHM;
+
+ default:
+ return KM_ERROR_UNKNOWN_ERROR;
+ }
+}
+
+keymaster_error_t TranslateRsaError(int reason) {
+ switch (reason) {
+ case RSA_R_KEY_SIZE_TOO_SMALL:
+ LOG_W("RSA key is too small to use with selected padding/digest", 0);
+ return KM_ERROR_INCOMPATIBLE_PADDING_MODE;
+ case RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE:
+ case RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE:
+ return KM_ERROR_INVALID_INPUT_LENGTH;
+ case RSA_R_DATA_TOO_LARGE_FOR_MODULUS:
+ return KM_ERROR_INVALID_ARGUMENT;
+ default:
+ return KM_ERROR_UNKNOWN_ERROR;
+ };
+}
+
+#endif // OPENSSL_IS_BORINGSSL
+
+keymaster_error_t TranslateEvpError(int reason) {
+ switch (reason) {
+
+#if !defined(OPENSSL_IS_BORINGSSL)
+ case EVP_R_UNKNOWN_DIGEST:
+ return KM_ERROR_UNSUPPORTED_DIGEST;
+
+ case EVP_R_UNSUPPORTED_PRF:
+ case EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM:
+ case EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION:
+ case EVP_R_UNSUPPORTED_SALT_TYPE:
+ case EVP_R_UNKNOWN_PBE_ALGORITHM:
+ case EVP_R_UNSUPORTED_NUMBER_OF_ROUNDS:
+ case EVP_R_UNSUPPORTED_CIPHER:
+ case EVP_R_PKCS8_UNKNOWN_BROKEN_TYPE:
+ case EVP_R_UNKNOWN_CIPHER:
+#endif
+ case EVP_R_UNSUPPORTED_ALGORITHM:
+ case EVP_R_OPERATON_NOT_INITIALIZED:
+ case EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE:
+ return KM_ERROR_UNSUPPORTED_ALGORITHM;
+
+#if !defined(OPENSSL_IS_BORINGSSL)
+ case EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH:
+ case EVP_R_WRONG_FINAL_BLOCK_LENGTH:
+ return KM_ERROR_INVALID_INPUT_LENGTH;
+
+ case EVP_R_UNSUPPORTED_KEYLENGTH:
+ case EVP_R_BAD_KEY_LENGTH:
+ return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+#endif
+
+#if !defined(OPENSSL_IS_BORINGSSL)
+ case EVP_R_BAD_BLOCK_LENGTH:
+ case EVP_R_BN_DECODE_ERROR:
+ case EVP_R_BN_PUBKEY_ERROR:
+ case EVP_R_CIPHER_PARAMETER_ERROR:
+ case EVP_R_ERROR_LOADING_SECTION:
+ case EVP_R_EXPECTING_A_DH_KEY:
+ case EVP_R_EXPECTING_A_ECDSA_KEY:
+ case EVP_R_EXPECTING_A_EC_KEY:
+ case EVP_R_INVALID_DIGEST:
+ case EVP_R_INVALID_KEY_LENGTH:
+ case EVP_R_NO_DSA_PARAMETERS:
+ case EVP_R_PRIVATE_KEY_DECODE_ERROR:
+ case EVP_R_PRIVATE_KEY_ENCODE_ERROR:
+ case EVP_R_PUBLIC_KEY_NOT_RSA:
+ case EVP_R_WRONG_PUBLIC_KEY_TYPE:
+#endif
+ case EVP_R_BUFFER_TOO_SMALL:
+ case EVP_R_EXPECTING_AN_RSA_KEY:
+ case EVP_R_EXPECTING_A_DSA_KEY:
+ case EVP_R_MISSING_PARAMETERS:
+ return KM_ERROR_INVALID_KEY_BLOB;
+
+#if !defined(OPENSSL_IS_BORINGSSL)
+ case EVP_R_BAD_DECRYPT:
+ case EVP_R_ENCODE_ERROR:
+#endif
+ case EVP_R_DIFFERENT_PARAMETERS:
+ case EVP_R_DECODE_ERROR:
+ return KM_ERROR_INVALID_ARGUMENT;
+
+ case EVP_R_DIFFERENT_KEY_TYPES:
+ return KM_ERROR_INCOMPATIBLE_ALGORITHM;
+ }
+
+ return KM_ERROR_UNKNOWN_ERROR;
+}
+
+} // namespace keymaster
diff --git a/keymaster/openssl_err.h b/keymaster/openssl_err.h
new file mode 100644
index 0000000..8f97ef5
--- /dev/null
+++ b/keymaster/openssl_err.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 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_OPENSSL_ERR_H_
+#define SYSTEM_KEYMASTER_OPENSSL_ERR_H_
+
+#include <hardware/keymaster_defs.h>
+#include <keymaster/logger.h>
+
+namespace keymaster {
+
+/**
+ * Translate the last OpenSSL error to a keymaster error. Does not remove the error from the queue.
+ */
+keymaster_error_t TranslateLastOpenSslError(bool log_message = true);
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_OPENSSL_ERR_H_
diff --git a/keymaster/openssl_utils.cpp b/keymaster/openssl_utils.cpp
new file mode 100644
index 0000000..5d2cb1c
--- /dev/null
+++ b/keymaster/openssl_utils.cpp
@@ -0,0 +1,142 @@
+/*
+ * 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 "openssl_utils.h"
+
+#include <keymaster/android_keymaster_utils.h>
+
+#include "openssl_err.h"
+
+namespace keymaster {
+
+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:
+ *key_size_bits = 224;
+ break;
+ case NID_X9_62_prime256v1:
+ *key_size_bits = 256;
+ break;
+ case NID_secp384r1:
+ *key_size_bits = 384;
+ break;
+ case NID_secp521r1:
+ *key_size_bits = 521;
+ break;
+ default:
+ return KM_ERROR_UNSUPPORTED_EC_FIELD;
+ }
+ return KM_ERROR_OK;
+}
+
+EC_GROUP* ec_get_group(keymaster_ec_curve_t curve) {
+ switch (curve) {
+ case KM_EC_CURVE_P_224:
+ return EC_GROUP_new_by_curve_name(NID_secp224r1);
+ break;
+ case KM_EC_CURVE_P_256:
+ return EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
+ break;
+ case KM_EC_CURVE_P_384:
+ return EC_GROUP_new_by_curve_name(NID_secp384r1);
+ break;
+ case KM_EC_CURVE_P_521:
+ return EC_GROUP_new_by_curve_name(NID_secp521r1);
+ break;
+ default:
+ return nullptr;
+ break;
+ }
+}
+
+void convert_bn_to_blob(BIGNUM* bn, keymaster_blob_t* blob) {
+ blob->data_length = BN_num_bytes(bn);
+ blob->data = new uint8_t[blob->data_length];
+ BN_bn2bin(bn, const_cast<uint8_t*>(blob->data));
+}
+
+static int convert_to_evp(keymaster_algorithm_t algorithm) {
+ switch (algorithm) {
+ case KM_ALGORITHM_RSA:
+ return EVP_PKEY_RSA;
+ case KM_ALGORITHM_EC:
+ return EVP_PKEY_EC;
+ default:
+ return -1;
+ };
+}
+
+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 == NULL || 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(NULL, &key_data, key_length));
+ if (pkcs8.get() == NULL)
+ return TranslateLastOpenSslError(true /* log_message */);
+
+ pkey->reset(EVP_PKCS82PKEY(pkcs8.get()));
+ 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),
+ convert_to_evp(expected_algorithm));
+ return KM_ERROR_INVALID_KEY_BLOB;
+ }
+
+ return KM_ERROR_OK;
+}
+
+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;
+
+ return convert_pkcs8_blob_to_evp(key_material.key_material, key_material.key_material_size,
+ expected_algorithm, pkey);
+}
+
+keymaster_error_t EvpKeyToKeyMaterial(const EVP_PKEY* pkey, KeymasterKeyBlob* key_blob) {
+ int key_data_size = i2d_PrivateKey(pkey, NULL /* key_data*/);
+ if (key_data_size <= 0)
+ return TranslateLastOpenSslError();
+
+ if (!key_blob->Reset(key_data_size))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ uint8_t* tmp = key_blob->writable_data();
+ i2d_PrivateKey(pkey, &tmp);
+
+ 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());
+ UniquePtr<BIGNUM, BIGNUM_Delete> order(BN_new());
+ if (!EC_GROUP_get_order(group, order.get(), bn_ctx.get())) {
+ LOG_E("Failed to get EC group order", 0);
+ return 0;
+ }
+ return BN_num_bits(order.get());
+}
+
+} // namespace keymaster
diff --git a/keymaster/openssl_utils.h b/keymaster/openssl_utils.h
new file mode 100644
index 0000000..034b129
--- /dev/null
+++ b/keymaster/openssl_utils.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2014 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_OPENSSL_UTILS_H_
+#define SYSTEM_KEYMASTER_OPENSSL_UTILS_H_
+
+#include <openssl/bn.h>
+#include <openssl/ec.h>
+#include <openssl/engine.h>
+#include <openssl/evp.h>
+#include <openssl/rsa.h>
+#include <openssl/x509.h>
+
+#include <UniquePtr.h>
+
+#include <hardware/keymaster_defs.h>
+
+namespace keymaster {
+
+struct KeymasterKeyBlob;
+
+class EvpMdCtxCleaner {
+ public:
+ explicit EvpMdCtxCleaner(EVP_MD_CTX* ctx) : ctx_(ctx) {}
+ ~EvpMdCtxCleaner() { EVP_MD_CTX_cleanup(ctx_); }
+
+ private:
+ EVP_MD_CTX* ctx_;
+};
+
+template <typename T, void (*FreeFunc)(T*)> struct OpenSslObjectDeleter {
+ void operator()(T* p) { FreeFunc(p); }
+};
+
+#define DEFINE_OPENSSL_OBJECT_POINTER(name) \
+ typedef OpenSslObjectDeleter<name, name##_free> name##_Delete; \
+ typedef UniquePtr<name, name##_Delete> name##_Ptr;
+
+DEFINE_OPENSSL_OBJECT_POINTER(ASN1_INTEGER)
+DEFINE_OPENSSL_OBJECT_POINTER(ASN1_OBJECT)
+DEFINE_OPENSSL_OBJECT_POINTER(ASN1_OCTET_STRING)
+DEFINE_OPENSSL_OBJECT_POINTER(ASN1_TIME)
+DEFINE_OPENSSL_OBJECT_POINTER(BN_CTX);
+DEFINE_OPENSSL_OBJECT_POINTER(EC_GROUP);
+DEFINE_OPENSSL_OBJECT_POINTER(EC_KEY);
+DEFINE_OPENSSL_OBJECT_POINTER(EC_POINT);
+DEFINE_OPENSSL_OBJECT_POINTER(ENGINE);
+DEFINE_OPENSSL_OBJECT_POINTER(EVP_PKEY);
+DEFINE_OPENSSL_OBJECT_POINTER(PKCS8_PRIV_KEY_INFO);
+DEFINE_OPENSSL_OBJECT_POINTER(RSA);
+DEFINE_OPENSSL_OBJECT_POINTER(X509)
+DEFINE_OPENSSL_OBJECT_POINTER(X509_EXTENSION)
+DEFINE_OPENSSL_OBJECT_POINTER(X509_NAME)
+
+typedef OpenSslObjectDeleter<BIGNUM, BN_free> BIGNUM_Delete;
+typedef UniquePtr<BIGNUM, BIGNUM_Delete> BIGNUM_Ptr;
+
+keymaster_error_t ec_get_group_size(const EC_GROUP* group, size_t* key_size_bits);
+EC_GROUP* ec_get_group(keymaster_ec_curve_t curve);
+
+/**
+ * Many OpenSSL APIs take ownership of an argument on success but don't free the argument on
+ * failure. This means we need to tell our scoped pointers when we've transferred ownership, without
+ * triggering a warning by not using the result of release().
+ */
+template <typename T, typename Delete_T>
+inline void release_because_ownership_transferred(UniquePtr<T, Delete_T>& p) {
+ T* val __attribute__((unused)) = p.release();
+}
+
+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);
+
+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>* evp_pkey);
+
+keymaster_error_t EvpKeyToKeyMaterial(const EVP_PKEY* evp_pkey, KeymasterKeyBlob* key_blob);
+
+size_t ec_group_size_bits(EC_KEY* ec_key);
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_OPENSSL_UTILS_H_
diff --git a/keymaster/operation.cpp b/keymaster/operation.cpp
new file mode 100644
index 0000000..410c9aa
--- /dev/null
+++ b/keymaster/operation.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2014 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 "operation.h"
+
+#include <keymaster/authorization_set.h>
+
+#include "key.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;
+ return false;
+}
+
+bool OperationFactory::supported(keymaster_block_mode_t block_mode) const {
+ 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;
+ return false;
+}
+
+bool OperationFactory::supported(keymaster_digest_t digest) const {
+ 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;
+ return false;
+}
+
+inline bool is_public_key_algorithm(keymaster_algorithm_t algorithm) {
+ switch (algorithm) {
+ case KM_ALGORITHM_HMAC:
+ case KM_ALGORITHM_AES:
+ return false;
+ case KM_ALGORITHM_RSA:
+ case KM_ALGORITHM_EC:
+ return true;
+ }
+
+ // Unreachable.
+ assert(false);
+ return false;
+}
+
+bool OperationFactory::is_public_key_operation() const {
+ KeyType key_type = registry_key();
+
+ if (!is_public_key_algorithm(key_type.algorithm))
+ return false;
+
+ switch (key_type.purpose) {
+ case KM_PURPOSE_VERIFY:
+ case KM_PURPOSE_ENCRYPT:
+ return true;
+ case KM_PURPOSE_SIGN:
+ case KM_PURPOSE_DECRYPT:
+ case KM_PURPOSE_DERIVE_KEY:
+ return false;
+ };
+
+ // Unreachable.
+ assert(false);
+ return false;
+}
+
+bool OperationFactory::GetAndValidatePadding(const AuthorizationSet& begin_params, const Key& key,
+ keymaster_padding_t* padding,
+ keymaster_error_t* error) const {
+ *error = KM_ERROR_UNSUPPORTED_PADDING_MODE;
+ if (!begin_params.GetTagValue(TAG_PADDING, padding)) {
+ LOG_E("%d padding modes specified in begin params", begin_params.GetTagCount(TAG_PADDING));
+ return false;
+ } else if (!supported(*padding)) {
+ LOG_E("Padding mode %d not supported", *padding);
+ return false;
+ } else if (
+ // If it's a public key operation, all padding modes are authorized.
+ !is_public_key_operation() &&
+ // Otherwise the key needs to authorize the specific mode.
+ !key.authorizations().Contains(TAG_PADDING, *padding) &&
+ !key.authorizations().Contains(TAG_PADDING_OLD, *padding)) {
+ LOG_E("Padding mode %d was specified, but not authorized by key", *padding);
+ *error = KM_ERROR_INCOMPATIBLE_PADDING_MODE;
+ return false;
+ }
+
+ *error = KM_ERROR_OK;
+ return true;
+}
+
+bool OperationFactory::GetAndValidateDigest(const AuthorizationSet& begin_params, const Key& key,
+ keymaster_digest_t* digest,
+ keymaster_error_t* error) const {
+ *error = KM_ERROR_UNSUPPORTED_DIGEST;
+ if (!begin_params.GetTagValue(TAG_DIGEST, digest)) {
+ LOG_E("%d digests specified in begin params", begin_params.GetTagCount(TAG_DIGEST));
+ return false;
+ } else if (!supported(*digest)) {
+ LOG_E("Digest %d not supported", *digest);
+ return false;
+ } else if (
+ // If it's a public key operation, all digests are authorized.
+ !is_public_key_operation() &&
+ // Otherwise the key needs to authorize the specific digest.
+ !key.authorizations().Contains(TAG_DIGEST, *digest) &&
+ !key.authorizations().Contains(TAG_DIGEST_OLD, *digest)) {
+ LOG_E("Digest %d was specified, but not authorized by key", *digest);
+ *error = KM_ERROR_INCOMPATIBLE_DIGEST;
+ return false;
+ }
+ *error = KM_ERROR_OK;
+ return true;
+}
+
+keymaster_error_t Operation::UpdateForFinish(const AuthorizationSet& input_params,
+ const Buffer& input) {
+ if (!input_params.empty() || input.available_read()) {
+ size_t input_consumed;
+ Buffer output;
+ AuthorizationSet output_params;
+ keymaster_error_t error =
+ Update(input_params, input, &output_params, &output, &input_consumed);
+ if (error != KM_ERROR_OK)
+ return error;
+ assert(input_consumed == input.available_read());
+ assert(output_params.empty());
+ assert(output.available_read() == 0);
+ }
+
+ return KM_ERROR_OK;
+}
+
+} // namespace keymaster
diff --git a/keymaster/operation.h b/keymaster/operation.h
new file mode 100644
index 0000000..aadc406
--- /dev/null
+++ b/keymaster/operation.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2014 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_OPERATION_H_
+#define SYSTEM_KEYMASTER_OPERATION_H_
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <hardware/keymaster_defs.h>
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/authorization_set.h>
+#include <keymaster/logger.h>
+
+namespace keymaster {
+
+class AuthorizationSet;
+class Key;
+class Operation;
+
+class OperationFactory {
+ public:
+ virtual ~OperationFactory() {}
+
+ // Required for registry
+ struct KeyType {
+ KeyType(keymaster_algorithm_t alg, keymaster_purpose_t purp)
+ : algorithm(alg), purpose(purp) {}
+
+ keymaster_algorithm_t algorithm;
+ keymaster_purpose_t purpose;
+
+ bool operator==(const KeyType& rhs) const {
+ return algorithm == rhs.algorithm && purpose == rhs.purpose;
+ }
+ };
+ virtual KeyType registry_key() const = 0;
+
+ // Factory methods
+ virtual Operation* CreateOperation(const Key& key, const AuthorizationSet& begin_params,
+ keymaster_error_t* error) = 0;
+
+ // Informational methods. The returned arrays reference static memory and must not be
+ // deallocated or modified.
+ virtual const keymaster_padding_t* SupportedPaddingModes(size_t* padding_count) const {
+ *padding_count = 0;
+ return NULL;
+ }
+ virtual const keymaster_block_mode_t* SupportedBlockModes(size_t* block_mode_count) const {
+ *block_mode_count = 0;
+ return NULL;
+ }
+ virtual const keymaster_digest_t* SupportedDigests(size_t* digest_count) const {
+ *digest_count = 0;
+ return NULL;
+ }
+
+ // Convenience methods
+ bool supported(keymaster_padding_t padding) const;
+ bool supported(keymaster_block_mode_t padding) const;
+ bool supported(keymaster_digest_t padding) const;
+
+ bool is_public_key_operation() const;
+
+ bool GetAndValidatePadding(const AuthorizationSet& begin_params, const Key& key,
+ keymaster_padding_t* padding, keymaster_error_t* error) const;
+ bool GetAndValidateDigest(const AuthorizationSet& begin_params, const Key& key,
+ keymaster_digest_t* digest, keymaster_error_t* error) const;
+};
+
+/**
+ * Abstract base for all cryptographic operations.
+ */
+class Operation {
+ public:
+ explicit Operation(keymaster_purpose_t purpose) : purpose_(purpose) {}
+ virtual ~Operation() {}
+
+ keymaster_purpose_t purpose() const { return purpose_; }
+
+ void set_key_id(uint64_t key_id) { key_id_ = key_id; }
+ uint64_t key_id() const { return key_id_; }
+
+ void SetAuthorizations(const AuthorizationSet& auths) {
+ key_auths_.Reinitialize(auths.data(), auths.size());
+ }
+ const AuthorizationSet authorizations() { return key_auths_; }
+
+ virtual keymaster_error_t Begin(const AuthorizationSet& input_params,
+ AuthorizationSet* output_params) = 0;
+ virtual keymaster_error_t Update(const AuthorizationSet& input_params, const Buffer& input,
+ AuthorizationSet* output_params, Buffer* output,
+ size_t* input_consumed) = 0;
+ virtual keymaster_error_t Finish(const AuthorizationSet& input_params, const Buffer& input,
+ const Buffer& signature, AuthorizationSet* output_params,
+ Buffer* output) = 0;
+ virtual keymaster_error_t Abort() = 0;
+
+protected:
+ // Helper function for implementing Finish() methods that need to call Update() to process
+ // input, but don't expect any output.
+ keymaster_error_t UpdateForFinish(const AuthorizationSet& input_params, const Buffer& input);
+
+ private:
+ const keymaster_purpose_t purpose_;
+ AuthorizationSet key_auths_;
+ uint64_t key_id_;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_OPERATION_H_
diff --git a/keymaster/operation_table.cpp b/keymaster/operation_table.cpp
new file mode 100644
index 0000000..d30885e
--- /dev/null
+++ b/keymaster/operation_table.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 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 "operation_table.h"
+
+#include <new>
+
+#include <openssl/rand.h>
+
+#include "openssl_err.h"
+#include "operation.h"
+
+namespace keymaster {
+
+OperationTable::Entry::~Entry() {
+ delete operation;
+ operation = NULL;
+ handle = 0;
+}
+
+keymaster_error_t OperationTable::Add(Operation* operation,
+ keymaster_operation_handle_t* op_handle) {
+ if (!table_.get()) {
+ table_.reset(new (std::nothrow) Entry[table_size_]);
+ if (!table_.get())
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ }
+
+ UniquePtr<Operation> op(operation);
+ if (RAND_bytes(reinterpret_cast<uint8_t*>(op_handle), sizeof(*op_handle)) != 1)
+ return TranslateLastOpenSslError();
+ if (*op_handle == 0) {
+ // Statistically this is vanishingly unlikely, which means if it ever happens in practice,
+ // it indicates a broken RNG.
+ return KM_ERROR_UNKNOWN_ERROR;
+ }
+
+ for (size_t i = 0; i < table_size_; ++i) {
+ if (table_[i].operation == NULL) {
+ table_[i].operation = op.release();
+ table_[i].handle = *op_handle;
+ return KM_ERROR_OK;
+ }
+ }
+ return KM_ERROR_TOO_MANY_OPERATIONS;
+}
+
+Operation* OperationTable::Find(keymaster_operation_handle_t op_handle) {
+ if (op_handle == 0)
+ return NULL;
+
+ if (!table_.get())
+ return NULL;
+
+ for (size_t i = 0; i < table_size_; ++i) {
+ if (table_[i].handle == op_handle)
+ return table_[i].operation;
+ }
+ return NULL;
+}
+
+bool OperationTable::Delete(keymaster_operation_handle_t op_handle) {
+ if (!table_.get())
+ return false;
+
+ for (size_t i = 0; i < table_size_; ++i) {
+ if (table_[i].handle == op_handle) {
+ delete table_[i].operation;
+ table_[i].operation = NULL;
+ table_[i].handle = 0;
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace keymaster
diff --git a/keymaster/operation_table.h b/keymaster/operation_table.h
new file mode 100644
index 0000000..c840ad9
--- /dev/null
+++ b/keymaster/operation_table.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 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_OPERATION_TABLE_H
+#define SYSTEM_KEYMASTER_OPERATION_TABLE_H
+
+#include <UniquePtr.h>
+
+#include <hardware/keymaster_defs.h>
+
+namespace keymaster {
+
+class Operation;
+
+class OperationTable {
+ public:
+ explicit OperationTable(size_t table_size) : table_size_(table_size) {}
+
+ struct Entry {
+ Entry() {
+ handle = 0;
+ operation = NULL;
+ };
+ ~Entry();
+ keymaster_operation_handle_t handle;
+ Operation* operation;
+ };
+
+ keymaster_error_t Add(Operation* operation, keymaster_operation_handle_t* op_handle);
+ Operation* Find(keymaster_operation_handle_t op_handle);
+ bool Delete(keymaster_operation_handle_t);
+
+ private:
+ UniquePtr<Entry[]> table_;
+ size_t table_size_;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_OPERATION_TABLE_H
diff --git a/keymaster/rsa_key.cpp b/keymaster/rsa_key.cpp
new file mode 100644
index 0000000..4231953
--- /dev/null
+++ b/keymaster/rsa_key.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2014 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 "rsa_key.h"
+
+#include <keymaster/keymaster_context.h>
+
+#include "openssl_err.h"
+#include "openssl_utils.h"
+#include "rsa_operation.h"
+
+namespace keymaster {
+
+bool RsaKey::EvpToInternal(const EVP_PKEY* pkey) {
+ rsa_key_.reset(EVP_PKEY_get1_RSA(const_cast<EVP_PKEY*>(pkey)));
+ return rsa_key_.get() != NULL;
+}
+
+bool RsaKey::InternalToEvp(EVP_PKEY* pkey) const {
+ return EVP_PKEY_set1_RSA(pkey, rsa_key_.get()) == 1;
+}
+
+bool RsaKey::SupportedMode(keymaster_purpose_t purpose, keymaster_padding_t padding) {
+ switch (purpose) {
+ case KM_PURPOSE_SIGN:
+ case KM_PURPOSE_VERIFY:
+ return padding == KM_PAD_NONE || padding == KM_PAD_RSA_PSS ||
+ padding == KM_PAD_RSA_PKCS1_1_5_SIGN;
+
+ case KM_PURPOSE_ENCRYPT:
+ case KM_PURPOSE_DECRYPT:
+ return padding == KM_PAD_RSA_OAEP || padding == KM_PAD_RSA_PKCS1_1_5_ENCRYPT;
+
+ case KM_PURPOSE_DERIVE_KEY:
+ return false;
+ };
+ return false;
+}
+
+bool RsaKey::SupportedMode(keymaster_purpose_t purpose, keymaster_digest_t digest) {
+ switch (purpose) {
+ case KM_PURPOSE_SIGN:
+ case KM_PURPOSE_VERIFY:
+ return digest == KM_DIGEST_NONE || digest == KM_DIGEST_SHA_2_256;
+
+ case KM_PURPOSE_ENCRYPT:
+ case KM_PURPOSE_DECRYPT:
+ /* Don't care */
+ break;
+
+ case KM_PURPOSE_DERIVE_KEY:
+ return false;
+ };
+ return true;
+}
+
+} // namespace keymaster
diff --git a/keymaster/rsa_key.h b/keymaster/rsa_key.h
new file mode 100644
index 0000000..502f28a
--- /dev/null
+++ b/keymaster/rsa_key.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2014 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_KEY_H_
+#define SYSTEM_KEYMASTER_RSA_KEY_H_
+
+#include <openssl/rsa.h>
+
+#include "asymmetric_key.h"
+
+namespace keymaster {
+
+class RsaKey : public AsymmetricKey {
+ public:
+ RsaKey(const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+ keymaster_error_t* error)
+ : AsymmetricKey(hw_enforced, sw_enforced, error) {}
+
+ bool InternalToEvp(EVP_PKEY* pkey) const override;
+ bool EvpToInternal(const EVP_PKEY* pkey) override;
+
+ 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, const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+ keymaster_error_t* error)
+ : AsymmetricKey(hw_enforced, sw_enforced, error), rsa_key_(rsa) {}
+
+ private:
+ UniquePtr<RSA, RSA_Delete> rsa_key_;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_RSA_KEY_H_
diff --git a/keymaster/rsa_key_factory.cpp b/keymaster/rsa_key_factory.cpp
new file mode 100644
index 0000000..e6c3f8c
--- /dev/null
+++ b/keymaster/rsa_key_factory.cpp
@@ -0,0 +1,180 @@
+/*
+ * 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/rsa_key_factory.h>
+
+#include <new>
+
+#include <keymaster/keymaster_context.h>
+
+#include "openssl_err.h"
+#include "openssl_utils.h"
+#include "rsa_key.h"
+#include "rsa_operation.h"
+
+namespace keymaster {
+
+const int kMaximumRsaKeySize = 16 * 1024; // 16kbits should be enough for anyone.
+
+static RsaSigningOperationFactory sign_factory;
+static RsaVerificationOperationFactory verify_factory;
+static RsaEncryptionOperationFactory encrypt_factory;
+static RsaDecryptionOperationFactory decrypt_factory;
+
+OperationFactory* RsaKeyFactory::GetOperationFactory(keymaster_purpose_t purpose) const {
+ switch (purpose) {
+ case KM_PURPOSE_SIGN:
+ return &sign_factory;
+ case KM_PURPOSE_VERIFY:
+ return &verify_factory;
+ case KM_PURPOSE_ENCRYPT:
+ return &encrypt_factory;
+ case KM_PURPOSE_DECRYPT:
+ return &decrypt_factory;
+ default:
+ return nullptr;
+ }
+}
+
+keymaster_error_t RsaKeyFactory::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;
+
+ const AuthorizationSet& authorizations(key_description);
+
+ uint64_t public_exponent;
+ if (!authorizations.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 (!authorizations.GetTagValue(TAG_KEY_SIZE, &key_size)) {
+ LOG_E("No key size specified for RSA key generation", 0);
+ return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+ }
+ if (key_size % 8 != 0 || key_size > kMaximumRsaKeySize) {
+ LOG_E("Invalid key size of %u bits specified for RSA key generation", key_size);
+ 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() == NULL || rsa_key.get() == NULL || pkey.get() == NULL)
+ 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(), NULL /* callback */))
+ 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;
+
+ return context_->CreateKeyBlob(authorizations, KM_ORIGIN_GENERATED, key_material, key_blob,
+ hw_enforced, sw_enforced);
+}
+
+keymaster_error_t RsaKeyFactory::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;
+ return context_->CreateKeyBlob(authorizations, KM_ORIGIN_IMPORTED, input_key_material,
+ output_key_blob, hw_enforced, sw_enforced);
+}
+
+keymaster_error_t RsaKeyFactory::UpdateImportKeyDescription(const AuthorizationSet& key_description,
+ keymaster_key_format_t key_format,
+ const KeymasterKeyBlob& key_material,
+ AuthorizationSet* updated_description,
+ uint64_t* public_exponent,
+ uint32_t* key_size) const {
+ if (!updated_description || !public_exponent || !key_size)
+ 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;
+
+ UniquePtr<RSA, RsaKey::RSA_Delete> 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 (!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)) {
+ LOG_E("Imported public exponent (%u) does not match specified public exponent (%u)",
+ *public_exponent, BN_get_word(rsa_key->e));
+ return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
+ }
+
+ *key_size = RSA_size(rsa_key.get()) * 8;
+ if (!updated_description->GetTagValue(TAG_KEY_SIZE, key_size))
+ updated_description->push_back(TAG_KEY_SIZE, *key_size);
+ if (RSA_size(rsa_key.get()) * 8 != *key_size) {
+ LOG_E("Imported key size (%u bits) does not match specified key size (%u bits)",
+ RSA_size(rsa_key.get()) * 8, *key_size);
+ return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
+ }
+
+ 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;
+
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t RsaKeyFactory::CreateEmptyKey(const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ UniquePtr<AsymmetricKey>* key) const {
+ keymaster_error_t error;
+ key->reset(new (std::nothrow) RsaKey(hw_enforced, sw_enforced, &error));
+ if (!key->get())
+ error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return error;
+}
+
+} // namespace keymaster
diff --git a/keymaster/rsa_keymaster0_key.cpp b/keymaster/rsa_keymaster0_key.cpp
new file mode 100644
index 0000000..6e5c083
--- /dev/null
+++ b/keymaster/rsa_keymaster0_key.cpp
@@ -0,0 +1,128 @@
+/*
+ * 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 "rsa_keymaster0_key.h"
+
+#include <memory>
+
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/logger.h>
+#include <keymaster/soft_keymaster_context.h>
+
+#include "keymaster0_engine.h"
+#include "openssl_utils.h"
+
+using std::unique_ptr;
+
+namespace keymaster {
+
+RsaKeymaster0KeyFactory::RsaKeymaster0KeyFactory(const SoftKeymasterContext* context,
+ const Keymaster0Engine* engine)
+ : RsaKeyFactory(context), 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
+ // context_->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 context_->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
+ // context_->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 context_->CreateKeyBlob(authorizations, KM_ORIGIN_UNKNOWN, imported_hw_key,
+ output_key_blob, hw_enforced, sw_enforced);
+}
+
+keymaster_error_t RsaKeymaster0KeyFactory::LoadKey(const KeymasterKeyBlob& key_material,
+ const AuthorizationSet& additional_params,
+ const AuthorizationSet& hw_enforced,
+ const 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(key_material, additional_params, hw_enforced, sw_enforced, key);
+
+ unique_ptr<RSA, RSA_Delete> rsa(engine_->BlobToRsaKey(key_material));
+ if (!rsa)
+ return KM_ERROR_UNKNOWN_ERROR;
+
+ keymaster_error_t error;
+ key->reset(new (std::nothrow)
+ RsaKeymaster0Key(rsa.release(), hw_enforced, sw_enforced, &error));
+ if (!key->get())
+ error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ if (error != KM_ERROR_OK)
+ return error;
+
+ return KM_ERROR_OK;
+}
+
+} // namespace keymaster
diff --git a/keymaster/rsa_keymaster0_key.h b/keymaster/rsa_keymaster0_key.h
new file mode 100644
index 0000000..261448f
--- /dev/null
+++ b/keymaster/rsa_keymaster0_key.h
@@ -0,0 +1,70 @@
+/*
+ * 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/rsa_key_factory.h>
+
+#include "rsa_key.h"
+
+namespace keymaster {
+
+class Keymaster0Engine;
+class SoftKeymasterContext;
+
+/**
+ * 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 SoftKeymasterContext* context, 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(const KeymasterKeyBlob& key_material,
+ const AuthorizationSet& additional_params,
+ const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ UniquePtr<Key>* key) const override;
+
+ private:
+ const Keymaster0Engine* engine_;
+};
+
+class RsaKeymaster0Key : public RsaKey {
+ public:
+ RsaKeymaster0Key(RSA* rsa_key, const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced, keymaster_error_t* error)
+ : RsaKey(rsa_key, hw_enforced, sw_enforced, error) {}
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_RSA_KEYMASTER0_KEY_H_
diff --git a/keymaster/rsa_keymaster1_key.cpp b/keymaster/rsa_keymaster1_key.cpp
new file mode 100644
index 0000000..7d8a33f
--- /dev/null
+++ b/keymaster/rsa_keymaster1_key.cpp
@@ -0,0 +1,144 @@
+/*
+ * 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 "rsa_keymaster1_key.h"
+
+#include <memory>
+
+#include <keymaster/logger.h>
+#include <keymaster/soft_keymaster_context.h>
+
+#include "rsa_keymaster1_operation.h"
+
+using std::unique_ptr;
+
+namespace keymaster {
+
+RsaKeymaster1KeyFactory::RsaKeymaster1KeyFactory(const SoftKeymasterContext* context,
+ const Keymaster1Engine* engine)
+ : RsaKeyFactory(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.
+ verify_factory_(new RsaVerificationOperationFactory),
+ encrypt_factory_(new RsaEncryptionOperationFactory) {}
+
+static bool is_supported(uint32_t digest) {
+ return digest == KM_DIGEST_NONE || digest == KM_DIGEST_SHA_2_256;
+}
+
+static void UpdateToWorkAroundUnsupportedDigests(const AuthorizationSet& key_description,
+ AuthorizationSet* new_description) {
+ bool have_unsupported_digests = false;
+ bool have_digest_none = false;
+ bool have_pad_none = false;
+ bool have_padding_requiring_digest = false;
+ for (const keymaster_key_param_t& entry : key_description) {
+ new_description->push_back(entry);
+
+ if (entry.tag == TAG_DIGEST) {
+ if (entry.enumerated == KM_DIGEST_NONE) {
+ have_digest_none = true;
+ } else if (!is_supported(entry.enumerated)) {
+ LOG_D("Found request for unsupported digest %u", entry.enumerated);
+ have_unsupported_digests = true;
+ }
+ }
+
+ if (entry.tag == TAG_PADDING) {
+ switch (entry.enumerated) {
+ case KM_PAD_RSA_PSS:
+ case KM_PAD_RSA_OAEP:
+ have_padding_requiring_digest = true;
+ break;
+ case KM_PAD_NONE:
+ have_pad_none = true;
+ break;
+ }
+ }
+ }
+
+ if (have_unsupported_digests && !have_digest_none) {
+ LOG_I("Adding KM_DIGEST_NONE to key authorization, to enable software digesting", 0);
+ new_description->push_back(TAG_DIGEST, KM_DIGEST_NONE);
+ }
+
+ if (have_unsupported_digests && have_padding_requiring_digest && !have_pad_none) {
+ LOG_I("Adding KM_PAD_NONE to key authorization, to enable PSS or OAEP software padding", 0);
+ new_description->push_back(TAG_PADDING, KM_PAD_NONE);
+ }
+}
+
+keymaster_error_t RsaKeymaster1KeyFactory::GenerateKey(const AuthorizationSet& key_description,
+ KeymasterKeyBlob* key_blob,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) 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 {
+ AuthorizationSet key_params_copy;
+ UpdateToWorkAroundUnsupportedDigests(key_description, &key_params_copy);
+ return engine_->ImportKey(key_params_copy, input_key_material_format, input_key_material,
+ output_key_blob, hw_enforced, sw_enforced);
+}
+
+keymaster_error_t RsaKeymaster1KeyFactory::LoadKey(const KeymasterKeyBlob& key_material,
+ const AuthorizationSet& additional_params,
+ const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ UniquePtr<Key>* key) const {
+ if (!key)
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+ keymaster_error_t error;
+ unique_ptr<RSA, RSA_Delete> rsa(engine_->BuildRsaKey(key_material, additional_params, &error));
+ if (!rsa)
+ return error;
+
+ key->reset(new (std::nothrow)
+ RsaKeymaster1Key(rsa.release(), hw_enforced, sw_enforced, &error));
+ if (!key->get())
+ error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ if (error != KM_ERROR_OK)
+ return error;
+
+ return KM_ERROR_OK;
+}
+
+OperationFactory* RsaKeymaster1KeyFactory::GetOperationFactory(keymaster_purpose_t purpose) const {
+ switch (purpose) {
+ case KM_PURPOSE_SIGN:
+ return sign_factory_.get();
+ case KM_PURPOSE_VERIFY:
+ return verify_factory_.get();
+ case KM_PURPOSE_ENCRYPT:
+ return encrypt_factory_.get();
+ case KM_PURPOSE_DECRYPT:
+ return decrypt_factory_.get();
+ case KM_PURPOSE_DERIVE_KEY:
+ break;
+ }
+ return nullptr;
+}
+
+} // namespace keymaster
diff --git a/keymaster/rsa_keymaster1_key.h b/keymaster/rsa_keymaster1_key.h
new file mode 100644
index 0000000..dd543dd
--- /dev/null
+++ b/keymaster/rsa_keymaster1_key.h
@@ -0,0 +1,81 @@
+/*
+ * 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_KEYMASTER1_KEY_H_
+#define SYSTEM_KEYMASTER_RSA_KEYMASTER1_KEY_H_
+
+#include <openssl/rsa.h>
+
+#include <keymaster/rsa_key_factory.h>
+
+#include "keymaster1_engine.h"
+#include "rsa_key.h"
+
+namespace keymaster {
+
+class SoftKeymasterContext;
+
+/**
+ * RsaKeymaster1KeyFactory is a KeyFactory that creates and loads keys which are actually backed by
+ * a hardware keymaster1 module, but which does not support all keymaster1 digests. If unsupported
+ * digests are found during generation or import, KM_DIGEST_NONE is added to the key description,
+ * then the operations handle the unsupported digests in software.
+ *
+ * If unsupported digests are requested and KM_PAD_RSA_PSS or KM_PAD_RSA_OAEP is also requested, but
+ * KM_PAD_NONE is not present KM_PAD_NONE will be added to the description, to allow for
+ * software padding as well as software digesting.
+ */
+class RsaKeymaster1KeyFactory : public RsaKeyFactory {
+ public:
+ RsaKeymaster1KeyFactory(const SoftKeymasterContext* context, const Keymaster1Engine* 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(const KeymasterKeyBlob& key_material,
+ const AuthorizationSet& additional_params,
+ const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ UniquePtr<Key>* key) const override;
+
+ OperationFactory* GetOperationFactory(keymaster_purpose_t purpose) const override;
+
+ private:
+ const Keymaster1Engine* engine_;
+
+ std::unique_ptr<OperationFactory> sign_factory_;
+ std::unique_ptr<OperationFactory> decrypt_factory_;
+ std::unique_ptr<OperationFactory> verify_factory_;
+ std::unique_ptr<OperationFactory> encrypt_factory_;
+};
+
+class RsaKeymaster1Key : public RsaKey {
+ public:
+ RsaKeymaster1Key(RSA* rsa_key, const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced, keymaster_error_t* error)
+ : RsaKey(rsa_key, hw_enforced, sw_enforced, error) {}
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_RSA_KEYMASTER1_KEY_H_
diff --git a/keymaster/rsa_keymaster1_operation.cpp b/keymaster/rsa_keymaster1_operation.cpp
new file mode 100644
index 0000000..002930e
--- /dev/null
+++ b/keymaster/rsa_keymaster1_operation.cpp
@@ -0,0 +1,180 @@
+/*
+ * 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 "rsa_keymaster1_operation.h"
+
+#include <memory>
+
+#include <keymaster/android_keymaster_utils.h>
+
+#include "openssl_err.h"
+#include "openssl_utils.h"
+#include "rsa_keymaster1_key.h"
+
+using std::unique_ptr;
+
+namespace keymaster {
+
+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;
+
+ // 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
+ // to the hardware module. The regular Rsa*Operation classes will do software digesting and
+ // padding where we've told the HW not to.
+ //
+ // The reason we don't change KM_PAD_RSA_PKCS1_1_5_SIGN or KM_PAD_RSA_PKCS1_1_5_ENCRYPT to
+ // KM_PAD_NONE is because the hardware can perform those padding modes, since they don't involve
+ // digesting.
+ //
+ // We also cache in the key the padding value that we expect to be passed to the engine crypto
+ // operation. This just allows us to double-check that the correct padding value is reaching
+ // that layer.
+ AuthorizationSet begin_params(input_params);
+ int pos = begin_params.find(TAG_DIGEST);
+ if (pos == -1)
+ return KM_ERROR_UNSUPPORTED_DIGEST;
+ begin_params[pos].enumerated = KM_DIGEST_NONE;
+
+ pos = begin_params.find(TAG_PADDING);
+ if (pos == -1)
+ return KM_ERROR_UNSUPPORTED_PADDING_MODE;
+ switch (begin_params[pos].enumerated) {
+
+ case KM_PAD_RSA_PSS:
+ case KM_PAD_RSA_OAEP:
+ key_data->expected_openssl_padding = RSA_NO_PADDING;
+ begin_params[pos].enumerated = KM_PAD_NONE;
+ break;
+
+ case KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
+ case KM_PAD_RSA_PKCS1_1_5_SIGN:
+ key_data->expected_openssl_padding = RSA_PKCS1_PADDING;
+ break;
+ }
+
+ return engine_->device()->begin(engine_->device(), purpose_, &key_data->key_material,
+ &begin_params, nullptr /* out_params */, &operation_handle_);
+}
+
+keymaster_error_t
+RsaKeymaster1WrappedOperation::PrepareFinish(EVP_PKEY* rsa_key,
+ const AuthorizationSet& input_params) {
+ Keymaster1Engine::KeyData* key_data = engine_->GetData(rsa_key);
+ if (!key_data) {
+ LOG_E("Could not get extended key data... not a Keymaster1Engine key?", 0);
+ return KM_ERROR_UNKNOWN_ERROR;
+ }
+ key_data->op_handle = operation_handle_;
+ key_data->finish_params.Reinitialize(input_params);
+
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t RsaKeymaster1WrappedOperation::Abort() {
+ return engine_->device()->abort(engine_->device(), operation_handle_);
+}
+
+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;
+ return key_data->error;
+}
+
+static EVP_PKEY* GetEvpKey(const RsaKeymaster1Key& key, keymaster_error_t* error) {
+ if (!key.key()) {
+ *error = KM_ERROR_UNKNOWN_ERROR;
+ return nullptr;
+ }
+
+ UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new());
+ if (!key.InternalToEvp(pkey.get())) {
+ *error = KM_ERROR_UNKNOWN_ERROR;
+ return nullptr;
+ }
+ return pkey.release();
+}
+
+Operation* RsaKeymaster1OperationFactory::CreateOperation(const Key& key,
+ const AuthorizationSet& begin_params,
+ keymaster_error_t* error) {
+ keymaster_digest_t digest;
+ if (!GetAndValidateDigest(begin_params, key, &digest, error))
+ return nullptr;
+
+ keymaster_padding_t padding;
+ if (!GetAndValidatePadding(begin_params, key, &padding, error))
+ return nullptr;
+
+ const RsaKeymaster1Key& rsa_km1_key(static_cast<const RsaKeymaster1Key&>(key));
+ unique_ptr<EVP_PKEY, EVP_PKEY_Delete> rsa(GetEvpKey(rsa_km1_key, error));
+ if (!rsa)
+ return nullptr;
+
+ switch (purpose_) {
+ case KM_PURPOSE_SIGN:
+ return new RsaKeymaster1Operation<RsaSignOperation>(digest, padding, rsa.release(),
+ engine_);
+ case KM_PURPOSE_DECRYPT:
+ return new RsaKeymaster1Operation<RsaDecryptOperation>(digest, padding, rsa.release(),
+ engine_);
+ default:
+ LOG_E("Bug: Pubkey operation requested. Those should be handled by normal RSA operations.",
+ 0);
+ *error = KM_ERROR_UNSUPPORTED_PURPOSE;
+ return nullptr;
+ }
+}
+
+static const keymaster_digest_t supported_digests[] = {
+ KM_DIGEST_NONE, KM_DIGEST_MD5, KM_DIGEST_SHA1, KM_DIGEST_SHA_2_224,
+ KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512};
+
+const keymaster_digest_t*
+RsaKeymaster1OperationFactory::SupportedDigests(size_t* digest_count) const {
+ *digest_count = array_length(supported_digests);
+ return supported_digests;
+}
+
+static const keymaster_padding_t supported_sig_padding[] = {
+ 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,
+};
+
+const keymaster_padding_t*
+RsaKeymaster1OperationFactory::SupportedPaddingModes(size_t* padding_mode_count) const {
+ switch (purpose_) {
+ case KM_PURPOSE_SIGN:
+ case KM_PURPOSE_VERIFY:
+ *padding_mode_count = array_length(supported_sig_padding);
+ return supported_sig_padding;
+ case KM_PURPOSE_ENCRYPT:
+ case KM_PURPOSE_DECRYPT:
+ *padding_mode_count = array_length(supported_crypt_padding);
+ return supported_crypt_padding;
+ default:
+ *padding_mode_count = 0;
+ return nullptr;
+ }
+}
+
+} // namespace keymaster
diff --git a/keymaster/rsa_keymaster1_operation.h b/keymaster/rsa_keymaster1_operation.h
new file mode 100644
index 0000000..30123f0
--- /dev/null
+++ b/keymaster/rsa_keymaster1_operation.h
@@ -0,0 +1,120 @@
+/*
+ * 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_KEYMASTER1_OPERATION_H_
+#define SYSTEM_KEYMASTER_RSA_KEYMASTER1_OPERATION_H_
+
+#include <openssl/evp.h>
+
+#include <hardware/keymaster1.h>
+#include <keymaster/android_keymaster_utils.h>
+
+#include "keymaster1_engine.h"
+#include "rsa_operation.h"
+
+namespace keymaster {
+
+class RsaKeymaster1WrappedOperation {
+ public:
+ RsaKeymaster1WrappedOperation(keymaster_purpose_t purpose, const Keymaster1Engine* engine)
+ : purpose_(purpose), operation_handle_(0), engine_(engine) {}
+ ~RsaKeymaster1WrappedOperation() {
+ if (operation_handle_)
+ Abort();
+ }
+
+ keymaster_error_t Begin(EVP_PKEY* rsa_key, const AuthorizationSet& input_params);
+ keymaster_error_t PrepareFinish(EVP_PKEY* rsa_key, const AuthorizationSet& input_params);
+ void Finish() { operation_handle_ = 0; }
+ keymaster_error_t Abort();
+
+ keymaster_error_t GetError(EVP_PKEY* rsa_key);
+
+ protected:
+ keymaster_purpose_t purpose_;
+ keymaster_operation_handle_t operation_handle_;
+ const Keymaster1Engine* engine_;
+};
+
+template <typename BaseOperation> class RsaKeymaster1Operation : public BaseOperation {
+ typedef BaseOperation super;
+
+ public:
+ RsaKeymaster1Operation(keymaster_digest_t digest, keymaster_padding_t padding, EVP_PKEY* key,
+ const Keymaster1Engine* engine)
+ : BaseOperation(digest, padding, key), wrapped_operation_(super::purpose(), engine) {
+ // Shouldn't be instantiated for public key operations.
+ assert(super::purpose() != KM_PURPOSE_VERIFY);
+ assert(super::purpose() != KM_PURPOSE_ENCRYPT);
+ }
+
+ 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;
+ return super::Begin(input_params, output_params);
+ }
+
+ keymaster_error_t Finish(const AuthorizationSet& input_params, const Buffer& input,
+ 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;
+ 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_);
+ if (error == KM_ERROR_OK)
+ wrapped_operation_.Finish();
+ return error;
+ }
+
+ keymaster_error_t Abort() override {
+ keymaster_error_t error = wrapped_operation_.Abort();
+ if (error != KM_ERROR_OK)
+ return error;
+ return super::Abort();
+ }
+
+ private:
+ RsaKeymaster1WrappedOperation wrapped_operation_;
+};
+
+/**
+ * Factory that produces RsaKeymaster1Operations. This is instantiated and
+ * provided by RsaKeymaster1KeyFactory.
+ */
+class RsaKeymaster1OperationFactory : public OperationFactory {
+ public:
+ RsaKeymaster1OperationFactory(keymaster_purpose_t purpose, const Keymaster1Engine* engine)
+ : purpose_(purpose), engine_(engine) {}
+ KeyType registry_key() const override { return KeyType(KM_ALGORITHM_RSA, purpose_); }
+
+ Operation* CreateOperation(const Key& key, const AuthorizationSet& begin_params,
+ keymaster_error_t* error) override;
+
+ const keymaster_digest_t* SupportedDigests(size_t* digest_count) const override;
+ const keymaster_padding_t* SupportedPaddingModes(size_t* padding_mode_count) const override;
+
+ private:
+ keymaster_purpose_t purpose_;
+ const Keymaster1Engine* engine_;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_RSA_KEYMASTER1_OPERATION_H_
diff --git a/keymaster/rsa_operation.cpp b/keymaster/rsa_operation.cpp
new file mode 100644
index 0000000..2046a64
--- /dev/null
+++ b/keymaster/rsa_operation.cpp
@@ -0,0 +1,619 @@
+/*
+ * Copyright 2014 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 "rsa_operation.h"
+
+#include <limits.h>
+
+#include <new>
+
+#include <openssl/err.h>
+
+#include <keymaster/logger.h>
+
+#include "openssl_err.h"
+#include "openssl_utils.h"
+#include "rsa_key.h"
+
+namespace keymaster {
+
+const size_t kPssOverhead = 2;
+const size_t kMinPssSaltSize = 20;
+
+// Overhead for PKCS#1 v1.5 signature padding of undigested messages. Digested messages have
+// additional overhead, for the digest algorithmIdentifier required by PKCS#1.
+const size_t kPkcs1UndigestedSignaturePaddingOverhead = 11;
+
+/* static */
+EVP_PKEY* RsaOperationFactory::GetRsaKey(const Key& key, keymaster_error_t* error) {
+ const RsaKey* rsa_key = static_cast<const RsaKey*>(&key);
+ assert(rsa_key);
+ if (!rsa_key || !rsa_key->key()) {
+ *error = KM_ERROR_UNKNOWN_ERROR;
+ return nullptr;
+ }
+
+ UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new());
+ if (!rsa_key->InternalToEvp(pkey.get())) {
+ *error = KM_ERROR_UNKNOWN_ERROR;
+ return nullptr;
+ }
+ return pkey.release();
+}
+
+static const keymaster_digest_t supported_digests[] = {
+ KM_DIGEST_NONE, KM_DIGEST_MD5, KM_DIGEST_SHA1, KM_DIGEST_SHA_2_224,
+ KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512};
+
+const keymaster_digest_t* RsaOperationFactory::SupportedDigests(size_t* digest_count) const {
+ *digest_count = array_length(supported_digests);
+ return supported_digests;
+}
+
+RsaOperation* RsaOperationFactory::CreateRsaOperation(const Key& key,
+ const AuthorizationSet& begin_params,
+ keymaster_error_t* error) {
+ keymaster_padding_t padding;
+ if (!GetAndValidatePadding(begin_params, key, &padding, error))
+ return nullptr;
+
+ bool require_digest = (purpose() == KM_PURPOSE_SIGN || purpose() == KM_PURPOSE_VERIFY ||
+ padding == KM_PAD_RSA_OAEP);
+
+ keymaster_digest_t digest = KM_DIGEST_NONE;
+ if (require_digest && !GetAndValidateDigest(begin_params, key, &digest, error))
+ return nullptr;
+
+ UniquePtr<EVP_PKEY, EVP_PKEY_Delete> rsa(GetRsaKey(key, error));
+ if (!rsa.get())
+ return nullptr;
+
+ RsaOperation* op = InstantiateOperation(digest, padding, rsa.release());
+ if (!op)
+ *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return op;
+}
+
+static const keymaster_padding_t supported_sig_padding[] = {KM_PAD_NONE, KM_PAD_RSA_PKCS1_1_5_SIGN,
+ KM_PAD_RSA_PSS};
+const keymaster_padding_t*
+RsaDigestingOperationFactory::SupportedPaddingModes(size_t* padding_mode_count) const {
+ *padding_mode_count = array_length(supported_sig_padding);
+ return supported_sig_padding;
+}
+
+RsaOperation* RsaCryptingOperationFactory::CreateRsaOperation(const Key& key,
+ const AuthorizationSet& begin_params,
+ keymaster_error_t* error) {
+ UniquePtr<RsaOperation> op(RsaOperationFactory::CreateRsaOperation(key, begin_params, error));
+ if (op.get()) {
+ switch (op->padding()) {
+ case KM_PAD_NONE:
+ case KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
+ if (op->digest() != KM_DIGEST_NONE) {
+ *error = KM_ERROR_INCOMPATIBLE_DIGEST;
+ return nullptr;
+ }
+ break;
+
+ case KM_PAD_RSA_OAEP:
+ if (op->digest() == KM_DIGEST_NONE) {
+ *error = KM_ERROR_INCOMPATIBLE_DIGEST;
+ return nullptr;
+ }
+ break;
+
+ default:
+ *error = KM_ERROR_UNSUPPORTED_PADDING_MODE;
+ return nullptr;
+ }
+ }
+ return op.release();
+}
+
+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*
+RsaCryptingOperationFactory::SupportedPaddingModes(size_t* padding_mode_count) const {
+ *padding_mode_count = array_length(supported_crypt_padding);
+ return supported_crypt_padding;
+}
+
+RsaOperation::~RsaOperation() {
+ if (rsa_key_ != NULL)
+ EVP_PKEY_free(rsa_key_);
+}
+
+keymaster_error_t RsaOperation::Begin(const AuthorizationSet& /* input_params */,
+ AuthorizationSet* /* output_params */) {
+ return InitDigest();
+}
+
+keymaster_error_t RsaOperation::Update(const AuthorizationSet& /* additional_params */,
+ const Buffer& input, AuthorizationSet* /* output_params */,
+ Buffer* /* output */, size_t* input_consumed) {
+ assert(input_consumed);
+ switch (purpose()) {
+ default:
+ return KM_ERROR_UNIMPLEMENTED;
+ case KM_PURPOSE_SIGN:
+ case KM_PURPOSE_VERIFY:
+ case KM_PURPOSE_ENCRYPT:
+ case KM_PURPOSE_DECRYPT:
+ return StoreData(input, input_consumed);
+ }
+}
+
+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 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",
+ input.available_read() + data_.available_read(), EVP_PKEY_size(rsa_key_));
+ return KM_ERROR_INVALID_INPUT_LENGTH;
+ }
+
+ *input_consumed = input.available_read();
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t RsaOperation::SetRsaPaddingInEvpContext(EVP_PKEY_CTX* pkey_ctx) {
+ keymaster_error_t error;
+ int openssl_padding = GetOpensslPadding(&error);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, openssl_padding) <= 0)
+ return TranslateLastOpenSslError();
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t RsaOperation::InitDigest() {
+ if (digest_ == KM_DIGEST_NONE) {
+ 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:
+ return KM_ERROR_UNSUPPORTED_DIGEST;
+ }
+}
+
+RsaDigestingOperation::RsaDigestingOperation(keymaster_purpose_t purpose, keymaster_digest_t digest,
+ keymaster_padding_t padding, EVP_PKEY* key)
+ : RsaOperation(purpose, digest, padding, key) {
+ EVP_MD_CTX_init(&digest_ctx_);
+}
+RsaDigestingOperation::~RsaDigestingOperation() {
+ EVP_MD_CTX_cleanup(&digest_ctx_);
+}
+
+int RsaDigestingOperation::GetOpensslPadding(keymaster_error_t* error) {
+ *error = KM_ERROR_OK;
+ switch (padding_) {
+ case KM_PAD_NONE:
+ return RSA_NO_PADDING;
+ case KM_PAD_RSA_PKCS1_1_5_SIGN:
+ return RSA_PKCS1_PADDING;
+ case KM_PAD_RSA_PSS:
+ if (digest_ == KM_DIGEST_NONE) {
+ *error = KM_ERROR_INCOMPATIBLE_PADDING_MODE;
+ return -1;
+ }
+ if (EVP_MD_size(digest_algorithm_) + kPssOverhead + kMinPssSaltSize >
+ (size_t)EVP_PKEY_size(rsa_key_)) {
+ LOG_E("Input too long: %d-byte digest cannot be used with %d-byte RSA key in PSS "
+ "padding mode",
+ EVP_MD_size(digest_algorithm_), EVP_PKEY_size(rsa_key_));
+ *error = KM_ERROR_INCOMPATIBLE_DIGEST;
+ return -1;
+ }
+ return RSA_PKCS1_PSS_PADDING;
+ default:
+ return -1;
+ }
+}
+
+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 (digest_ == KM_DIGEST_NONE)
+ return KM_ERROR_OK;
+
+ EVP_PKEY_CTX* pkey_ctx;
+ if (EVP_DigestSignInit(&digest_ctx_, &pkey_ctx, digest_algorithm_, nullptr /* engine */,
+ rsa_key_) != 1)
+ return TranslateLastOpenSslError();
+ return SetRsaPaddingInEvpContext(pkey_ctx);
+}
+
+keymaster_error_t RsaSignOperation::Update(const AuthorizationSet& additional_params,
+ const Buffer& input, AuthorizationSet* output_params,
+ Buffer* output, size_t* input_consumed) {
+ if (digest_ == KM_DIGEST_NONE)
+ // Just buffer the data.
+ return RsaOperation::Update(additional_params, input, output_params, output,
+ input_consumed);
+
+ if (EVP_DigestSignUpdate(&digest_ctx_, input.peek_read(), input.available_read()) != 1)
+ return TranslateLastOpenSslError();
+ *input_consumed = input.available_read();
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t RsaSignOperation::Finish(const AuthorizationSet& additional_params,
+ const Buffer& input, const Buffer& /* signature */,
+ AuthorizationSet* /* output_params */, Buffer* output) {
+ assert(output);
+
+ keymaster_error_t error = UpdateForFinish(additional_params, input);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ if (digest_ == KM_DIGEST_NONE)
+ return SignUndigested(output);
+ else
+ return SignDigested(output);
+}
+
+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 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;
+
+ 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 (!output->Reinitialize(RSA_size(rsa.get())))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ size_t key_len = EVP_PKEY_size(rsa_key_);
+ int bytes_encrypted;
+ switch (padding_) {
+ case KM_PAD_NONE: {
+ const uint8_t* to_encrypt = data_.peek_read();
+ UniquePtr<uint8_t[]> zero_padded;
+ if (data_.available_read() > key_len) {
+ 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;
+ to_encrypt = zero_padded.get();
+ }
+ bytes_encrypted = RSA_private_encrypt(key_len, to_encrypt, output->peek_write(), rsa.get(),
+ RSA_NO_PADDING);
+ break;
+ }
+ case KM_PAD_RSA_PKCS1_1_5_SIGN:
+ // Does PKCS1 padding without digesting even make sense? Dunno. We'll support it.
+ if (data_.available_read() + kPkcs1UndigestedSignaturePaddingOverhead > key_len) {
+ LOG_E("Input too long: cannot sign %u-byte message with PKCS1 padding with %u-bit key",
+ data_.available_read(), EVP_PKEY_size(rsa_key_) * 8);
+ return KM_ERROR_INVALID_INPUT_LENGTH;
+ }
+ bytes_encrypted = RSA_private_encrypt(data_.available_read(), data_.peek_read(),
+ output->peek_write(), rsa.get(), RSA_PKCS1_PADDING);
+ break;
+
+ default:
+ return KM_ERROR_UNSUPPORTED_PADDING_MODE;
+ }
+
+ if (bytes_encrypted <= 0)
+ return TranslateLastOpenSslError();
+ if (!output->advance_write(bytes_encrypted))
+ return KM_ERROR_UNKNOWN_ERROR;
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t RsaSignOperation::SignDigested(Buffer* output) {
+ size_t siglen;
+ if (EVP_DigestSignFinal(&digest_ctx_, nullptr /* signature */, &siglen) != 1)
+ return TranslateLastOpenSslError();
+
+ 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;
+
+ return KM_ERROR_OK;
+}
+
+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 (digest_ == KM_DIGEST_NONE)
+ return KM_ERROR_OK;
+
+ EVP_PKEY_CTX* pkey_ctx;
+ if (EVP_DigestVerifyInit(&digest_ctx_, &pkey_ctx, digest_algorithm_, NULL, rsa_key_) != 1)
+ return TranslateLastOpenSslError();
+ return SetRsaPaddingInEvpContext(pkey_ctx);
+}
+
+keymaster_error_t RsaVerifyOperation::Update(const AuthorizationSet& additional_params,
+ const Buffer& input, AuthorizationSet* output_params,
+ Buffer* output, size_t* input_consumed) {
+ if (digest_ == KM_DIGEST_NONE)
+ // Just buffer the data.
+ return RsaOperation::Update(additional_params, input, output_params, output,
+ input_consumed);
+
+ if (EVP_DigestVerifyUpdate(&digest_ctx_, input.peek_read(), input.available_read()) != 1)
+ return TranslateLastOpenSslError();
+ *input_consumed = input.available_read();
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t RsaVerifyOperation::Finish(const AuthorizationSet& additional_params,
+ const Buffer& input, const Buffer& signature,
+ AuthorizationSet* /* output_params */,
+ Buffer* /* output */) {
+ keymaster_error_t error = UpdateForFinish(additional_params, input);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ if (digest_ == KM_DIGEST_NONE)
+ return VerifyUndigested(signature);
+ else
+ return VerifyDigested(signature);
+}
+
+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;
+
+ 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;
+ openssl_padding = RSA_NO_PADDING;
+ break;
+ case KM_PAD_RSA_PKCS1_1_5_SIGN:
+ if (data_.available_read() + kPkcs1UndigestedSignaturePaddingOverhead > key_len) {
+ LOG_E("Input too long: cannot verify %u-byte message with PKCS1 padding && %u-bit key",
+ data_.available_read(), key_len * 8);
+ return KM_ERROR_INVALID_INPUT_LENGTH;
+ }
+ openssl_padding = RSA_PKCS1_PADDING;
+ break;
+ default:
+ return KM_ERROR_UNSUPPORTED_PADDING_MODE;
+ }
+
+ UniquePtr<uint8_t[]> decrypted_data(new (std::nothrow) uint8_t[key_len]);
+ 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;
+
+ const uint8_t* compare_pos = decrypted_data.get();
+ size_t bytes_to_compare = bytes_decrypted;
+ uint8_t zero_check_result = 0;
+ if (padding_ == KM_PAD_NONE && data_.available_read() < bytes_to_compare) {
+ // If the data is short, for "unpadded" signing we zero-pad to the left. So during
+ // verification we should have zeros on the left of the decrypted data. Do a constant-time
+ // check.
+ const uint8_t* zero_end = compare_pos + bytes_to_compare - data_.available_read();
+ while (compare_pos < zero_end)
+ zero_check_result |= *compare_pos++;
+ bytes_to_compare = data_.available_read();
+ }
+ if (memcmp_s(compare_pos, data_.peek_read(), bytes_to_compare) != 0 || zero_check_result != 0)
+ return KM_ERROR_VERIFICATION_FAILED;
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t RsaVerifyOperation::VerifyDigested(const Buffer& signature) {
+ if (!EVP_DigestVerifyFinal(&digest_ctx_, signature.peek_read(), signature.available_read()))
+ return KM_ERROR_VERIFICATION_FAILED;
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t RsaCryptOperation::SetOaepDigestIfRequired(EVP_PKEY_CTX* pkey_ctx) {
+ 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_))
+ return TranslateLastOpenSslError();
+
+ // MGF1 MD is always SHA1.
+ if (!EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, EVP_sha1()))
+ return TranslateLastOpenSslError();
+
+ return KM_ERROR_OK;
+}
+
+int RsaCryptOperation::GetOpensslPadding(keymaster_error_t* error) {
+ *error = KM_ERROR_OK;
+ switch (padding_) {
+ case KM_PAD_NONE:
+ return RSA_NO_PADDING;
+ case KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
+ return RSA_PKCS1_PADDING;
+ case KM_PAD_RSA_OAEP:
+ return RSA_PKCS1_OAEP_PADDING;
+ default:
+ return -1;
+ }
+}
+
+struct EVP_PKEY_CTX_Delete {
+ void operator()(EVP_PKEY_CTX* p) { EVP_PKEY_CTX_free(p); }
+};
+
+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;
+
+ keymaster_error_t error = UpdateForFinish(additional_params, input);
+ 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;
+
+ if (EVP_PKEY_encrypt_init(ctx.get()) <= 0)
+ return TranslateLastOpenSslError();
+
+ error = SetRsaPaddingInEvpContext(ctx.get());
+ if (error != KM_ERROR_OK)
+ return error;
+ error = SetOaepDigestIfRequired(ctx.get());
+ 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;
+
+ 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;
+ 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;
+
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t RsaDecryptOperation::Finish(const AuthorizationSet& additional_params,
+ const Buffer& input, const Buffer& /* signature */,
+ AuthorizationSet* /* output_params */,
+ Buffer* output) {
+ if (!output)
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+ keymaster_error_t error = UpdateForFinish(additional_params, input);
+ 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;
+
+ if (EVP_PKEY_decrypt_init(ctx.get()) <= 0)
+ return TranslateLastOpenSslError();
+
+ error = SetRsaPaddingInEvpContext(ctx.get());
+ if (error != KM_ERROR_OK)
+ return error;
+ error = SetOaepDigestIfRequired(ctx.get());
+ 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;
+
+ 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;
+ 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;
+
+ return KM_ERROR_OK;
+}
+
+} // namespace keymaster
diff --git a/keymaster/rsa_operation.h b/keymaster/rsa_operation.h
new file mode 100644
index 0000000..8283f2e
--- /dev/null
+++ b/keymaster/rsa_operation.h
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2014 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_OPERATION_H_
+#define SYSTEM_KEYMASTER_RSA_OPERATION_H_
+
+#include <UniquePtr.h>
+
+#include <openssl/evp.h>
+#include <openssl/rsa.h>
+
+#include "operation.h"
+
+namespace keymaster {
+
+/**
+ * Base class for all RSA operations.
+ *
+ * This class provides RSA key management, plus buffering of data for non-digesting modes.
+ */
+class RsaOperation : public Operation {
+ public:
+ RsaOperation(keymaster_purpose_t purpose, keymaster_digest_t digest,
+ keymaster_padding_t padding, EVP_PKEY* key)
+ : Operation(purpose), rsa_key_(key), padding_(padding), digest_(digest),
+ digest_algorithm_(nullptr) {}
+ ~RsaOperation();
+
+ 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 Abort() override { return KM_ERROR_OK; }
+
+ keymaster_padding_t padding() const { return padding_; }
+ keymaster_digest_t digest() const { return digest_; }
+
+ protected:
+ virtual int GetOpensslPadding(keymaster_error_t* error) = 0;
+ virtual bool require_digest() const = 0;
+
+ keymaster_error_t StoreData(const Buffer& input, size_t* input_consumed);
+ keymaster_error_t SetRsaPaddingInEvpContext(EVP_PKEY_CTX* pkey_ctx);
+ keymaster_error_t InitDigest();
+
+ EVP_PKEY* rsa_key_;
+ const keymaster_padding_t padding_;
+ Buffer data_;
+ const keymaster_digest_t digest_;
+ const EVP_MD* digest_algorithm_;
+};
+
+/**
+ * Base class for all digesting RSA operations.
+ *
+ * This class adds digesting support, for digesting modes. For non-digesting modes, it falls back
+ * on the RsaOperation input buffering.
+ */
+class RsaDigestingOperation : public RsaOperation {
+ public:
+ RsaDigestingOperation(keymaster_purpose_t purpose, keymaster_digest_t digest,
+ keymaster_padding_t padding, EVP_PKEY* key);
+ ~RsaDigestingOperation();
+
+ protected:
+ int GetOpensslPadding(keymaster_error_t* error) override;
+ bool require_digest() const override { return padding_ == KM_PAD_RSA_PSS; }
+ EVP_MD_CTX digest_ctx_;
+};
+
+/**
+ * RSA private key signing operation.
+ */
+class RsaSignOperation : public RsaDigestingOperation {
+ public:
+ RsaSignOperation(keymaster_digest_t digest, keymaster_padding_t padding, EVP_PKEY* key)
+ : RsaDigestingOperation(KM_PURPOSE_SIGN, digest, padding, key) {}
+
+ 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;
+
+ private:
+ keymaster_error_t SignUndigested(Buffer* output);
+ keymaster_error_t SignDigested(Buffer* output);
+};
+
+/**
+ * RSA public key verification operation.
+ */
+class RsaVerifyOperation : public RsaDigestingOperation {
+ public:
+ RsaVerifyOperation(keymaster_digest_t digest, keymaster_padding_t padding, EVP_PKEY* key)
+ : RsaDigestingOperation(KM_PURPOSE_VERIFY, digest, padding, key) {}
+
+ 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;
+
+ private:
+ keymaster_error_t VerifyUndigested(const Buffer& signature);
+ keymaster_error_t VerifyDigested(const Buffer& signature);
+};
+
+/**
+ * Base class for RSA crypting operations.
+ */
+class RsaCryptOperation : public RsaOperation {
+ public:
+ RsaCryptOperation(keymaster_purpose_t purpose, keymaster_digest_t digest,
+ keymaster_padding_t padding, EVP_PKEY* key)
+ : RsaOperation(purpose, digest, padding, key) {}
+
+ protected:
+ keymaster_error_t SetOaepDigestIfRequired(EVP_PKEY_CTX* pkey_ctx);
+
+ private:
+ int GetOpensslPadding(keymaster_error_t* error) override;
+ bool require_digest() const override { return padding_ == KM_PAD_RSA_OAEP; }
+};
+
+/**
+ * RSA public key encryption operation.
+ */
+class RsaEncryptOperation : public RsaCryptOperation {
+ public:
+ RsaEncryptOperation(keymaster_digest_t digest, keymaster_padding_t padding, EVP_PKEY* key)
+ : RsaCryptOperation(KM_PURPOSE_ENCRYPT, digest, padding, key) {}
+ keymaster_error_t Finish(const AuthorizationSet& additional_params, const Buffer& input,
+ const Buffer& signature, AuthorizationSet* output_params,
+ Buffer* output) override;
+};
+
+/**
+ * RSA private key decryption operation.
+ */
+class RsaDecryptOperation : public RsaCryptOperation {
+ public:
+ RsaDecryptOperation(keymaster_digest_t digest, keymaster_padding_t padding, EVP_PKEY* key)
+ : RsaCryptOperation(KM_PURPOSE_DECRYPT, digest, padding, key) {}
+ keymaster_error_t Finish(const AuthorizationSet& additional_params, const Buffer& input,
+ const Buffer& signature, AuthorizationSet* output_params,
+ Buffer* output) override;
+};
+
+/**
+ * Abstract base for all RSA operation factories. This class exists mainly to centralize some code
+ * common to all RSA operation factories.
+ */
+class RsaOperationFactory : public OperationFactory {
+ public:
+ KeyType registry_key() const override { return KeyType(KM_ALGORITHM_RSA, purpose()); }
+ virtual keymaster_purpose_t purpose() const = 0;
+
+ Operation* CreateOperation(const Key& key, const AuthorizationSet& begin_params,
+ keymaster_error_t* error) override {
+ return CreateRsaOperation(key, begin_params, error);
+ }
+ const keymaster_digest_t* SupportedDigests(size_t* digest_count) const override;
+
+ protected:
+ static EVP_PKEY* GetRsaKey(const Key& key, keymaster_error_t* error);
+ virtual RsaOperation* CreateRsaOperation(const Key& key, const AuthorizationSet& begin_params,
+ keymaster_error_t* error);
+
+ private:
+ virtual RsaOperation* InstantiateOperation(keymaster_digest_t digest,
+ keymaster_padding_t padding, EVP_PKEY* key) = 0;
+};
+
+/**
+ * Abstract base for RSA operations that digest their input (signing and verification).
+ */
+class RsaDigestingOperationFactory : public RsaOperationFactory {
+ public:
+ const keymaster_padding_t* SupportedPaddingModes(size_t* padding_mode_count) const override;
+};
+
+/**
+ * Abstract base for en/de-crypting RSA operation factories. This class does most of the work of
+ * creating such operations, delegating only the actual operation instantiation.
+ */
+class RsaCryptingOperationFactory : public RsaOperationFactory {
+ public:
+ RsaOperation* CreateRsaOperation(const Key& key, const AuthorizationSet& begin_params,
+ keymaster_error_t* error) override;
+ const keymaster_padding_t* SupportedPaddingModes(size_t* padding_mode_count) const override;
+};
+
+/**
+ * Concrete factory for RSA signing operations.
+ */
+class RsaSigningOperationFactory : public RsaDigestingOperationFactory {
+ public:
+ keymaster_purpose_t purpose() const override { return KM_PURPOSE_SIGN; }
+ RsaOperation* InstantiateOperation(keymaster_digest_t digest, keymaster_padding_t padding,
+ EVP_PKEY* key) override {
+ return new (std::nothrow) RsaSignOperation(digest, padding, key);
+ }
+};
+
+/**
+ * Concrete factory for RSA signing operations.
+ */
+class RsaVerificationOperationFactory : public RsaDigestingOperationFactory {
+ keymaster_purpose_t purpose() const override { return KM_PURPOSE_VERIFY; }
+ RsaOperation* InstantiateOperation(keymaster_digest_t digest, keymaster_padding_t padding,
+ EVP_PKEY* key) override {
+ return new (std::nothrow) RsaVerifyOperation(digest, padding, key);
+ }
+};
+
+/**
+ * Concrete factory for RSA signing operations.
+ */
+class RsaEncryptionOperationFactory : public RsaCryptingOperationFactory {
+ keymaster_purpose_t purpose() const override { return KM_PURPOSE_ENCRYPT; }
+ RsaOperation* InstantiateOperation(keymaster_digest_t digest, keymaster_padding_t padding,
+ EVP_PKEY* key) override {
+ return new (std::nothrow) RsaEncryptOperation(digest, padding, key);
+ }
+};
+
+/**
+ * Concrete factory for RSA signing operations.
+ */
+class RsaDecryptionOperationFactory : public RsaCryptingOperationFactory {
+ keymaster_purpose_t purpose() const override { return KM_PURPOSE_DECRYPT; }
+ RsaOperation* InstantiateOperation(keymaster_digest_t digest, keymaster_padding_t padding,
+ EVP_PKEY* key) override {
+ return new (std::nothrow) RsaDecryptOperation(digest, padding, key);
+ }
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_RSA_OPERATION_H_
diff --git a/keymaster/rsa_privkey_pk8.der b/keymaster/rsa_privkey_pk8.der
new file mode 100644
index 0000000..0336f80
--- /dev/null
+++ b/keymaster/rsa_privkey_pk8.der
Binary files differ
diff --git a/keymaster/serializable.cpp b/keymaster/serializable.cpp
new file mode 100644
index 0000000..5db64f8
--- /dev/null
+++ b/keymaster/serializable.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2014 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/serializable.h>
+
+#include <assert.h>
+
+#include <new>
+
+#include <keymaster/android_keymaster_utils.h>
+
+namespace keymaster {
+
+uint8_t* append_to_buf(uint8_t* buf, const uint8_t* end, const void* data, size_t data_len) {
+ if (buf + data_len < buf) // Pointer wrap check
+ return buf;
+
+ if (buf + data_len <= end) {
+ memcpy(buf, data, data_len);
+ return buf + data_len;
+ }
+ return buf;
+}
+
+bool copy_from_buf(const uint8_t** buf_ptr, const uint8_t* end, void* dest, size_t size) {
+ if (*buf_ptr + size < *buf_ptr) // Pointer wrap check
+ return false;
+
+ if (end < *buf_ptr + size)
+ return false;
+ memcpy(dest, *buf_ptr, size);
+ *buf_ptr += size;
+ return true;
+}
+
+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 (*buf_ptr + *size < *buf_ptr) // Pointer wrap check
+ return false;
+
+ if (*buf_ptr + *size > end)
+ return false;
+
+ if (*size == 0) {
+ dest->reset();
+ return true;
+ }
+ dest->reset(new (std::nothrow) uint8_t[*size]);
+ if (!dest->get())
+ return false;
+ return copy_from_buf(buf_ptr, end, dest->get(), *size);
+}
+
+bool Buffer::reserve(size_t size) {
+ 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;
+ memcpy(new_buffer, buffer_.get() + read_position_, available_read());
+ memset_s(buffer_.get(), 0, buffer_size_);
+ buffer_.reset(new_buffer);
+ buffer_size_ = new_size;
+ write_position_ -= read_position_;
+ read_position_ = 0;
+ }
+ return true;
+}
+
+bool Buffer::Reinitialize(size_t size) {
+ Clear();
+ buffer_.reset(new (std::nothrow) uint8_t[size]);
+ if (!buffer_.get())
+ return false;
+ buffer_size_ = size;
+ read_position_ = 0;
+ write_position_ = 0;
+ return true;
+}
+
+bool Buffer::Reinitialize(const void* data, size_t data_len) {
+ Clear();
+ if (static_cast<const uint8_t*>(data) + data_len < data) // Pointer wrap check
+ return false;
+ buffer_.reset(new (std::nothrow) uint8_t[data_len]);
+ if (!buffer_.get())
+ return false;
+ buffer_size_ = data_len;
+ memcpy(buffer_.get(), data, data_len);
+ read_position_ = 0;
+ write_position_ = buffer_size_;
+ return true;
+}
+
+size_t Buffer::available_write() const {
+ assert(buffer_size_ >= write_position_);
+ return buffer_size_ - write_position_;
+}
+
+size_t Buffer::available_read() const {
+ assert(buffer_size_ >= write_position_);
+ assert(write_position_ >= read_position_);
+ return write_position_ - read_position_;
+}
+
+bool Buffer::write(const uint8_t* src, size_t write_length) {
+ 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;
+ memcpy(dest, buffer_.get() + read_position_, read_length);
+ read_position_ += read_length;
+ return true;
+}
+
+size_t Buffer::SerializedSize() const {
+ return sizeof(uint32_t) + available_read();
+}
+
+uint8_t* Buffer::Serialize(uint8_t* buf, const uint8_t* end) const {
+ return append_size_and_data_to_buf(buf, end, peek_read(), available_read());
+}
+
+bool Buffer::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+ Clear();
+ if (!copy_size_and_data_from_buf(buf_ptr, end, &buffer_size_, &buffer_)) {
+ buffer_.reset();
+ buffer_size_ = 0;
+ return false;
+ }
+ write_position_ = buffer_size_;
+ return true;
+}
+
+void Buffer::Clear() {
+ memset_s(buffer_.get(), 0, buffer_size_);
+ buffer_.reset();
+ read_position_ = 0;
+ write_position_ = 0;
+ buffer_size_ = 0;
+}
+
+} // namespace keymaster
diff --git a/keymaster/soft_keymaster_context.cpp b/keymaster/soft_keymaster_context.cpp
new file mode 100644
index 0000000..a143245
--- /dev/null
+++ b/keymaster/soft_keymaster_context.cpp
@@ -0,0 +1,883 @@
+/*
+ * 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/soft_keymaster_context.h>
+
+#include <memory>
+#include <time.h>
+
+#include <openssl/aes.h>
+#include <openssl/rand.h>
+#include <openssl/sha.h>
+
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/logger.h>
+
+#include "aes_key.h"
+#include "auth_encrypted_key_blob.h"
+#include "ec_keymaster0_key.h"
+#include "ec_keymaster1_key.h"
+#include "hmac_key.h"
+#include "integrity_assured_key_blob.h"
+#include "keymaster0_engine.h"
+#include "ocb_utils.h"
+#include "openssl_err.h"
+#include "rsa_keymaster0_key.h"
+#include "rsa_keymaster1_key.h"
+
+using std::unique_ptr;
+
+namespace keymaster {
+
+namespace {
+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));
+
+static uint8_t kRsaAttestKey[] = {
+ 0x30, 0x82, 0x02, 0x5d, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xc0, 0x83, 0x23, 0xdc, 0x56,
+ 0x88, 0x1b, 0xb8, 0x30, 0x20, 0x69, 0xf5, 0xb0, 0x85, 0x61, 0xc6, 0xee, 0xbe, 0x7f, 0x05, 0xe2,
+ 0xf5, 0xa8, 0x42, 0x04, 0x8a, 0xbe, 0x8b, 0x47, 0xbe, 0x76, 0xfe, 0xae, 0xf2, 0x5c, 0xf2, 0x9b,
+ 0x2a, 0xfa, 0x32, 0x00, 0x14, 0x16, 0x01, 0x42, 0x99, 0x89, 0xa1, 0x5f, 0xcf, 0xc6, 0x81, 0x5e,
+ 0xb3, 0x63, 0x58, 0x3c, 0x2f, 0xd2, 0xf2, 0x0b, 0xe4, 0x98, 0x32, 0x83, 0xdd, 0x81, 0x4b, 0x16,
+ 0xd7, 0xe1, 0x85, 0x41, 0x7a, 0xe5, 0x4a, 0xbc, 0x29, 0x6a, 0x3a, 0x6d, 0xb5, 0xc0, 0x04, 0x08,
+ 0x3b, 0x68, 0xc5, 0x56, 0xc1, 0xf0, 0x23, 0x39, 0x91, 0x64, 0x19, 0x86, 0x4d, 0x50, 0xb7, 0x4d,
+ 0x40, 0xae, 0xca, 0x48, 0x4c, 0x77, 0x35, 0x6c, 0x89, 0x5a, 0x0c, 0x27, 0x5a, 0xbf, 0xac, 0x49,
+ 0x9d, 0x5d, 0x7d, 0x23, 0x62, 0xf2, 0x9c, 0x5e, 0x02, 0xe8, 0x71, 0x02, 0x03, 0x01, 0x00, 0x01,
+ 0x02, 0x81, 0x81, 0x00, 0xbe, 0x86, 0x0b, 0x0b, 0x99, 0xa8, 0x02, 0xa6, 0xfb, 0x1a, 0x59, 0x43,
+ 0x8a, 0x7b, 0xb7, 0x15, 0x06, 0x5b, 0x09, 0xa3, 0x6d, 0xc6, 0xe9, 0xca, 0xcc, 0x6b, 0xf3, 0xc0,
+ 0x2c, 0x34, 0xd7, 0xd7, 0x9e, 0x94, 0xc6, 0x60, 0x64, 0x28, 0xd8, 0x8c, 0x7b, 0x7f, 0x65, 0x77,
+ 0xc1, 0xcd, 0xea, 0x64, 0x07, 0x4a, 0xbe, 0x8e, 0x72, 0x86, 0xdf, 0x1f, 0x08, 0x11, 0xdc, 0x97,
+ 0x28, 0x26, 0x08, 0x68, 0xde, 0x95, 0xd3, 0x2e, 0xfc, 0x96, 0xb6, 0xd0, 0x84, 0xff, 0x27, 0x1a,
+ 0x5f, 0x60, 0xde, 0xfc, 0xc7, 0x03, 0xe7, 0xa3, 0x8e, 0x6e, 0x29, 0xba, 0x9a, 0x3c, 0x5f, 0xc2,
+ 0xc2, 0x80, 0x76, 0xb6, 0xa8, 0x96, 0xaf, 0x1d, 0x34, 0xd7, 0x88, 0x28, 0xce, 0x9b, 0xdd, 0xb1,
+ 0xf3, 0x4f, 0x9c, 0x94, 0x04, 0x43, 0x07, 0x81, 0x29, 0x8e, 0x20, 0x13, 0x16, 0x72, 0x5b, 0xbd,
+ 0xbc, 0x99, 0x3a, 0x41, 0x02, 0x41, 0x00, 0xe1, 0xc6, 0xd9, 0x27, 0x64, 0x6c, 0x09, 0x16, 0xec,
+ 0x36, 0x82, 0x6d, 0x59, 0x49, 0x83, 0x74, 0x0c, 0x21, 0xf1, 0xb0, 0x74, 0xc4, 0xa1, 0xa5, 0x98,
+ 0x67, 0xc6, 0x69, 0x79, 0x5c, 0x85, 0xd3, 0xdc, 0x46, 0x4c, 0x5b, 0x92, 0x9e, 0x94, 0xbf, 0xb3,
+ 0x4e, 0x0d, 0xcc, 0x50, 0x14, 0xb1, 0x0f, 0x13, 0x34, 0x1a, 0xb7, 0xfd, 0xd5, 0xf6, 0x04, 0x14,
+ 0xd2, 0xa3, 0x26, 0xca, 0xd4, 0x1c, 0xc5, 0x02, 0x41, 0x00, 0xda, 0x48, 0x59, 0x97, 0x78, 0x5c,
+ 0xd5, 0x63, 0x0f, 0xb0, 0xfd, 0x8c, 0x52, 0x54, 0xf9, 0x8e, 0x53, 0x8e, 0x18, 0x98, 0x3a, 0xae,
+ 0x9e, 0x6b, 0x7e, 0x6a, 0x5a, 0x7b, 0x5d, 0x34, 0x37, 0x55, 0xb9, 0x21, 0x8e, 0xbd, 0x40, 0x32,
+ 0x0d, 0x28, 0x38, 0x7d, 0x78, 0x9f, 0x76, 0xfa, 0x21, 0x8b, 0xcc, 0x2d, 0x8b, 0x68, 0xa5, 0xf6,
+ 0x41, 0x8f, 0xbb, 0xec, 0xa5, 0x17, 0x9a, 0xb3, 0xaf, 0xbd, 0x02, 0x40, 0x50, 0xfe, 0xfc, 0x32,
+ 0x64, 0x95, 0x59, 0x61, 0x6e, 0xd6, 0x53, 0x4e, 0x15, 0x45, 0x09, 0x32, 0x9d, 0x93, 0xa3, 0xd8,
+ 0x10, 0xdb, 0xe5, 0xbd, 0xb9, 0x82, 0x29, 0x2c, 0xf7, 0x8b, 0xd8, 0xba, 0xdb, 0x80, 0x20, 0xae,
+ 0x8d, 0x57, 0xf4, 0xb7, 0x1d, 0x05, 0x38, 0x6f, 0xfe, 0x9e, 0x9d, 0xb2, 0x71, 0xca, 0x34, 0x77,
+ 0xa3, 0x49, 0x99, 0xdb, 0x76, 0xf8, 0xe5, 0xec, 0xe9, 0xc0, 0xd4, 0x9d, 0x02, 0x40, 0x15, 0xb7,
+ 0x4c, 0xf2, 0x7c, 0xce, 0xff, 0x8b, 0xb3, 0x6b, 0xf0, 0x4d, 0x9d, 0x83, 0x46, 0xb0, 0x9a, 0x2f,
+ 0x70, 0xd2, 0xf4, 0x43, 0x9b, 0x0f, 0x26, 0xac, 0x7e, 0x03, 0xf7, 0xe9, 0xd1, 0xf7, 0x7d, 0x4b,
+ 0x91, 0x5f, 0xd2, 0x9b, 0x28, 0x23, 0xf0, 0x3a, 0xcb, 0x5d, 0x52, 0x00, 0xe0, 0x85, 0x7f, 0xf2,
+ 0xa8, 0x03, 0xe9, 0x3e, 0xee, 0x96, 0xd6, 0x23, 0x5c, 0xe9, 0x54, 0x42, 0xbc, 0x21, 0x02, 0x41,
+ 0x00, 0x90, 0xa7, 0x45, 0xda, 0x89, 0x70, 0xb2, 0xcd, 0x64, 0x96, 0x60, 0x32, 0x42, 0x28, 0xc5,
+ 0xf8, 0x28, 0x56, 0xff, 0xd6, 0x65, 0xba, 0x9a, 0x85, 0xc8, 0xd6, 0x0f, 0x1b, 0x8b, 0xee, 0x71,
+ 0x7e, 0xcd, 0x2c, 0x72, 0xea, 0xe0, 0x1d, 0xad, 0x86, 0xba, 0x76, 0x54, 0xd4, 0xcf, 0x45, 0xad,
+ 0xb5, 0xf1, 0xf2, 0xb3, 0x1d, 0x9f, 0x81, 0x22, 0xcf, 0xa5, 0xf1, 0xa5, 0x57, 0x0f, 0x9b, 0x2d,
+ 0x25,
+};
+
+static uint8_t kRsaAttestCert[] = {
+ 0x30, 0x82, 0x02, 0xb6, 0x30, 0x82, 0x02, 0x1f, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x10,
+ 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
+ 0x30, 0x63, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+ 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f,
+ 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d,
+ 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x56, 0x69, 0x65, 0x77, 0x31, 0x15, 0x30, 0x13,
+ 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0c, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2c, 0x20, 0x49,
+ 0x6e, 0x63, 0x2e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x07, 0x41, 0x6e,
+ 0x64, 0x72, 0x6f, 0x69, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x31, 0x30, 0x34, 0x31,
+ 0x32, 0x34, 0x30, 0x35, 0x33, 0x5a, 0x17, 0x0d, 0x33, 0x35, 0x31, 0x32, 0x33, 0x30, 0x31, 0x32,
+ 0x34, 0x30, 0x35, 0x33, 0x5a, 0x30, 0x76, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+ 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x43,
+ 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55,
+ 0x04, 0x0a, 0x0c, 0x0c, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e,
+ 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x07, 0x41, 0x6e, 0x64, 0x72, 0x6f,
+ 0x69, 0x64, 0x31, 0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x20, 0x41, 0x6e, 0x64,
+ 0x72, 0x6f, 0x69, 0x64, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x41, 0x74,
+ 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x4b, 0x65, 0x79, 0x30, 0x81, 0x9f,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
+ 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xc0, 0x83, 0x23, 0xdc, 0x56, 0x88,
+ 0x1b, 0xb8, 0x30, 0x20, 0x69, 0xf5, 0xb0, 0x85, 0x61, 0xc6, 0xee, 0xbe, 0x7f, 0x05, 0xe2, 0xf5,
+ 0xa8, 0x42, 0x04, 0x8a, 0xbe, 0x8b, 0x47, 0xbe, 0x76, 0xfe, 0xae, 0xf2, 0x5c, 0xf2, 0x9b, 0x2a,
+ 0xfa, 0x32, 0x00, 0x14, 0x16, 0x01, 0x42, 0x99, 0x89, 0xa1, 0x5f, 0xcf, 0xc6, 0x81, 0x5e, 0xb3,
+ 0x63, 0x58, 0x3c, 0x2f, 0xd2, 0xf2, 0x0b, 0xe4, 0x98, 0x32, 0x83, 0xdd, 0x81, 0x4b, 0x16, 0xd7,
+ 0xe1, 0x85, 0x41, 0x7a, 0xe5, 0x4a, 0xbc, 0x29, 0x6a, 0x3a, 0x6d, 0xb5, 0xc0, 0x04, 0x08, 0x3b,
+ 0x68, 0xc5, 0x56, 0xc1, 0xf0, 0x23, 0x39, 0x91, 0x64, 0x19, 0x86, 0x4d, 0x50, 0xb7, 0x4d, 0x40,
+ 0xae, 0xca, 0x48, 0x4c, 0x77, 0x35, 0x6c, 0x89, 0x5a, 0x0c, 0x27, 0x5a, 0xbf, 0xac, 0x49, 0x9d,
+ 0x5d, 0x7d, 0x23, 0x62, 0xf2, 0x9c, 0x5e, 0x02, 0xe8, 0x71, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3,
+ 0x66, 0x30, 0x64, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xd4, 0x0c,
+ 0x10, 0x1b, 0xf8, 0xcd, 0x63, 0xb9, 0xf7, 0x39, 0x52, 0xb5, 0x0e, 0x13, 0x5c, 0xa6, 0xd7, 0x99,
+ 0x93, 0x86, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x29,
+ 0xfa, 0xf1, 0xac, 0xcc, 0x4d, 0xd2, 0x4c, 0x96, 0x40, 0x27, 0x75, 0xb6, 0xb0, 0xe9, 0x32, 0xe5,
+ 0x07, 0xfe, 0x2e, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
+ 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01,
+ 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x84, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x9e, 0x2d, 0x48, 0x5f, 0x8c, 0x67,
+ 0x33, 0xdc, 0x1a, 0x85, 0xad, 0x99, 0xd7, 0x50, 0x23, 0xea, 0x14, 0xec, 0x43, 0xb0, 0xe1, 0x9d,
+ 0xea, 0xc2, 0x23, 0x46, 0x1e, 0x72, 0xb5, 0x19, 0xdc, 0x60, 0x22, 0xe4, 0xa5, 0x68, 0x31, 0x6c,
+ 0x0b, 0x55, 0xc4, 0xe6, 0x9c, 0xa2, 0x2d, 0x9f, 0x3a, 0x4f, 0x93, 0x6b, 0x31, 0x8b, 0x16, 0x78,
+ 0x16, 0x0d, 0x88, 0xcb, 0xd9, 0x8b, 0xcc, 0x80, 0x9d, 0x84, 0xf0, 0xc2, 0x27, 0xe3, 0x6b, 0x38,
+ 0xf1, 0xfd, 0xd1, 0xe7, 0x17, 0x72, 0x31, 0x59, 0x35, 0x7d, 0x96, 0xf3, 0xc5, 0x7f, 0xab, 0x9d,
+ 0x8f, 0x96, 0x61, 0x26, 0x4f, 0xb2, 0xbe, 0x81, 0xbb, 0x0d, 0x49, 0x04, 0x22, 0x8a, 0xce, 0x9f,
+ 0xf7, 0xf5, 0x42, 0x2e, 0x25, 0x44, 0xfa, 0x21, 0x07, 0x12, 0x5a, 0x83, 0xb5, 0x55, 0xad, 0x18,
+ 0x82, 0xf8, 0x40, 0x14, 0x9b, 0x9c, 0x20, 0x63, 0x04, 0x7f,
+};
+
+static uint8_t kRsaAttestRootCert[] = {
+ 0x30, 0x82, 0x02, 0xa7, 0x30, 0x82, 0x02, 0x10, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00,
+ 0xff, 0x94, 0xd9, 0xdd, 0x9f, 0x07, 0xc8, 0x0c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x63, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+ 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c,
+ 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, 0x06,
+ 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x56,
+ 0x69, 0x65, 0x77, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0c, 0x47, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03,
+ 0x55, 0x04, 0x0b, 0x0c, 0x07, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x30, 0x1e, 0x17, 0x0d,
+ 0x31, 0x36, 0x30, 0x31, 0x30, 0x34, 0x31, 0x32, 0x33, 0x31, 0x30, 0x38, 0x5a, 0x17, 0x0d, 0x33,
+ 0x35, 0x31, 0x32, 0x33, 0x30, 0x31, 0x32, 0x33, 0x31, 0x30, 0x38, 0x5a, 0x30, 0x63, 0x31, 0x0b,
+ 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06,
+ 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61,
+ 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d, 0x6f, 0x75, 0x6e, 0x74,
+ 0x61, 0x69, 0x6e, 0x20, 0x56, 0x69, 0x65, 0x77, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04,
+ 0x0a, 0x0c, 0x0c, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31,
+ 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x07, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69,
+ 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xa2, 0x6b,
+ 0xad, 0xeb, 0x6e, 0x2e, 0x44, 0x61, 0xef, 0xd5, 0x0e, 0x82, 0xe6, 0xb7, 0x94, 0xd1, 0x75, 0x23,
+ 0x1f, 0x77, 0x9b, 0x63, 0x91, 0x63, 0xff, 0xf7, 0xaa, 0xff, 0x0b, 0x72, 0x47, 0x4e, 0xc0, 0x2c,
+ 0x43, 0xec, 0x33, 0x7c, 0xd7, 0xac, 0xed, 0x40, 0x3e, 0x8c, 0x28, 0xa0, 0x66, 0xd5, 0xf7, 0x87,
+ 0x0b, 0x33, 0x97, 0xde, 0x0e, 0xb8, 0x4e, 0x13, 0x40, 0xab, 0xaf, 0xa5, 0x27, 0xbf, 0x95, 0x69,
+ 0xa0, 0x31, 0xdb, 0x06, 0x52, 0x65, 0xf8, 0x44, 0x59, 0x57, 0x61, 0xf0, 0xbb, 0xf2, 0x17, 0x4b,
+ 0xb7, 0x41, 0x80, 0x64, 0xc0, 0x28, 0x0e, 0x8f, 0x52, 0x77, 0x8e, 0xdb, 0xd2, 0x47, 0xb6, 0x45,
+ 0xe9, 0x19, 0xc8, 0xe9, 0x8b, 0xc3, 0xdb, 0xc2, 0x91, 0x3f, 0xd7, 0xd7, 0x50, 0xc4, 0x1d, 0x35,
+ 0x66, 0xf9, 0x57, 0xe4, 0x97, 0x96, 0x0b, 0x09, 0xac, 0xce, 0x92, 0x35, 0x85, 0x9b, 0x02, 0x03,
+ 0x01, 0x00, 0x01, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
+ 0x04, 0x14, 0x29, 0xfa, 0xf1, 0xac, 0xcc, 0x4d, 0xd2, 0x4c, 0x96, 0x40, 0x27, 0x75, 0xb6, 0xb0,
+ 0xe9, 0x32, 0xe5, 0x07, 0xfe, 0x2e, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30,
+ 0x16, 0x80, 0x14, 0x29, 0xfa, 0xf1, 0xac, 0xcc, 0x4d, 0xd2, 0x4c, 0x96, 0x40, 0x27, 0x75, 0xb6,
+ 0xb0, 0xe9, 0x32, 0xe5, 0x07, 0xfe, 0x2e, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
+ 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01,
+ 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x84, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x4f, 0x72, 0xf3, 0x36, 0x59,
+ 0x8d, 0x0e, 0xc1, 0xb9, 0x74, 0x5b, 0x31, 0x59, 0xf6, 0xf0, 0x8d, 0x25, 0x49, 0x30, 0x9e, 0xa3,
+ 0x1c, 0x1c, 0x29, 0xd2, 0x45, 0x2d, 0x20, 0xb9, 0x4d, 0x5f, 0x64, 0xb4, 0xe8, 0x80, 0xc7, 0x78,
+ 0x7a, 0x9c, 0x39, 0xde, 0xa8, 0xb3, 0xf5, 0xbf, 0x2f, 0x70, 0x5f, 0x47, 0x10, 0x5c, 0xc5, 0xe6,
+ 0xeb, 0x4d, 0x06, 0x99, 0x61, 0xd2, 0xae, 0x9a, 0x07, 0xff, 0xf7, 0x7c, 0xb8, 0xab, 0xeb, 0x9c,
+ 0x0f, 0x24, 0x07, 0x5e, 0xb1, 0x7f, 0xba, 0x79, 0x71, 0xfd, 0x4d, 0x5b, 0x9e, 0xdf, 0x14, 0xa9,
+ 0xfe, 0xdf, 0xed, 0x7c, 0xc0, 0x88, 0x5d, 0xf8, 0xdd, 0x9b, 0x64, 0x32, 0x56, 0xd5, 0x35, 0x9a,
+ 0xe2, 0x13, 0xf9, 0x8f, 0xce, 0xc1, 0x7c, 0xdc, 0xef, 0xa4, 0xaa, 0xb2, 0x55, 0xc3, 0x83, 0xa9,
+ 0x2e, 0xfb, 0x5c, 0xf6, 0x62, 0xf5, 0x27, 0x52, 0x17, 0xbe, 0x63,
+};
+
+static uint8_t kEcAttestKey[] = {
+ 0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x21, 0xe0, 0x86, 0x43, 0x2a, 0x15, 0x19, 0x84, 0x59,
+ 0xcf, 0x36, 0x3a, 0x50, 0xfc, 0x14, 0xc9, 0xda, 0xad, 0xf9, 0x35, 0xf5, 0x27, 0xc2, 0xdf, 0xd7,
+ 0x1e, 0x4d, 0x6d, 0xbc, 0x42, 0xe5, 0x44, 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
+ 0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0xeb, 0x9e, 0x79, 0xf8, 0x42, 0x63, 0x59,
+ 0xac, 0xcb, 0x2a, 0x91, 0x4c, 0x89, 0x86, 0xcc, 0x70, 0xad, 0x90, 0x66, 0x93, 0x82, 0xa9, 0x73,
+ 0x26, 0x13, 0xfe, 0xac, 0xcb, 0xf8, 0x21, 0x27, 0x4c, 0x21, 0x74, 0x97, 0x4a, 0x2a, 0xfe, 0xa5,
+ 0xb9, 0x4d, 0x7f, 0x66, 0xd4, 0xe0, 0x65, 0x10, 0x66, 0x35, 0xbc, 0x53, 0xb7, 0xa0, 0xa3, 0xa6,
+ 0x71, 0x58, 0x3e, 0xdb, 0x3e, 0x11, 0xae, 0x10, 0x14,
+};
+
+static uint8_t kEcAttestCert[] = {
+ 0x30, 0x82, 0x02, 0x78, 0x30, 0x82, 0x02, 0x1e, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x10,
+ 0x01, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x81, 0x98,
+ 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30,
+ 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e,
+ 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d, 0x6f, 0x75,
+ 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x56, 0x69, 0x65, 0x77, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03,
+ 0x55, 0x04, 0x0a, 0x0c, 0x0c, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63,
+ 0x2e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x07, 0x41, 0x6e, 0x64, 0x72,
+ 0x6f, 0x69, 0x64, 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2a, 0x41, 0x6e,
+ 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x4b, 0x65, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x53,
+ 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x31,
+ 0x31, 0x31, 0x30, 0x30, 0x34, 0x36, 0x30, 0x39, 0x5a, 0x17, 0x0d, 0x32, 0x36, 0x30, 0x31, 0x30,
+ 0x38, 0x30, 0x30, 0x34, 0x36, 0x30, 0x39, 0x5a, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06,
+ 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
+ 0x08, 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x15, 0x30,
+ 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0c, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2c, 0x20,
+ 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x07, 0x41,
+ 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x31, 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
+ 0x32, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x4b, 0x65, 0x79, 0x73, 0x74, 0x6f, 0x72,
+ 0x65, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x41, 0x74, 0x74, 0x65, 0x73,
+ 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69,
+ 0x61, 0x74, 0x65, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,
+ 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xeb, 0x9e,
+ 0x79, 0xf8, 0x42, 0x63, 0x59, 0xac, 0xcb, 0x2a, 0x91, 0x4c, 0x89, 0x86, 0xcc, 0x70, 0xad, 0x90,
+ 0x66, 0x93, 0x82, 0xa9, 0x73, 0x26, 0x13, 0xfe, 0xac, 0xcb, 0xf8, 0x21, 0x27, 0x4c, 0x21, 0x74,
+ 0x97, 0x4a, 0x2a, 0xfe, 0xa5, 0xb9, 0x4d, 0x7f, 0x66, 0xd4, 0xe0, 0x65, 0x10, 0x66, 0x35, 0xbc,
+ 0x53, 0xb7, 0xa0, 0xa3, 0xa6, 0x71, 0x58, 0x3e, 0xdb, 0x3e, 0x11, 0xae, 0x10, 0x14, 0xa3, 0x66,
+ 0x30, 0x64, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x3f, 0xfc, 0xac,
+ 0xd6, 0x1a, 0xb1, 0x3a, 0x9e, 0x81, 0x20, 0xb8, 0xd5, 0x25, 0x1c, 0xc5, 0x65, 0xbb, 0x1e, 0x91,
+ 0xa9, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xc8, 0xad,
+ 0xe9, 0x77, 0x4c, 0x45, 0xc3, 0xa3, 0xcf, 0x0d, 0x16, 0x10, 0xe4, 0x79, 0x43, 0x3a, 0x21, 0x5a,
+ 0x30, 0xcf, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06,
+ 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
+ 0x04, 0x04, 0x03, 0x02, 0x02, 0x84, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04,
+ 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x20, 0x4b, 0x8a, 0x9b, 0x7b, 0xee, 0x82, 0xbc,
+ 0xc0, 0x33, 0x87, 0xae, 0x2f, 0xc0, 0x89, 0x98, 0xb4, 0xdd, 0xc3, 0x8d, 0xab, 0x27, 0x2a, 0x45,
+ 0x9f, 0x69, 0x0c, 0xc7, 0xc3, 0x92, 0xd4, 0x0f, 0x8e, 0x02, 0x21, 0x00, 0xee, 0xda, 0x01, 0x5d,
+ 0xb6, 0xf4, 0x32, 0xe9, 0xd4, 0x84, 0x3b, 0x62, 0x4c, 0x94, 0x04, 0xef, 0x3a, 0x7c, 0xcc, 0xbd,
+ 0x5e, 0xfb, 0x22, 0xbb, 0xe7, 0xfe, 0xb9, 0x77, 0x3f, 0x59, 0x3f, 0xfb,
+};
+
+static uint8_t kEcAttestRootCert[] = {
+ 0x30, 0x82, 0x02, 0x8b, 0x30, 0x82, 0x02, 0x32, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00,
+ 0xa2, 0x05, 0x9e, 0xd1, 0x0e, 0x43, 0x5b, 0x57, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce,
+ 0x3d, 0x04, 0x03, 0x02, 0x30, 0x81, 0x98, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+ 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x43,
+ 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55,
+ 0x04, 0x07, 0x0c, 0x0d, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x56, 0x69, 0x65,
+ 0x77, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0c, 0x47, 0x6f, 0x6f, 0x67,
+ 0x6c, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04,
+ 0x0b, 0x0c, 0x07, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x31, 0x33, 0x30, 0x31, 0x06, 0x03,
+ 0x55, 0x04, 0x03, 0x0c, 0x2a, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x4b, 0x65, 0x79,
+ 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x41,
+ 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30,
+ 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x31, 0x31, 0x31, 0x30, 0x30, 0x34, 0x33, 0x35, 0x30, 0x5a,
+ 0x17, 0x0d, 0x33, 0x36, 0x30, 0x31, 0x30, 0x36, 0x30, 0x30, 0x34, 0x33, 0x35, 0x30, 0x5a, 0x30,
+ 0x81, 0x98, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+ 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f,
+ 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d,
+ 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x56, 0x69, 0x65, 0x77, 0x31, 0x15, 0x30, 0x13,
+ 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0c, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2c, 0x20, 0x49,
+ 0x6e, 0x63, 0x2e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x07, 0x41, 0x6e,
+ 0x64, 0x72, 0x6f, 0x69, 0x64, 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2a,
+ 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x4b, 0x65, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65,
+ 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07,
+ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01,
+ 0x07, 0x03, 0x42, 0x00, 0x04, 0xee, 0x5d, 0x5e, 0xc7, 0xe1, 0xc0, 0xdb, 0x6d, 0x03, 0xa6, 0x7e,
+ 0xe6, 0xb6, 0x1b, 0xec, 0x4d, 0x6a, 0x5d, 0x6a, 0x68, 0x2e, 0x0f, 0xff, 0x7f, 0x49, 0x0e, 0x7d,
+ 0x77, 0x1f, 0x44, 0x22, 0x6d, 0xbd, 0xb1, 0xaf, 0xfa, 0x16, 0xcb, 0xc7, 0xad, 0xc5, 0x77, 0xd2,
+ 0x56, 0x9c, 0xaa, 0xb7, 0xb0, 0x2d, 0x54, 0x01, 0x5d, 0x3e, 0x43, 0x2b, 0x2a, 0x8e, 0xd7, 0x4e,
+ 0xec, 0x48, 0x75, 0x41, 0xa4, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
+ 0x04, 0x16, 0x04, 0x14, 0xc8, 0xad, 0xe9, 0x77, 0x4c, 0x45, 0xc3, 0xa3, 0xcf, 0x0d, 0x16, 0x10,
+ 0xe4, 0x79, 0x43, 0x3a, 0x21, 0x5a, 0x30, 0xcf, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
+ 0x18, 0x30, 0x16, 0x80, 0x14, 0xc8, 0xad, 0xe9, 0x77, 0x4c, 0x45, 0xc3, 0xa3, 0xcf, 0x0d, 0x16,
+ 0x10, 0xe4, 0x79, 0x43, 0x3a, 0x21, 0x5a, 0x30, 0xcf, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13,
+ 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d,
+ 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x84, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86,
+ 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x47, 0x00, 0x30, 0x44, 0x02, 0x20, 0x35, 0x21, 0xa3,
+ 0xef, 0x8b, 0x34, 0x46, 0x1e, 0x9c, 0xd5, 0x60, 0xf3, 0x1d, 0x58, 0x89, 0x20, 0x6a, 0xdc, 0xa3,
+ 0x65, 0x41, 0xf6, 0x0d, 0x9e, 0xce, 0x8a, 0x19, 0x8c, 0x66, 0x48, 0x60, 0x7b, 0x02, 0x20, 0x4d,
+ 0x0b, 0xf3, 0x51, 0xd9, 0x30, 0x7c, 0x7d, 0x5b, 0xda, 0x35, 0x34, 0x1d, 0xa8, 0x47, 0x1b, 0x63,
+ 0xa5, 0x85, 0x65, 0x3c, 0xad, 0x4f, 0x24, 0xa7, 0xe7, 0x4d, 0xaf, 0x41, 0x7d, 0xf1, 0xbf,
+};
+
+size_t kCertificateChainLength = 2;
+
+} // 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)), hmac_factory_(new HmacKeyFactory(this)),
+ km1_dev_(nullptr), root_of_trust_(root_of_trust) {}
+
+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;
+
+ 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()));
+
+ // All AES and HMAC operations should be passed directly to the keymaster1 device. Explicitly
+ // do not handle them, to provoke errors in case the higher layers fail to send them to the
+ // device.
+ aes_factory_.reset(nullptr);
+ hmac_factory_.reset(nullptr);
+
+ return KM_ERROR_OK;
+}
+
+KeyFactory* SoftKeymasterContext::GetKeyFactory(keymaster_algorithm_t algorithm) const {
+ switch (algorithm) {
+ case KM_ALGORITHM_RSA:
+ return rsa_factory_.get();
+ case KM_ALGORITHM_EC:
+ return ec_factory_.get();
+ case KM_ALGORITHM_AES:
+ return aes_factory_.get();
+ case KM_ALGORITHM_HMAC:
+ return hmac_factory_.get();
+ default:
+ return nullptr;
+ }
+}
+
+static keymaster_algorithm_t supported_algorithms[] = {KM_ALGORITHM_RSA, KM_ALGORITHM_EC,
+ KM_ALGORITHM_AES, KM_ALGORITHM_HMAC};
+
+keymaster_algorithm_t*
+SoftKeymasterContext::GetSupportedAlgorithms(size_t* algorithms_count) const {
+ *algorithms_count = array_length(supported_algorithms);
+ return supported_algorithms;
+}
+
+OperationFactory* SoftKeymasterContext::GetOperationFactory(keymaster_algorithm_t algorithm,
+ keymaster_purpose_t purpose) const {
+ KeyFactory* key_factory = GetKeyFactory(algorithm);
+ if (!key_factory)
+ return nullptr;
+ return key_factory->GetOperationFactory(purpose);
+}
+
+static keymaster_error_t TranslateAuthorizationSetError(AuthorizationSet::Error err) {
+ switch (err) {
+ case AuthorizationSet::OK:
+ return KM_ERROR_OK;
+ case AuthorizationSet::ALLOCATION_FAILURE:
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ case AuthorizationSet::MALFORMED_DATA:
+ return KM_ERROR_UNKNOWN_ERROR;
+ }
+ return KM_ERROR_OK;
+}
+
+static keymaster_error_t SetAuthorizations(const AuthorizationSet& key_description,
+ keymaster_key_origin_t origin,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) {
+ sw_enforced->Clear();
+
+ for (auto& entry : key_description) {
+ switch (entry.tag) {
+ // These cannot be specified by the client.
+ case KM_TAG_ROOT_OF_TRUST:
+ case KM_TAG_ORIGIN:
+ 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_ROLLBACK_RESISTANT:
+ LOG_E("KM_TAG_ROLLBACK_RESISTANT not supported", 0);
+ return KM_ERROR_UNSUPPORTED_TAG;
+
+ // These are hidden.
+ case KM_TAG_APPLICATION_ID:
+ case KM_TAG_APPLICATION_DATA:
+ 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);
+ break;
+ }
+ }
+
+ sw_enforced->push_back(TAG_CREATION_DATETIME, java_time(time(NULL)));
+ sw_enforced->push_back(TAG_ORIGIN, origin);
+ return TranslateAuthorizationSetError(sw_enforced->is_valid());
+}
+
+keymaster_error_t SoftKeymasterContext::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 = SetAuthorizations(key_description, origin, hw_enforced, sw_enforced);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ AuthorizationSet hidden;
+ error = BuildHiddenAuthorizations(key_description, &hidden);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ return SerializeIntegrityAssuredBlob(key_material, hidden, *hw_enforced, *sw_enforced, blob);
+}
+
+static 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;
+
+ 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);
+}
+
+// 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 SoftKeymasterContext::ParseOldSoftkeymasterBlob(
+ const KeymasterKeyBlob& blob, KeymasterKeyBlob* key_material, AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) const {
+ long publicLen = 0;
+ long privateLen = 0;
+ const uint8_t* p = blob.key_material;
+ const uint8_t* end = blob.key_material + blob.key_material_size;
+
+ int type = 0;
+ ptrdiff_t min_size =
+ sizeof(SOFT_KEY_MAGIC) + sizeof(type) + sizeof(publicLen) + 1 + sizeof(privateLen) + 1;
+ if (end - p < min_size) {
+ LOG_W("key blob appears to be truncated (if an old SW key)", 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++)
+ type = (type << 8) | *p++;
+
+ 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);
+ return KM_ERROR_INVALID_KEY_BLOB;
+ }
+ p += publicLen;
+
+ if (end - p < 2) {
+ LOG_W("key blob appears to be truncated (if an old SW key)", 0);
+ return KM_ERROR_INVALID_KEY_BLOB;
+ }
+
+ for (size_t i = 0; i < sizeof(type); i++)
+ privateLen = (privateLen << 8) | *p++;
+
+ if (p + privateLen > end) {
+ LOG_W("private key length encoding error: size=%ld, end=%td", privateLen, end - p);
+ return KM_ERROR_INVALID_KEY_BLOB;
+ }
+
+ // Just to be sure, make sure that the ASN.1 structure parses correctly. We don't actually use
+ // the EVP_PKEY here.
+ const uint8_t* key_start = p;
+ unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(d2i_PrivateKey(type, nullptr, &p, privateLen));
+ if (pkey.get() == nullptr) {
+ LOG_W("Failed to parse PKCS#8 key material (if old SW key)", 0);
+ return KM_ERROR_INVALID_KEY_BLOB;
+ }
+
+ // All auths go into sw_enforced, including those that would be HW-enforced if we were faking
+ // 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 (!key_material->Reset(privateLen))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ memcpy(key_material->writable_data(), key_start, privateLen);
+
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t SoftKeymasterContext::ParseKeyBlob(const KeymasterKeyBlob& blob,
+ const AuthorizationSet& additional_params,
+ KeymasterKeyBlob* key_material,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) const {
+ // This is a little bit complicated.
+ //
+ // The SoftKeymasterContext has to handle a lot of different kinds of key blobs.
+ //
+ // 1. New keymaster1 software key blobs. These are integrity-assured but not encrypted. The
+ // raw key material and auth sets should be extracted and returned. This is the kind
+ // produced by this context when the KeyFactory doesn't use keymaster0 to back the keys.
+ //
+ // 2. Old keymaster1 software key blobs. These are OCB-encrypted with an all-zero master key.
+ // They should be decrypted and the key material and auth sets extracted and returned.
+ //
+ // 3. Old keymaster0 software key blobs. These are raw key material with a small header tacked
+ // on the front. They don't have auth sets, so reasonable defaults are generated and
+ // returned along with the raw key material.
+ //
+ // 4. New keymaster0 hardware key blobs. These are integrity-assured but not encrypted (though
+ // they're protected by the keymaster0 hardware implementation). The keymaster0 key blob
+ // and auth sets should be extracted and returned.
+ //
+ // 5. Keymaster1 hardware key blobs. These are raw hardware key blobs. They contain auth
+ // sets, which we retrieve from the hardware module.
+ //
+ // 6. Old keymaster0 hardware key blobs. These are raw hardware key blobs. They don't have
+ // auth sets so reasonable defaults are generated and returned along with the key blob.
+ //
+ // Determining what kind of blob has arrived is somewhat tricky. What helps is that
+ // integrity-assured and OCB-encrypted blobs are self-consistent and effectively impossible to
+ // parse as anything else. Old keymaster0 software key blobs have a header. It's reasonably
+ // unlikely that hardware keys would have the same header. So anything that is neither
+ // integrity-assured nor OCB-encrypted and lacks the old software key header is assumed to be
+ // keymaster0 hardware.
+
+ AuthorizationSet hidden;
+ keymaster_error_t error = BuildHiddenAuthorizations(additional_params, &hidden);
+ 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 error;
+
+ // 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 error;
+
+ // 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 error;
+
+ if (km1_dev_)
+ return ParseKeymaster1HwBlob(blob, additional_params, key_material, hw_enforced,
+ sw_enforced);
+ else if (km0_engine_)
+ return ParseKeymaster0HwBlob(blob, key_material, hw_enforced, sw_enforced);
+
+ LOG_E("Failed to parse key; not a valid software blob, no hardware module configured", 0);
+ return KM_ERROR_INVALID_KEY_BLOB;
+}
+
+keymaster_error_t SoftKeymasterContext::DeleteKey(const KeymasterKeyBlob& blob) const {
+ if (km1_engine_) {
+ keymaster_error_t error = km1_engine_->DeleteKey(blob);
+ if (error == KM_ERROR_INVALID_KEY_BLOB) {
+ // Note that we succeed on invalid blob, because it probably just indicates that the
+ // blob is a software blob, not a hardware blob.
+ error = KM_ERROR_OK;
+ }
+ return error;
+ }
+
+ 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;
+
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t SoftKeymasterContext::AddRngEntropy(const uint8_t* buf, size_t length) const {
+ RAND_add(buf, length, 0 /* Don't assume any entropy is added to the pool. */);
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t SoftKeymasterContext::GenerateRandom(uint8_t* buf, size_t length) const {
+ if (RAND_bytes(buf, length) != 1)
+ return KM_ERROR_UNKNOWN_ERROR;
+ return KM_ERROR_OK;
+}
+
+EVP_PKEY* SoftKeymasterContext::AttestationKey(keymaster_algorithm_t algorithm,
+ keymaster_error_t* error) const {
+
+ const uint8_t* key;
+ size_t key_length;
+ int evp_key_type;
+
+ switch (algorithm) {
+ case KM_ALGORITHM_RSA:
+ key = kRsaAttestKey;
+ key_length = array_length(kRsaAttestKey);
+ evp_key_type = EVP_PKEY_RSA;
+ break;
+
+ case KM_ALGORITHM_EC:
+ key = kEcAttestKey;
+ key_length = array_length(kEcAttestKey);
+ evp_key_type = EVP_PKEY_EC;
+ break;
+
+ default:
+ *error = KM_ERROR_UNSUPPORTED_ALGORITHM;
+ return nullptr;
+ }
+
+ EVP_PKEY* pkey = d2i_PrivateKey(evp_key_type, nullptr /* pkey */, &key, key_length);
+ if (!pkey)
+ *error = TranslateLastOpenSslError();
+
+ return pkey;
+}
+
+keymaster_cert_chain_t* SoftKeymasterContext::AttestationChain(keymaster_algorithm_t algorithm,
+ keymaster_error_t* error) const {
+ // If we have to bail it will be because of an allocation failure.
+ *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ UniquePtr<keymaster_cert_chain_t, CertificateChainDelete> chain(new keymaster_cert_chain_t);
+ if (!chain.get())
+ return nullptr;
+ memset(chain.get(), 0, sizeof(keymaster_cert_chain_t));
+
+ chain->entries = new keymaster_blob_t[kCertificateChainLength];
+ if (!chain->entries)
+ return nullptr;
+
+ memset(chain->entries, 0, sizeof(chain->entries[0]) * kCertificateChainLength);
+ chain->entry_count = kCertificateChainLength;
+
+ size_t entry = 0;
+
+ switch (algorithm) {
+ case KM_ALGORITHM_RSA:
+ chain->entries[entry].data = dup_array(kRsaAttestCert);
+ if (!chain->entries[entry].data)
+ return nullptr;
+ chain->entries[entry].data_length = array_length(kRsaAttestCert);
+ entry++;
+ chain->entries[entry].data = dup_array(kRsaAttestRootCert);
+ if (!chain->entries[entry].data)
+ return nullptr;
+ chain->entries[entry].data_length = array_length(kRsaAttestRootCert);
+ entry++;
+ break;
+
+ case KM_ALGORITHM_EC:
+ chain->entries[entry].data = dup_array(kEcAttestCert);
+ if (!chain->entries[entry].data)
+ return nullptr;
+ chain->entries[entry].data_length = array_length(kEcAttestCert);
+ entry++;
+ chain->entries[entry].data = dup_array(kEcAttestRootCert);
+ if (!chain->entries[entry].data)
+ return nullptr;
+ chain->entries[entry].data_length = array_length(kEcAttestRootCert);
+ entry++;
+ break;
+
+ default:
+ *error = KM_ERROR_UNSUPPORTED_ALGORITHM;
+ return nullptr;
+ };
+
+ assert(entry == kCertificateChainLength);
+
+ *error = KM_ERROR_OK;
+ return chain.release();
+}
+
+keymaster_error_t SoftKeymasterContext::ParseKeymaster1HwBlob(
+ const KeymasterKeyBlob& blob, const AuthorizationSet& additional_params,
+ KeymasterKeyBlob* key_material, AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) const {
+ assert(km1_dev_);
+
+ 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;
+
+ // 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;
+ unique_ptr<keymaster_key_characteristics_t, Characteristics_Delete> characteristics_deleter(
+ characteristics);
+
+ LOG_D("Module \"%s\" accepted key", km1_dev_->common.module->name);
+
+ hw_enforced->Reinitialize(characteristics->hw_enforced);
+ sw_enforced->Reinitialize(characteristics->sw_enforced);
+ *key_material = blob;
+ 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::FakeKeyAuthorizations(EVP_PKEY* pubkey,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) const {
+ hw_enforced->Clear();
+ sw_enforced->Clear();
+
+ switch (EVP_PKEY_type(pubkey->type)) {
+ case EVP_PKEY_RSA: {
+ hw_enforced->push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
+ hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_NONE);
+ hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_MD5);
+ hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_SHA1);
+ hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_SHA_2_224);
+ hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
+ hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_SHA_2_384);
+ hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_SHA_2_512);
+ hw_enforced->push_back(TAG_PADDING, KM_PAD_NONE);
+ hw_enforced->push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN);
+ hw_enforced->push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
+ hw_enforced->push_back(TAG_PADDING, KM_PAD_RSA_PSS);
+ hw_enforced->push_back(TAG_PADDING, KM_PAD_RSA_OAEP);
+
+ sw_enforced->push_back(TAG_PURPOSE, KM_PURPOSE_SIGN);
+ sw_enforced->push_back(TAG_PURPOSE, KM_PURPOSE_VERIFY);
+ sw_enforced->push_back(TAG_PURPOSE, KM_PURPOSE_ENCRYPT);
+ sw_enforced->push_back(TAG_PURPOSE, KM_PURPOSE_DECRYPT);
+
+ unique_ptr<RSA, RSA_Delete> rsa(EVP_PKEY_get1_RSA(pubkey));
+ 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;
+ hw_enforced->push_back(TAG_RSA_PUBLIC_EXPONENT, public_exponent);
+ break;
+ }
+
+ case EVP_PKEY_EC: {
+ hw_enforced->push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
+ hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_NONE);
+ hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_MD5);
+ hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_SHA1);
+ hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_SHA_2_224);
+ hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
+ hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_SHA_2_384);
+ hw_enforced->push_back(TAG_DIGEST, KM_DIGEST_SHA_2_512);
+
+ sw_enforced->push_back(TAG_PURPOSE, KM_PURPOSE_SIGN);
+ 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();
+ 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;
+ hw_enforced->push_back(TAG_KEY_SIZE, key_size_bits);
+ break;
+ }
+
+ default:
+ return KM_ERROR_UNSUPPORTED_ALGORITHM;
+ }
+
+ sw_enforced->push_back(TAG_ALL_USERS);
+ sw_enforced->push_back(TAG_NO_AUTH_REQUIRED);
+
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t SoftKeymasterContext::BuildHiddenAuthorizations(const AuthorizationSet& input_set,
+ AuthorizationSet* hidden) const {
+ keymaster_blob_t entry;
+ if (input_set.GetTagValue(TAG_APPLICATION_ID, &entry))
+ hidden->push_back(TAG_APPLICATION_ID, entry.data, entry.data_length);
+ if (input_set.GetTagValue(TAG_APPLICATION_DATA, &entry))
+ hidden->push_back(TAG_APPLICATION_DATA, entry.data, entry.data_length);
+
+ hidden->push_back(TAG_ROOT_OF_TRUST, reinterpret_cast<const uint8_t*>(root_of_trust_.data()),
+ root_of_trust_.size());
+
+ return TranslateAuthorizationSetError(hidden->is_valid());
+}
+
+} // namespace keymaster
diff --git a/keymaster/soft_keymaster_device.cpp b/keymaster/soft_keymaster_device.cpp
new file mode 100644
index 0000000..cbeaec7
--- /dev/null
+++ b/keymaster/soft_keymaster_device.cpp
@@ -0,0 +1,1341 @@
+/*
+ * 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/soft_keymaster_device.h>
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <algorithm>
+
+#include <type_traits>
+
+#include <openssl/x509.h>
+
+#include <hardware/keymaster1.h>
+#define LOG_TAG "SoftKeymasterDevice"
+#include <cutils/log.h>
+
+#include <keymaster/android_keymaster.h>
+#include <keymaster/android_keymaster_messages.h>
+#include <keymaster/authorization_set.h>
+#include <keymaster/soft_keymaster_context.h>
+#include <keymaster/soft_keymaster_logger.h>
+
+#include "openssl_utils.h"
+
+struct keystore_module soft_keymaster1_device_module = {
+ .common =
+ {
+ .tag = HARDWARE_MODULE_TAG,
+ .module_api_version = KEYMASTER_MODULE_API_VERSION_1_0,
+ .hal_api_version = HARDWARE_HAL_API_VERSION,
+ .id = KEYSTORE_HARDWARE_MODULE_ID,
+ .name = "OpenSSL-based SoftKeymaster HAL",
+ .author = "The Android Open Source Project",
+ .methods = nullptr,
+ .dso = 0,
+ .reserved = {},
+ },
+};
+
+struct keystore_module soft_keymaster2_device_module = {
+ .common =
+ {
+ .tag = HARDWARE_MODULE_TAG,
+ .module_api_version = KEYMASTER_MODULE_API_VERSION_2_0,
+ .hal_api_version = HARDWARE_HAL_API_VERSION,
+ .id = KEYSTORE_HARDWARE_MODULE_ID,
+ .name = "OpenSSL-based SoftKeymaster HAL",
+ .author = "The Android Open Source Project",
+ .methods = nullptr,
+ .dso = 0,
+ .reserved = {},
+ },
+};
+
+namespace keymaster {
+
+const size_t kOperationTableSize = 16;
+
+template <typename T> std::vector<T> make_vector(const T* array, size_t len) {
+ return std::vector<T>(array, array + len);
+}
+
+static keymaster_error_t add_digests(keymaster1_device_t* dev, keymaster_algorithm_t algorithm,
+ keymaster_purpose_t purpose,
+ SoftKeymasterDevice::DigestMap* map) {
+ auto key = std::make_pair(algorithm, purpose);
+
+ keymaster_digest_t* digests;
+ size_t digests_length;
+ keymaster_error_t error =
+ dev->get_supported_digests(dev, algorithm, purpose, &digests, &digests_length);
+ if (error != KM_ERROR_OK) {
+ LOG_E("Error %d getting supported digests from keymaster1 device", error);
+ return error;
+ }
+ std::unique_ptr<keymaster_digest_t, Malloc_Delete> digests_deleter(digests);
+
+ (*map)[key] = make_vector(digests, digests_length);
+ return KM_ERROR_OK;
+}
+
+static keymaster_error_t map_digests(keymaster1_device_t* dev,
+ SoftKeymasterDevice::DigestMap* map) {
+ map->clear();
+
+ keymaster_algorithm_t sig_algorithms[] = {KM_ALGORITHM_RSA, KM_ALGORITHM_EC};
+ keymaster_purpose_t sig_purposes[] = {KM_PURPOSE_SIGN, KM_PURPOSE_VERIFY};
+ for (auto algorithm : sig_algorithms)
+ for (auto purpose : sig_purposes) {
+ keymaster_error_t error = add_digests(dev, algorithm, purpose, map);
+ if (error != KM_ERROR_OK)
+ return error;
+ }
+
+ keymaster_algorithm_t crypt_algorithms[] = {KM_ALGORITHM_RSA};
+ keymaster_purpose_t crypt_purposes[] = {KM_PURPOSE_ENCRYPT, KM_PURPOSE_DECRYPT};
+ for (auto algorithm : crypt_algorithms)
+ for (auto purpose : crypt_purposes) {
+ keymaster_error_t error = add_digests(dev, algorithm, purpose, map);
+ if (error != KM_ERROR_OK)
+ return error;
+ }
+
+ return KM_ERROR_OK;
+}
+
+SoftKeymasterDevice::SoftKeymasterDevice()
+ : wrapped_km0_device_(nullptr), wrapped_km1_device_(nullptr),
+ context_(new SoftKeymasterContext),
+ impl_(new AndroidKeymaster(context_, kOperationTableSize)) {
+ LOG_I("Creating device", 0);
+ LOG_D("Device address: %p", this);
+
+ initialize_device_struct(KEYMASTER_SOFTWARE_ONLY | KEYMASTER_BLOBS_ARE_STANDALONE |
+ KEYMASTER_SUPPORTS_EC);
+}
+
+SoftKeymasterDevice::SoftKeymasterDevice(SoftKeymasterContext* context)
+ : wrapped_km0_device_(nullptr), wrapped_km1_device_(nullptr), context_(context),
+ impl_(new AndroidKeymaster(context_, kOperationTableSize)) {
+ LOG_I("Creating test device", 0);
+ LOG_D("Device address: %p", this);
+
+ initialize_device_struct(KEYMASTER_SOFTWARE_ONLY | KEYMASTER_BLOBS_ARE_STANDALONE |
+ 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;
+
+ 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_km0_device_ = keymaster0_device;
+ 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;
+
+ keymaster_error_t error = map_digests(keymaster1_device, &km1_device_digests_);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ error = context_->SetHardwareDevice(keymaster1_device);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ initialize_device_struct(keymaster1_device->flags);
+
+ module_name_ = km1_device_.common.module->name;
+ module_name_.append(" (Wrapping ");
+ module_name_.append(keymaster1_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_km0_device_ = nullptr;
+ wrapped_km1_device_ = keymaster1_device;
+ return KM_ERROR_OK;
+}
+
+bool SoftKeymasterDevice::Keymaster1DeviceIsGood() {
+ std::vector<keymaster_digest_t> expected_rsa_digests = {
+ KM_DIGEST_NONE, KM_DIGEST_MD5, KM_DIGEST_SHA1, KM_DIGEST_SHA_2_224,
+ KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512};
+ std::vector<keymaster_digest_t> expected_ec_digests = {
+ KM_DIGEST_NONE, KM_DIGEST_SHA1, KM_DIGEST_SHA_2_224,
+ KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384, KM_DIGEST_SHA_2_512};
+
+ for (auto& entry : km1_device_digests_) {
+ if (entry.first.first == KM_ALGORITHM_RSA)
+ if (!std::is_permutation(entry.second.begin(), entry.second.end(),
+ expected_rsa_digests.begin()))
+ return false;
+ if (entry.first.first == KM_ALGORITHM_EC)
+ if (!std::is_permutation(entry.second.begin(), entry.second.end(),
+ expected_ec_digests.begin()))
+ return false;
+ }
+ return true;
+}
+
+void SoftKeymasterDevice::initialize_device_struct(uint32_t flags) {
+ memset(&km1_device_, 0, sizeof(km1_device_));
+
+ km1_device_.common.tag = HARDWARE_DEVICE_TAG;
+ km1_device_.common.version = 1;
+ km1_device_.common.module = reinterpret_cast<hw_module_t*>(&soft_keymaster1_device_module);
+ km1_device_.common.close = &close_device;
+
+ km1_device_.flags = flags;
+
+ km1_device_.context = this;
+
+ // keymaster0 APIs
+ km1_device_.generate_keypair = nullptr;
+ km1_device_.import_keypair = nullptr;
+ km1_device_.get_keypair_public = nullptr;
+ km1_device_.delete_keypair = nullptr;
+ km1_device_.delete_all = nullptr;
+ km1_device_.sign_data = nullptr;
+ km1_device_.verify_data = nullptr;
+
+ // keymaster1 APIs
+ km1_device_.get_supported_algorithms = get_supported_algorithms;
+ km1_device_.get_supported_block_modes = get_supported_block_modes;
+ km1_device_.get_supported_padding_modes = get_supported_padding_modes;
+ km1_device_.get_supported_digests = get_supported_digests;
+ km1_device_.get_supported_import_formats = get_supported_import_formats;
+ km1_device_.get_supported_export_formats = get_supported_export_formats;
+ km1_device_.add_rng_entropy = add_rng_entropy;
+ km1_device_.generate_key = generate_key;
+ km1_device_.get_key_characteristics = get_key_characteristics;
+ km1_device_.import_key = import_key;
+ km1_device_.export_key = export_key;
+ km1_device_.delete_key = delete_key;
+ km1_device_.delete_all_keys = delete_all_keys;
+ km1_device_.begin = begin;
+ km1_device_.update = update;
+ km1_device_.finish = finish;
+ km1_device_.abort = abort;
+
+ // keymaster2 APIs
+ memset(&km2_device_, 0, sizeof(km2_device_));
+
+ km2_device_.context = this;
+
+ km2_device_.common.tag = HARDWARE_DEVICE_TAG;
+ km2_device_.common.version = 1;
+ km2_device_.common.module = reinterpret_cast<hw_module_t*>(&soft_keymaster2_device_module);
+ km2_device_.common.close = &close_device;
+
+ km2_device_.add_rng_entropy = add_rng_entropy;
+ km2_device_.generate_key = generate_key;
+ km2_device_.get_key_characteristics = get_key_characteristics;
+ km2_device_.import_key = import_key;
+ km2_device_.export_key = export_key;
+ km2_device_.agree_key = nullptr; // TODO(swillden) Implement ECDH
+ km2_device_.attest_key = attest_key;
+ km2_device_.upgrade_key = nullptr; // TODO(swillden) Implement upgrade
+ km2_device_.delete_key = delete_key;
+ km2_device_.delete_all_keys = delete_all_keys;
+ km2_device_.begin = begin;
+ km2_device_.update = update;
+ km2_device_.finish = finish;
+ km2_device_.abort = abort;
+}
+
+hw_device_t* SoftKeymasterDevice::hw_device() {
+ return &km1_device_.common;
+}
+
+keymaster1_device_t* SoftKeymasterDevice::keymaster_device() {
+ return &km1_device_;
+}
+
+keymaster2_device_t* SoftKeymasterDevice::keymaster2_device() {
+ return &km2_device_;
+}
+
+namespace {
+
+keymaster_key_characteristics_t* BuildCharacteristics(const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced) {
+ keymaster_key_characteristics_t* characteristics =
+ reinterpret_cast<keymaster_key_characteristics_t*>(
+ malloc(sizeof(keymaster_key_characteristics_t)));
+ if (characteristics) {
+ hw_enforced.CopyToParamSet(&characteristics->hw_enforced);
+ sw_enforced.CopyToParamSet(&characteristics->sw_enforced);
+ }
+ return characteristics;
+}
+
+template <typename RequestType>
+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);
+}
+
+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 ||
+ std::is_same<T, keymaster2_device_t>::value),
+ "convert_device should only be applied to keymaster devices");
+ return reinterpret_cast<SoftKeymasterDevice*>(dev->context);
+}
+
+bool FindAlgorithm(const keymaster_key_param_set_t& params, keymaster_algorithm_t* algorithm) {
+ for (size_t i = 0; i < params.length; ++i)
+ if (params.params[i].tag == KM_TAG_ALGORITHM) {
+ *algorithm = static_cast<keymaster_algorithm_t>(params.params[i].enumerated);
+ return true;
+ }
+ return false;
+}
+
+keymaster_error_t GetAlgorithm(const keymaster1_device_t* dev, const keymaster_key_blob_t& key,
+ const AuthorizationSet& in_params,
+ keymaster_algorithm_t* algorithm) {
+ 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 (in_params.GetTagValue(TAG_APPLICATION_ID, &client_id))
+ client_id_ptr = &client_id;
+ if (in_params.GetTagValue(TAG_APPLICATION_DATA, &app_data))
+ app_data_ptr = &app_data;
+
+ keymaster_key_characteristics_t* characteristics;
+ keymaster_error_t error =
+ dev->get_key_characteristics(dev, &key, client_id_ptr, app_data_ptr, &characteristics);
+ if (error != KM_ERROR_OK)
+ return error;
+ std::unique_ptr<keymaster_key_characteristics_t, Characteristics_Delete>
+ characteristics_deleter(characteristics);
+
+ if (FindAlgorithm(characteristics->hw_enforced, algorithm))
+ return KM_ERROR_OK;
+
+ if (FindAlgorithm(characteristics->sw_enforced, algorithm))
+ return KM_ERROR_OK;
+
+ return KM_ERROR_INVALID_KEY_BLOB;
+}
+
+} // unnamed namespaced
+
+/* static */
+int SoftKeymasterDevice::close_device(hw_device_t* dev) {
+ switch (dev->module->module_api_version) {
+ case KEYMASTER_MODULE_API_VERSION_2_0: {
+ delete convert_device(reinterpret_cast<keymaster2_device_t*>(dev));
+ break;
+ }
+
+ case KEYMASTER_MODULE_API_VERSION_1_0: {
+ delete convert_device(reinterpret_cast<keymaster1_device_t*>(dev));
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+/* static */
+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 (!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);
+
+ SupportedAlgorithmsRequest request;
+ SupportedAlgorithmsResponse response;
+ convert_device(dev)->impl_->SupportedAlgorithms(request, &response);
+ if (response.error != KM_ERROR_OK) {
+ LOG_E("get_supported_algorithms failed with %d", response.error);
+
+ return response.error;
+ }
+
+ *algorithms_length = response.results_length;
+ *algorithms =
+ reinterpret_cast<keymaster_algorithm_t*>(malloc(*algorithms_length * sizeof(**algorithms)));
+ if (!*algorithms)
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ std::copy(response.results, response.results + response.results_length, *algorithms);
+ return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::get_supported_block_modes(const keymaster1_device_t* dev,
+ keymaster_algorithm_t algorithm,
+ keymaster_purpose_t purpose,
+ keymaster_block_mode_t** modes,
+ size_t* modes_length) {
+ if (!dev)
+ return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+ 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;
+ request.algorithm = algorithm;
+ request.purpose = purpose;
+ SupportedBlockModesResponse response;
+ convert_device(dev)->impl_->SupportedBlockModes(request, &response);
+
+ if (response.error != KM_ERROR_OK) {
+ LOG_E("get_supported_block_modes failed with %d", response.error);
+
+ return response.error;
+ }
+
+ *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;
+ std::copy(response.results, response.results + response.results_length, *modes);
+ return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::get_supported_padding_modes(const keymaster1_device_t* dev,
+ keymaster_algorithm_t algorithm,
+ keymaster_purpose_t purpose,
+ keymaster_padding_t** modes,
+ size_t* modes_length) {
+ if (!dev)
+ return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+ 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;
+ request.algorithm = algorithm;
+ request.purpose = purpose;
+ SupportedPaddingModesResponse response;
+ convert_device(dev)->impl_->SupportedPaddingModes(request, &response);
+
+ if (response.error != KM_ERROR_OK) {
+ LOG_E("get_supported_padding_modes failed with %d", response.error);
+ return response.error;
+ }
+
+ *modes_length = response.results_length;
+ *modes = reinterpret_cast<keymaster_padding_t*>(malloc(*modes_length * sizeof(**modes)));
+ if (!*modes)
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ std::copy(response.results, response.results + response.results_length, *modes);
+ return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::get_supported_digests(const keymaster1_device_t* dev,
+ keymaster_algorithm_t algorithm,
+ keymaster_purpose_t purpose,
+ keymaster_digest_t** digests,
+ size_t* digests_length) {
+ if (!dev)
+ return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+ 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;
+ request.algorithm = algorithm;
+ request.purpose = purpose;
+ SupportedDigestsResponse response;
+ convert_device(dev)->impl_->SupportedDigests(request, &response);
+
+ if (response.error != KM_ERROR_OK) {
+ LOG_E("get_supported_digests failed with %d", response.error);
+ return response.error;
+ }
+
+ *digests_length = response.results_length;
+ *digests = reinterpret_cast<keymaster_digest_t*>(malloc(*digests_length * sizeof(**digests)));
+ if (!*digests)
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ std::copy(response.results, response.results + response.results_length, *digests);
+ return KM_ERROR_OK;
+}
+
+/* static */
+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 (!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;
+ request.algorithm = algorithm;
+ SupportedImportFormatsResponse response;
+ convert_device(dev)->impl_->SupportedImportFormats(request, &response);
+
+ if (response.error != KM_ERROR_OK) {
+ LOG_E("get_supported_import_formats failed with %d", response.error);
+ return response.error;
+ }
+
+ *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;
+ std::copy(response.results, response.results + response.results_length, *formats);
+ return KM_ERROR_OK;
+}
+
+/* static */
+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 (!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;
+ request.algorithm = algorithm;
+ SupportedExportFormatsResponse response;
+ convert_device(dev)->impl_->SupportedExportFormats(request, &response);
+
+ if (response.error != KM_ERROR_OK) {
+ LOG_E("get_supported_export_formats failed with %d", response.error);
+ return response.error;
+ }
+
+ *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;
+ std::copy(response.results, response.results + *formats_length, *formats);
+ return KM_ERROR_OK;
+}
+
+/* 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;
+
+ 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);
+
+ AddEntropyRequest request;
+ 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);
+ 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;
+
+ SoftKeymasterDevice* sk_dev = convert_device(dev);
+ return add_rng_entropy(&sk_dev->km1_device_, data, data_length);
+}
+
+template <typename Collection, typename Value> bool contains(const Collection& c, const Value& v) {
+ return std::find(c.begin(), c.end(), v) != c.end();
+}
+
+bool SoftKeymasterDevice::FindUnsupportedDigest(keymaster_algorithm_t algorithm,
+ keymaster_purpose_t purpose,
+ const AuthorizationSet& params,
+ keymaster_digest_t* unsupported) const {
+ assert(wrapped_km1_device_);
+
+ auto supported_digests = km1_device_digests_.find(std::make_pair(algorithm, purpose));
+ if (supported_digests == km1_device_digests_.end())
+ // Invalid algorith/purpose pair (e.g. EC encrypt). Let the error be handled by HW module.
+ return false;
+
+ for (auto& entry : params)
+ if (entry.tag == TAG_DIGEST)
+ if (!contains(supported_digests->second, entry.enumerated)) {
+ LOG_I("Digest %d requested but not supported by module %s", entry.enumerated,
+ wrapped_km1_device_->common.module->name);
+ *unsupported = static_cast<keymaster_digest_t>(entry.enumerated);
+ return true;
+ }
+ return false;
+}
+
+bool SoftKeymasterDevice::RequiresSoftwareDigesting(keymaster_algorithm_t algorithm,
+ keymaster_purpose_t purpose,
+ const AuthorizationSet& params) const {
+ assert(wrapped_km1_device_);
+ if (!wrapped_km1_device_)
+ return true;
+
+ switch (algorithm) {
+ case KM_ALGORITHM_AES:
+ case KM_ALGORITHM_HMAC:
+ LOG_D("Not performing software digesting for algorithm %d", algorithm);
+ return false;
+ case KM_ALGORITHM_RSA:
+ case KM_ALGORITHM_EC:
+ break;
+ }
+
+ keymaster_digest_t unsupported;
+ if (!FindUnsupportedDigest(algorithm, purpose, params, &unsupported)) {
+ LOG_D("Requested digest(s) supported for algorithm %d and purpose %d", algorithm, purpose);
+ return false;
+ }
+
+ return true;
+}
+
+bool SoftKeymasterDevice::KeyRequiresSoftwareDigesting(
+ const AuthorizationSet& key_description) const {
+ assert(wrapped_km1_device_);
+ if (!wrapped_km1_device_)
+ return true;
+
+ keymaster_algorithm_t algorithm;
+ if (!key_description.GetTagValue(TAG_ALGORITHM, &algorithm)) {
+ // The hardware module will return an error during keygen.
+ return false;
+ }
+
+ 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;
+ }
+
+ return false;
+}
+
+/* static */
+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 (!key_blob)
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+ SoftKeymasterDevice* sk_dev = convert_device(dev);
+
+ GenerateKeyRequest request;
+ 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;
+
+ 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;
+ memcpy(tmp, response.key_blob.key_material, response.key_blob.key_material_size);
+ key_blob->key_material = tmp;
+
+ if (characteristics) {
+ *characteristics = BuildCharacteristics(response.enforced, response.unenforced);
+ if (!*characteristics)
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ }
+
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t
+SoftKeymasterDevice::generate_key(const keymaster2_device_t* dev, //
+ 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 (!key_blob)
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+ SoftKeymasterDevice* sk_dev = convert_device(dev);
+
+ GenerateKeyRequest request;
+ request.key_description.Reinitialize(*params);
+
+ keymaster1_device_t* km1_dev = sk_dev->wrapped_km1_device_;
+ if (km1_dev && !sk_dev->KeyRequiresSoftwareDigesting(request.key_description)) {
+ keymaster_key_characteristics_t* chars_ptr;
+ keymaster_error_t error = km1_dev->generate_key(km1_dev, params, key_blob,
+ characteristics ? &chars_ptr : nullptr);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ if (characteristics) {
+ *characteristics = *chars_ptr;
+ free(chars_ptr);
+ }
+ return KM_ERROR_OK;
+ }
+
+ GenerateKeyResponse response;
+ sk_dev->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;
+ memcpy(tmp, response.key_blob.key_material, response.key_blob.key_material_size);
+ key_blob->key_material = tmp;
+
+ if (characteristics) {
+ response.enforced.CopyToParamSet(&characteristics->hw_enforced);
+ response.unenforced.CopyToParamSet(&characteristics->sw_enforced);
+ }
+
+ return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::get_key_characteristics(
+ 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 (!characteristics)
+ 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_key_characteristics(km1_dev, key_blob, client_id, app_data,
+ characteristics);
+
+ GetKeyCharacteristicsRequest request;
+ 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;
+
+ *characteristics = BuildCharacteristics(response.enforced, response.unenforced);
+ if (!*characteristics)
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::get_key_characteristics(
+ 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 (!characteristics)
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+ SoftKeymasterDevice* sk_dev = convert_device(dev);
+
+ keymaster_error_t error;
+ keymaster_key_characteristics_t* key_characteristics;
+ error = get_key_characteristics(&sk_dev->km1_device_, key_blob, client_id, app_data,
+ &key_characteristics);
+ if (error != KM_ERROR_OK)
+ return error;
+ *characteristics = *key_characteristics;
+ free(key_characteristics);
+
+ return error;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::import_key(
+ 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 (!key_blob)
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+ SoftKeymasterDevice* sk_dev = convert_device(dev);
+
+ ImportKeyRequest request;
+ 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->import_key(km1_dev, params, key_format, key_data, key_blob,
+ characteristics);
+
+ *characteristics = nullptr;
+
+ request.key_format = key_format;
+ request.SetKeyMaterial(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;
+
+ 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;
+ 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;
+ }
+ return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::import_key(
+ 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;
+
+ SoftKeymasterDevice* sk_dev = convert_device(dev);
+
+ keymaster_error_t error;
+ if (characteristics) {
+ keymaster_key_characteristics_t* characteristics_ptr;
+ error = import_key(&sk_dev->km1_device_, params, key_format, key_data, key_blob,
+ &characteristics_ptr);
+ if (error == KM_ERROR_OK) {
+ *characteristics = *characteristics_ptr;
+ free(characteristics_ptr);
+ }
+ } else {
+ error = import_key(&sk_dev->km1_device_, params, key_format, key_data, key_blob, nullptr);
+ }
+
+ return error;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::export_key(const keymaster1_device_t* dev,
+ keymaster_key_format_t export_format,
+ const keymaster_key_blob_t* key_to_export,
+ 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 (!export_data)
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+ const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
+ if (km1_dev)
+ return km1_dev->export_key(km1_dev, export_format, key_to_export, client_id, app_data,
+ export_data);
+
+ export_data->data = nullptr;
+ export_data->data_length = 0;
+
+ ExportKeyRequest request;
+ 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;
+
+ 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;
+ memcpy(tmp, response.key_data, export_data->data_length);
+ export_data->data = tmp;
+ return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::export_key(const keymaster2_device_t* dev,
+ keymaster_key_format_t export_format,
+ const keymaster_key_blob_t* key_to_export,
+ 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;
+
+ SoftKeymasterDevice* sk_dev = convert_device(dev);
+ return export_key(&sk_dev->km1_device_, export_format, key_to_export, client_id, app_data,
+ export_data);
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::attest_key(const keymaster2_device_t* dev,
+ const keymaster_key_blob_t* key_to_attest,
+ const keymaster_key_param_set_t* attest_params,
+ keymaster_cert_chain_t* cert_chain) {
+ if (!dev || !key_to_attest || !attest_params || !cert_chain)
+ return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+ cert_chain->entry_count = 0;
+ cert_chain->entries = nullptr;
+
+ AttestKeyRequest request;
+ request.SetKeyMaterial(*key_to_attest);
+ request.attest_params.Reinitialize(*attest_params);
+
+ AttestKeyResponse response;
+ convert_device(dev)->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;
+ cert_chain->entry_count = rsp_chain.entry_count;
+ for (keymaster_blob_t& entry : array_range(cert_chain->entries, cert_chain->entry_count))
+ entry = {};
+
+ // Copy cert_chain contents
+ size_t i = 0;
+ for (keymaster_blob_t& entry : array_range(rsp_chain.entries, rsp_chain.entry_count)) {
+ cert_chain->entries[i].data = reinterpret_cast<uint8_t*>(malloc(entry.data_length));
+ if (!cert_chain->entries[i].data) {
+ keymaster_free_cert_chain(cert_chain);
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ }
+ cert_chain->entries[i].data_length = entry.data_length;
+ memcpy(const_cast<uint8_t*>(cert_chain->entries[i].data), entry.data, entry.data_length);
+ ++i;
+ }
+
+ return KM_ERROR_OK;
+}
+
+/* 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;
+
+ KeymasterKeyBlob blob(*key);
+ return convert_device(dev)->context_->DeleteKey(blob);
+}
+
+/* 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;
+
+ KeymasterKeyBlob blob(*key);
+ return convert_device(dev)->context_->DeleteKey(blob);
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::delete_all_keys(const keymaster1_device_t* dev) {
+ 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;
+
+ return convert_device(dev)->context_->DeleteAllKeys();
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::begin(const keymaster1_device_t* dev,
+ keymaster_purpose_t purpose,
+ const keymaster_key_blob_t* key,
+ const keymaster_key_param_set_t* in_params,
+ keymaster_key_param_set_t* out_params,
+ keymaster_operation_handle_t* operation_handle) {
+ if (!key || !key->key_material)
+ return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+ if (!operation_handle)
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+ const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
+ if (km1_dev) {
+ AuthorizationSet in_params_set(*in_params);
+
+ keymaster_algorithm_t algorithm = KM_ALGORITHM_AES;
+ keymaster_error_t error = GetAlgorithm(km1_dev, *key, in_params_set, &algorithm);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ if (!convert_device(dev)->RequiresSoftwareDigesting(algorithm, purpose, in_params_set)) {
+ LOG_D("Operation supported by %s, passing through to keymaster1 module",
+ km1_dev->common.module->name);
+ return km1_dev->begin(km1_dev, purpose, key, in_params, out_params, operation_handle);
+ }
+ LOG_I("Doing software digesting for keymaster1 module %s", km1_dev->common.module->name);
+ }
+
+ if (out_params) {
+ out_params->params = nullptr;
+ out_params->length = 0;
+ }
+
+ BeginOperationRequest request;
+ request.purpose = purpose;
+ request.SetKeyMaterial(*key);
+ request.additional_params.Reinitialize(*in_params);
+
+ BeginOperationResponse response;
+ convert_device(dev)->impl_->BeginOperation(request, &response);
+ if (response.error != KM_ERROR_OK)
+ return response.error;
+
+ if (response.output_params.size() > 0) {
+ if (out_params)
+ response.output_params.CopyToParamSet(out_params);
+ else
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+ }
+
+ *operation_handle = response.op_handle;
+ return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::begin(const keymaster2_device_t* dev,
+ keymaster_purpose_t purpose,
+ const keymaster_key_blob_t* key,
+ 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;
+
+ SoftKeymasterDevice* sk_dev = convert_device(dev);
+ return begin(&sk_dev->km1_device_, purpose, key, in_params, out_params, operation_handle);
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::update(const keymaster1_device_t* dev,
+ keymaster_operation_handle_t operation_handle,
+ const keymaster_key_param_set_t* in_params,
+ 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_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)) {
+ // This operation is being handled by km1_dev (or doesn't exist). Pass it through to
+ // km1_dev. Otherwise, we'll use the software AndroidKeymaster, which may delegate to
+ // km1_dev after doing necessary digesting.
+ return km1_dev->update(km1_dev, operation_handle, in_params, input, input_consumed,
+ out_params, output);
+ }
+
+ if (out_params) {
+ out_params->params = nullptr;
+ out_params->length = 0;
+ }
+ if (output) {
+ output->data = nullptr;
+ output->data_length = 0;
+ }
+
+ UpdateOperationRequest request;
+ request.op_handle = operation_handle;
+ 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;
+
+ if (response.output_params.size() > 0) {
+ if (out_params)
+ response.output_params.CopyToParamSet(out_params);
+ else
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+ }
+
+ *input_consumed = response.input_consumed;
+ 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;
+ memcpy(tmp, response.output.peek_read(), output->data_length);
+ output->data = tmp;
+ } else if (response.output.available_read() > 0) {
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+ }
+ return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::update(const keymaster2_device_t* dev,
+ keymaster_operation_handle_t operation_handle,
+ const keymaster_key_param_set_t* in_params,
+ 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;
+
+ SoftKeymasterDevice* sk_dev = convert_device(dev);
+ return update(&sk_dev->km1_device_, operation_handle, in_params, input, input_consumed,
+ out_params, output);
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::finish(const keymaster1_device_t* dev,
+ keymaster_operation_handle_t operation_handle,
+ const keymaster_key_param_set_t* params,
+ const keymaster_blob_t* signature,
+ keymaster_key_param_set_t* out_params,
+ keymaster_blob_t* output) {
+ const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
+ if (km1_dev && !convert_device(dev)->impl_->has_operation(operation_handle)) {
+ // This operation is being handled by km1_dev (or doesn't exist). Pass it through to
+ // km1_dev. Otherwise, we'll use the software AndroidKeymaster, which may delegate to
+ // km1_dev after doing necessary digesting.
+ return km1_dev->finish(km1_dev, operation_handle, params, signature, out_params, output);
+ }
+
+ if (out_params) {
+ out_params->params = nullptr;
+ out_params->length = 0;
+ }
+
+ if (output) {
+ output->data = nullptr;
+ output->data_length = 0;
+ }
+
+ FinishOperationRequest request;
+ 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;
+
+ if (response.output_params.size() > 0) {
+ if (out_params)
+ response.output_params.CopyToParamSet(out_params);
+ else
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+ }
+ 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;
+ memcpy(tmp, response.output.peek_read(), output->data_length);
+ output->data = tmp;
+ } else if (response.output.available_read() > 0) {
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+ }
+
+ return KM_ERROR_OK;
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::finish(const keymaster2_device_t* dev,
+ keymaster_operation_handle_t operation_handle,
+ const keymaster_key_param_set_t* params,
+ const keymaster_blob_t* input,
+ 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 (input && input->data)
+ return KM_ERROR_UNIMPLEMENTED; // TODO(swillden): Implement this
+
+ SoftKeymasterDevice* sk_dev = convert_device(dev);
+ return finish(&sk_dev->km1_device_, operation_handle, params, signature, out_params, output);
+}
+
+/* static */
+keymaster_error_t SoftKeymasterDevice::abort(const keymaster1_device_t* dev,
+ keymaster_operation_handle_t operation_handle) {
+ const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
+ if (km1_dev && !convert_device(dev)->impl_->has_operation(operation_handle)) {
+ // This operation is being handled by km1_dev (or doesn't exist). Pass it through to
+ // km1_dev. Otherwise, we'll use the software AndroidKeymaster, which may delegate to
+ // km1_dev.
+ return km1_dev->abort(km1_dev, operation_handle);
+ }
+
+ AbortOperationRequest request;
+ request.op_handle = operation_handle;
+ AbortOperationResponse response;
+ convert_device(dev)->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;
+
+ SoftKeymasterDevice* sk_dev = convert_device(dev);
+ return abort(&sk_dev->km1_device_, operation_handle);
+}
+
+/* static */
+void SoftKeymasterDevice::StoreDefaultNewKeyParams(keymaster_algorithm_t algorithm,
+ AuthorizationSet* auth_set) {
+ auth_set->push_back(TAG_PURPOSE, KM_PURPOSE_SIGN);
+ auth_set->push_back(TAG_PURPOSE, KM_PURPOSE_VERIFY);
+ auth_set->push_back(TAG_ALL_USERS);
+ auth_set->push_back(TAG_NO_AUTH_REQUIRED);
+
+ // All digests.
+ auth_set->push_back(TAG_DIGEST, KM_DIGEST_NONE);
+ auth_set->push_back(TAG_DIGEST, KM_DIGEST_MD5);
+ auth_set->push_back(TAG_DIGEST, KM_DIGEST_SHA1);
+ auth_set->push_back(TAG_DIGEST, KM_DIGEST_SHA_2_224);
+ auth_set->push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
+ auth_set->push_back(TAG_DIGEST, KM_DIGEST_SHA_2_384);
+ auth_set->push_back(TAG_DIGEST, KM_DIGEST_SHA_2_512);
+
+ if (algorithm == KM_ALGORITHM_RSA) {
+ auth_set->push_back(TAG_PURPOSE, KM_PURPOSE_ENCRYPT);
+ auth_set->push_back(TAG_PURPOSE, KM_PURPOSE_DECRYPT);
+ auth_set->push_back(TAG_PADDING, KM_PAD_NONE);
+ auth_set->push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN);
+ auth_set->push_back(TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
+ auth_set->push_back(TAG_PADDING, KM_PAD_RSA_PSS);
+ auth_set->push_back(TAG_PADDING, KM_PAD_RSA_OAEP);
+ }
+}
+
+} // namespace keymaster
diff --git a/keymaster/soft_keymaster_logger.cpp b/keymaster/soft_keymaster_logger.cpp
new file mode 100644
index 0000000..3c55a64
--- /dev/null
+++ b/keymaster/soft_keymaster_logger.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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/soft_keymaster_logger.h>
+
+#include <stdarg.h>
+#include <syslog.h>
+
+#define LOG_TAG "SoftKeymaster"
+#include <cutils/log.h>
+
+namespace keymaster {
+
+int SoftKeymasterLogger::log_msg(LogLevel level, const char* fmt, va_list args) const {
+
+ int android_log_level = ANDROID_LOG_ERROR;
+ switch (level) {
+ case DEBUG_LVL:
+ android_log_level = ANDROID_LOG_DEBUG;
+ break;
+ case INFO_LVL:
+ android_log_level = ANDROID_LOG_INFO;
+ break;
+ case WARNING_LVL:
+ android_log_level = ANDROID_LOG_WARN;
+ break;
+ case ERROR_LVL:
+ android_log_level = ANDROID_LOG_ERROR;
+ break;
+ case SEVERE_LVL:
+ android_log_level = ANDROID_LOG_ERROR;
+ break;
+ }
+
+ return LOG_PRI_VA(android_log_level, LOG_TAG, fmt, args);
+}
+
+} // namespace keymaster
diff --git a/keymaster/sw_rsa_attest_root.key.pem b/keymaster/sw_rsa_attest_root.key.pem
new file mode 100644
index 0000000..387a852
--- /dev/null
+++ b/keymaster/sw_rsa_attest_root.key.pem
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQCia63rbi5EYe/VDoLmt5TRdSMfd5tjkWP/96r/C3JHTsAsQ+wz
+fNes7UA+jCigZtX3hwszl94OuE4TQKuvpSe/lWmgMdsGUmX4RFlXYfC78hdLt0GA
+ZMAoDo9Sd47b0ke2RekZyOmLw9vCkT/X11DEHTVm+Vfkl5YLCazOkjWFmwIDAQAB
+AoGAU8dxXchmqzVNbbvff7zgUa63YErk51Yem/EXzhkMaIXRkMO0edaCtZtnkRvg
+9OQ2qEiLWaCTlUoyU7H/HUn2lwTQsOXyZI7dHijVDRMIv1mmrHCrGW/JC8FXfPLS
+r3L3KoHXQVYL2mslbR8Rpogxq4WwnwK6XqSTH9mynFwQwEkCQQDMX3EZk3ricWVH
+ruXD0BpXOMMpZuLu4rg5+1L51WEJvItIMeSjLuNa+g3AI8AYTYYi/aSLk6XEv82L
+iXFGmJ2XAkEAy3M8k8Z0QzHae4olduqoHVWEarBtDE+fqFQBWgdm8fZhdHWrvlAc
+qwJIXMUVc+dWm/FAQarCjbqWqhCRdaYgnQJBAJ7z7GdUCVNtlrQ2F4ZAqPwFreTZ
+nM7njxmpm1Os3hhQiJPSGl3A7huoOGGkbJd6VEWKuRvF7jwkYZ2RfITH1mkCQAvh
+X9E1Toa5+4spRwTJsSV9X+0m/kcwwx7+QNH0CrPockptsKi9Xt8xk+4u6BDLmogi
+r2DmStQh6DhoHUZkfBUCQQCOgBkqH/15drpdR+BQH3VaP4/ALFfxR9E3G+lS+M5a
+IqJEk9kh8vjuGzTaAZyU5keUmpWNc1gI7OvDMaH4+8vQ
+-----END RSA PRIVATE KEY-----
diff --git a/keymaster/symmetric_key.cpp b/keymaster/symmetric_key.cpp
new file mode 100644
index 0000000..1d51e3a
--- /dev/null
+++ b/keymaster/symmetric_key.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2014 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 "symmetric_key.h"
+
+#include <assert.h>
+
+#include <openssl/err.h>
+#include <openssl/rand.h>
+
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/logger.h>
+#include <keymaster/keymaster_context.h>
+
+#include "aes_key.h"
+#include "hmac_key.h"
+#include "openssl_err.h"
+
+namespace keymaster {
+
+keymaster_error_t SymmetricKeyFactory::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;
+
+ uint32_t key_size_bits;
+ if (!key_description.GetTagValue(TAG_KEY_SIZE, &key_size_bits) ||
+ !key_size_supported(key_size_bits))
+ 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;
+
+ size_t key_data_size = key_size_bits / 8;
+ KeymasterKeyBlob key_material(key_data_size);
+ if (!key_material.key_material)
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ error = context_->GenerateRandom(key_material.writable_data(), key_data_size);
+ if (error != KM_ERROR_OK) {
+ LOG_E("Error generating %d bit symmetric key", key_size_bits);
+ return error;
+ }
+
+ return context_->CreateKeyBlob(key_description, KM_ORIGIN_GENERATED, key_material, key_blob,
+ hw_enforced, sw_enforced);
+}
+
+keymaster_error_t SymmetricKeyFactory::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(key_description);
+
+ uint32_t key_size_bits;
+ if (!authorizations.GetTagValue(TAG_KEY_SIZE, &key_size_bits)) {
+ // Default key size if not specified.
+ key_size_bits = input_key_material.key_material_size * 8;
+ authorizations.push_back(TAG_KEY_SIZE, key_size_bits);
+ }
+
+ keymaster_error_t error = validate_algorithm_specific_new_key_params(key_description);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ if (!key_size_supported(key_size_bits))
+ return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+
+ if (input_key_material_format != KM_KEY_FORMAT_RAW)
+ return KM_ERROR_UNSUPPORTED_KEY_FORMAT;
+
+ if (key_size_bits != input_key_material.key_material_size * 8) {
+ LOG_E("Expected %d-bit key data but got %d bits", key_size_bits,
+ input_key_material.key_material_size * 8);
+ return KM_ERROR_INVALID_KEY_BLOB;
+ }
+
+ return context_->CreateKeyBlob(authorizations, KM_ORIGIN_IMPORTED, input_key_material,
+ output_key_blob, hw_enforced, sw_enforced);
+}
+
+static const keymaster_key_format_t supported_import_formats[] = {KM_KEY_FORMAT_RAW};
+const keymaster_key_format_t*
+SymmetricKeyFactory::SupportedImportFormats(size_t* format_count) const {
+ *format_count = array_length(supported_import_formats);
+ return supported_import_formats;
+}
+
+SymmetricKey::SymmetricKey(const KeymasterKeyBlob& key_material,
+ const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+ keymaster_error_t* error)
+ : Key(hw_enforced, sw_enforced, error) {
+ if (*error != KM_ERROR_OK)
+ return;
+
+ uint8_t* tmp = dup_buffer(key_material.key_material, key_material.key_material_size);
+ if (tmp) {
+ key_data_.reset(tmp);
+ key_data_size_ = key_material.key_material_size;
+ *error = KM_ERROR_OK;
+ } else {
+ *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ }
+}
+
+SymmetricKey::~SymmetricKey() {
+ memset_s(key_data_.get(), 0, key_data_size_);
+}
+
+keymaster_error_t SymmetricKey::key_material(UniquePtr<uint8_t[]>* key_material,
+ size_t* size) const {
+ *size = key_data_size_;
+ key_material->reset(new (std::nothrow) uint8_t[*size]);
+ if (!key_material->get())
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ memcpy(key_material->get(), key_data_.get(), *size);
+ return KM_ERROR_OK;
+}
+
+} // namespace keymaster
diff --git a/keymaster/symmetric_key.h b/keymaster/symmetric_key.h
new file mode 100644
index 0000000..979df62
--- /dev/null
+++ b/keymaster/symmetric_key.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2014 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_SYMMETRIC_KEY_H_
+#define SYSTEM_KEYMASTER_SYMMETRIC_KEY_H_
+
+#include <keymaster/key_factory.h>
+
+#include "key.h"
+
+namespace keymaster {
+
+class SymmetricKey;
+
+class SymmetricKeyFactory : public KeyFactory {
+ public:
+ explicit SymmetricKeyFactory(const KeymasterContext* context) : KeyFactory(context) {}
+
+ 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;
+
+ virtual const keymaster_key_format_t* SupportedImportFormats(size_t* format_count) const;
+ virtual const keymaster_key_format_t* SupportedExportFormats(size_t* format_count) const {
+ return NoFormats(format_count);
+ };
+
+ private:
+ virtual bool key_size_supported(size_t key_size_bits) const = 0;
+ virtual keymaster_error_t
+ validate_algorithm_specific_new_key_params(const AuthorizationSet& key_description) const = 0;
+
+ const keymaster_key_format_t* NoFormats(size_t* format_count) const {
+ *format_count = 0;
+ return NULL;
+ }
+};
+
+class SymmetricKey : public Key {
+ public:
+ ~SymmetricKey();
+
+ virtual keymaster_error_t key_material(UniquePtr<uint8_t[]>* key_material, size_t* size) const;
+ virtual keymaster_error_t formatted_key_material(keymaster_key_format_t, UniquePtr<uint8_t[]>*,
+ size_t*) const {
+ return KM_ERROR_UNSUPPORTED_KEY_FORMAT;
+ }
+
+ const uint8_t* key_data() const { return key_data_.get(); }
+ size_t key_data_size() const { return key_data_size_; }
+
+ protected:
+ SymmetricKey(const KeymasterKeyBlob& key_material, const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced, keymaster_error_t* error);
+
+ private:
+ size_t key_data_size_;
+ UniquePtr<uint8_t[]> key_data_;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_AES_KEY_H_
diff --git a/keymaster/valgrind.supp b/keymaster/valgrind.supp
new file mode 100644
index 0000000..2838278
--- /dev/null
+++ b/keymaster/valgrind.supp
@@ -0,0 +1,40 @@
+{
+ BoringSSLErrorLeak
+ Memcheck:Leak
+ fun:malloc
+ ...
+ fun:err_get_state
+ ...
+}
+{
+ EcKeyErrorLeak
+ Memcheck:Leak
+ fun:malloc
+ fun:err_add_error_vdata
+ fun:ERR_add_error_data
+ fun:ASN1_item_ex_d2i
+ fun:ASN1_item_d2i
+ fun:d2i_EC_PRIVATEKEY
+ fun:d2i_ECPrivateKey
+ fun:old_ec_priv_decode
+ fun:d2i_PrivateKey
+ ...
+}
+{
+ BoringSSLGetNewIndexLeak1
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:malloc
+ ...
+ fun:CRYPTO_get_ex_new_index
+ ...
+}
+{
+ BoringSSLGetNewIndexLeak2
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:realloc
+ ...
+ fun:CRYPTO_get_ex_new_index
+ ...
+}
\ No newline at end of file