Fix clang-tidy performance warnings in keymaster.
am: 68ecd28e87

Change-Id: Id3789808369a9c71c92354d0f31889b8a61ad2d1
diff --git a/Android.mk b/Android.mk
index 233ed95..3e3a25b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -90,7 +90,7 @@
 # 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.
+# Ignore benign warnings for now.
 LOCAL_CLANG_CFLAGS += -Wno-error=unused-private-field
 LOCAL_MODULE_TAGS := optional
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
@@ -111,6 +111,7 @@
 	ecdsa_keymaster1_operation.cpp \
 	keymaster0_engine.cpp \
 	keymaster1_engine.cpp \
+	keymaster_configuration.cpp \
 	rsa_keymaster0_key.cpp \
 	rsa_keymaster1_key.cpp \
 	rsa_keymaster1_operation.cpp \
@@ -126,7 +127,7 @@
 # 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_SHARED_LIBRARIES := libkeymaster_messages libkeymaster1 liblog libcrypto libcutils
 LOCAL_MODULE_TAGS := optional
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
diff --git a/Makefile b/Makefile
index fc8a540..656c4e5 100644
--- a/Makefile
+++ b/Makefile
@@ -49,11 +49,11 @@
 endif
 
 LDFLAGS += $(ARCH_FLAGS)
-CPPFLAGS = $(INCLUDES) -g -O0 -MD -MP
+CPPFLAGS = $(INCLUDES) -g -O0 -MD -MP $(ARCH_FLAGS) -DKEYMASTER_UNIT_TEST_BUILD -DHOST_BUILD
 CXXFLAGS += -Wall -Werror -Wno-unused -Winit-self -Wpointer-arith -Wunused-parameter \
 	-Werror=sign-compare -Werror=return-type -fno-permissive \
 	-Wno-deprecated-declarations -fno-exceptions -DKEYMASTER_NAME_TAGS $(ARCH_FLAGS)
-CFLAGS += $(ARCH_FLAGS)
+CFLAGS += $(ARCH_FLAGS) -DKEYMASTER_UNIT_TEST_BUILD -DHOST_BUILD
 
 # Uncomment to enable debug logging.
 # CXXFLAGS += -DDEBUG
@@ -94,13 +94,15 @@
 	integrity_assured_key_blob.cpp \
 	iso18033kdf.cpp \
 	kdf.cpp \
-	kdf_test.cpp \
 	kdf1_test.cpp \
 	kdf2_test.cpp \
+	kdf_test.cpp \
 	key.cpp \
 	key_blob_test.cpp \
 	keymaster0_engine.cpp \
 	keymaster1_engine.cpp \
+	keymaster_configuration.cpp \
+	keymaster_configuration_test.cpp \
 	keymaster_enforcement.cpp \
 	keymaster_enforcement_test.cpp \
 	keymaster_tags.cpp \
@@ -137,10 +139,11 @@
 	ecies_kem_test \
 	hkdf_test \
 	hmac_test \
-	kdf_test \
 	kdf1_test \
 	kdf2_test \
+	kdf_test \
 	key_blob_test \
+	keymaster_configuration_test \
 	keymaster_enforcement_test \
 	nist_curve_key_exchange_test
 
@@ -191,6 +194,13 @@
 
 GTEST_OBJS = $(GTEST)/src/gtest-all.o gtest_main.o
 
+keymaster_configuration_test: keymaster_configuration_test.o \
+	authorization_set.o \
+	serializable.o \
+	logger.o \
+	keymaster_configuration.o \
+	$(GTEST_OBJS)
+
 hmac_test: hmac_test.o \
 	android_keymaster_test_utils.o \
 	android_keymaster_utils.o \
@@ -361,6 +371,7 @@
 
 attestation_record_test: attestation_record_test.o \
 	android_keymaster_test_utils.o \
+	android_keymaster_utils.o \
 	attestation_record.o \
 	authorization_set.o \
 	keymaster_tags.o \
diff --git a/android_keymaster.cpp b/android_keymaster.cpp
index 3a53394..aeb4f4d 100644
--- a/android_keymaster.cpp
+++ b/android_keymaster.cpp
@@ -38,10 +38,33 @@
 
 namespace keymaster {
 
+namespace {
+
 const uint8_t MAJOR_VER = 1;
 const uint8_t MINOR_VER = 1;
 const uint8_t SUBMINOR_VER = 0;
 
+keymaster_error_t CheckVersionInfo(const AuthorizationSet& tee_enforced,
+                                   const AuthorizationSet& sw_enforced,
+                                   const KeymasterContext& context) {
+    uint32_t os_version;
+    uint32_t os_patchlevel;
+    context.GetSystemVersion(&os_version, &os_patchlevel);
+
+    uint32_t key_os_patchlevel;
+    if (tee_enforced.GetTagValue(TAG_OS_PATCHLEVEL, &key_os_patchlevel) ||
+        sw_enforced.GetTagValue(TAG_OS_PATCHLEVEL, &key_os_patchlevel)) {
+        if (key_os_patchlevel < os_patchlevel)
+            return KM_ERROR_KEY_REQUIRES_UPGRADE;
+        else if (key_os_patchlevel > os_patchlevel)
+            return KM_ERROR_INVALID_KEY_BLOB;
+    }
+
+    return KM_ERROR_OK;
+}
+
+}  // anonymous namespace
+
 AndroidKeymaster::AndroidKeymaster(KeymasterContext* context, size_t operation_table_size)
     : context_(context), operation_table_(new OperationTable(operation_table_size)) {}
 
@@ -193,6 +216,8 @@
                                &key_material, &response->enforced, &response->unenforced);
     if (response->error != KM_ERROR_OK)
         return;
+
+    response->error = CheckVersionInfo(response->enforced, response->unenforced, *context_);
 }
 
 static KeyFactory* GetKeyFactory(const KeymasterContext& context,
@@ -381,6 +406,18 @@
                                                sw_enforced, &response->certificate_chain);
 }
 
+void AndroidKeymaster::UpgradeKey(const UpgradeKeyRequest& request, UpgradeKeyResponse* response) {
+    if (!response)
+        return;
+
+    KeymasterKeyBlob upgraded_key;
+    response->error = context_->UpgradeKeyBlob(KeymasterKeyBlob(request.key_blob),
+                                               request.upgrade_params, &upgraded_key);
+    if (response->error != KM_ERROR_OK)
+        return;
+    response->upgraded_key = upgraded_key.release();
+}
+
 void AndroidKeymaster::ImportKey(const ImportKeyRequest& request, ImportKeyResponse* response) {
     if (response == NULL)
         return;
@@ -429,6 +466,10 @@
     if (error != KM_ERROR_OK)
         return error;
 
+    error = CheckVersionInfo(*hw_enforced, *sw_enforced, *context_);
+    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)
diff --git a/android_keymaster_messages.cpp b/android_keymaster_messages.cpp
index 1b8f36e..83a1785 100644
--- a/android_keymaster_messages.cpp
+++ b/android_keymaster_messages.cpp
@@ -523,4 +523,42 @@
     return true;
 }
 
+UpgradeKeyRequest::~UpgradeKeyRequest() {
+    delete[] key_blob.key_material;
+}
+
+void UpgradeKeyRequest::SetKeyMaterial(const void* key_material, size_t length) {
+    set_key_blob(&key_blob, key_material, length);
+}
+
+size_t UpgradeKeyRequest::SerializedSize() const {
+    return key_blob_size(key_blob) + upgrade_params.SerializedSize();
+}
+
+uint8_t* UpgradeKeyRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
+    buf = serialize_key_blob(key_blob, buf, end);
+    return upgrade_params.Serialize(buf, end);
+}
+
+bool UpgradeKeyRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    return deserialize_key_blob(&key_blob, buf_ptr, end) &&
+           upgrade_params.Deserialize(buf_ptr, end);
+}
+
+UpgradeKeyResponse::~UpgradeKeyResponse() {
+    delete[] upgraded_key.key_material;
+}
+
+size_t UpgradeKeyResponse::NonErrorSerializedSize() const {
+    return key_blob_size(upgraded_key);
+}
+
+uint8_t* UpgradeKeyResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
+    return serialize_key_blob(upgraded_key, buf, end);
+}
+
+bool UpgradeKeyResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+    return deserialize_key_blob(&upgraded_key, buf_ptr, end);
+}
+
 }  // namespace keymaster
diff --git a/android_keymaster_messages_test.cpp b/android_keymaster_messages_test.cpp
index 1ec5894..9207df2 100644
--- a/android_keymaster_messages_test.cpp
+++ b/android_keymaster_messages_test.cpp
@@ -578,6 +578,34 @@
     }
 }
 
+TEST(RoundTrip, UpgradeKeyRequest) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        UpgradeKeyRequest msg(ver);
+        msg.SetKeyMaterial("foo", 3);
+        msg.upgrade_params.Reinitialize(params, array_length(params));
+
+        UniquePtr<UpgradeKeyRequest> 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.upgrade_params, deserialized->upgrade_params);
+    }
+}
+
+TEST(RoundTrip, UpgradeKeyResponse) {
+    for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+        UpgradeKeyResponse req(ver);
+        req.error = KM_ERROR_OK;
+        req.upgraded_key.key_material = dup_array(TEST_DATA);
+        req.upgraded_key.key_material_size = array_length(TEST_DATA);
+
+        UniquePtr<UpgradeKeyResponse> deserialized(round_trip(ver, req, 19));
+        EXPECT_EQ(KM_ERROR_OK, deserialized->error);
+        EXPECT_EQ(req.upgraded_key.key_material_size, deserialized->upgraded_key.key_material_size);
+        EXPECT_EQ(0, memcmp(req.upgraded_key.key_material, deserialized->upgraded_key.key_material,
+                            req.upgraded_key.key_material_size));
+    }
+}
+
 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,
@@ -672,6 +700,8 @@
 GARBAGE_TEST(UpdateOperationResponse);
 GARBAGE_TEST(AttestKeyRequest);
 GARBAGE_TEST(AttestKeyResponse);
+GARBAGE_TEST(UpgradeKeyRequest);
+GARBAGE_TEST(UpgradeKeyResponse);
 
 // The macro doesn't work on this one.
 TEST(GarbageTest, SupportedResponse) {
diff --git a/android_keymaster_test.cpp b/android_keymaster_test.cpp
index ddc9783..ce85316 100644
--- a/android_keymaster_test.cpp
+++ b/android_keymaster_test.cpp
@@ -50,6 +50,9 @@
 namespace keymaster {
 namespace test {
 
+const uint32_t kOsVersion = 060000;
+const uint32_t kOsPatchLevel = 201603;
+
 StdoutLogger logger;
 
 template <typename T> vector<T> make_vector(const T* array, size_t len) {
@@ -90,18 +93,28 @@
 };
 
 /**
- * Test instance creator that builds a pure software keymaster1 implementations.
+ * Test instance creator that builds a pure software keymaster2 implementation.
  */
 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);
+        context_ = new TestKeymasterContext;
+        SoftKeymasterDevice* device = new SoftKeymasterDevice(context_);
+        AuthorizationSet version_info(AuthorizationSetBuilder()
+                                          .Authorization(TAG_OS_VERSION, kOsVersion)
+                                          .Authorization(TAG_OS_PATCHLEVEL, kOsPatchLevel));
+        device->keymaster2_device()->configure(device->keymaster2_device(), &version_info);
         return device->keymaster2_device();
     }
 
     bool algorithm_in_km0_hardware(keymaster_algorithm_t) const override { return false; }
     int keymaster0_calls() const override { return 0; }
+    bool is_keymaster1_hw() const override { return false; }
+    KeymasterContext* keymaster_context() const override { return context_; }
+
+  private:
+    mutable TestKeymasterContext* context_;
 };
 
 /**
@@ -130,8 +143,13 @@
 
         counting_keymaster0_device_ = new Keymaster0CountingWrapper(keymaster0_device);
 
-        SoftKeymasterDevice* keymaster = new SoftKeymasterDevice(new TestKeymasterContext);
+        context_ = new TestKeymasterContext;
+        SoftKeymasterDevice* keymaster = new SoftKeymasterDevice(context_);
         keymaster->SetHardwareDevice(counting_keymaster0_device_);
+        AuthorizationSet version_info(AuthorizationSetBuilder()
+                                          .Authorization(TAG_OS_VERSION, kOsVersion)
+                                          .Authorization(TAG_OS_PATCHLEVEL, kOsPatchLevel));
+        keymaster->keymaster2_device()->configure(keymaster->keymaster2_device(), &version_info);
         return keymaster->keymaster2_device();
     }
 
@@ -146,8 +164,11 @@
         }
     }
     int keymaster0_calls() const override { return counting_keymaster0_device_->count(); }
+    bool is_keymaster1_hw() const override { return false; }
+    KeymasterContext* keymaster_context() const override { return context_; }
 
   private:
+    mutable TestKeymasterContext* context_;
     mutable Keymaster0CountingWrapper* counting_keymaster0_device_;
     bool support_ec_;
 };
@@ -156,7 +177,7 @@
  * Test instance creator that builds a SoftKeymasterDevice which wraps a fake hardware keymaster1
  * instance, with minimal digest support.
  */
-class Sha256OnlyKeymaster1TestInstanceCreator : public Keymaster2TestInstanceCreator {
+class Sha256OnlyKeymaster2TestInstanceCreator : public Keymaster2TestInstanceCreator {
     keymaster2_device_t* CreateDevice() const {
         std::cerr << "Creating keymaster1-backed device that supports only SHA256";
 
@@ -165,22 +186,32 @@
             (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);
+        context_ = new TestKeymasterContext;
+        SoftKeymasterDevice* device = new SoftKeymasterDevice(context_);
         device->SetHardwareDevice(fake_device);
 
+        AuthorizationSet version_info(AuthorizationSetBuilder()
+                                          .Authorization(TAG_OS_VERSION, kOsVersion)
+                                          .Authorization(TAG_OS_PATCHLEVEL, kOsPatchLevel));
+        device->keymaster2_device()->configure(device->keymaster2_device(), &version_info);
         return device->keymaster2_device();
     }
 
     bool algorithm_in_km0_hardware(keymaster_algorithm_t) const override { return false; }
     int keymaster0_calls() const override { return 0; }
     int minimal_digest_set() const override { return true; }
+    bool is_keymaster1_hw() const override { return true; }
+    KeymasterContext* keymaster_context() const override { return context_; }
+
+  private:
+    mutable TestKeymasterContext* context_;
 };
 
 static auto test_params = testing::Values(
     InstanceCreatorPtr(new SoftKeymasterTestInstanceCreator),
     InstanceCreatorPtr(new Keymaster0AdapterTestInstanceCreator(true /* support_ec */)),
     InstanceCreatorPtr(new Keymaster0AdapterTestInstanceCreator(false /* support_ec */)),
-    InstanceCreatorPtr(new Sha256OnlyKeymaster1TestInstanceCreator));
+    InstanceCreatorPtr(new Sha256OnlyKeymaster2TestInstanceCreator));
 
 class NewKeyGeneration : public Keymaster2Test {
   protected:
@@ -206,6 +237,16 @@
 
         // Now check that unspecified, defaulted tags are correct.
         EXPECT_TRUE(contains(auths, KM_TAG_CREATION_DATETIME));
+        if (GetParam()->is_keymaster1_hw()) {
+            // If the underlying (faked) HW is KM1, it will not have version info.
+            EXPECT_FALSE(auths.Contains(TAG_OS_VERSION));
+            EXPECT_FALSE(auths.Contains(TAG_OS_PATCHLEVEL));
+        } else {
+            // In all othe cases; SoftKeymasterDevice keys, or keymaster0 keys wrapped by
+            // SoftKeymasterDevice, version information will be present and up to date.
+            EXPECT_TRUE(contains(auths, TAG_OS_VERSION, kOsVersion));
+            EXPECT_TRUE(contains(auths, TAG_OS_PATCHLEVEL, kOsPatchLevel));
+        }
     }
 };
 INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, NewKeyGeneration, test_params);
@@ -293,17 +334,17 @@
 }
 
 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)));
+    ASSERT_EQ(KM_ERROR_UNSUPPORTED_KEY_SIZE,
+              GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(190).Digest(KM_DIGEST_NONE)));
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
 
-    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
-        EXPECT_EQ(1, GetParam()->keymaster0_calls());
+TEST_P(NewKeyGeneration, EcdsaMismatchKeySize) {
+    ASSERT_EQ(KM_ERROR_INVALID_ARGUMENT,
+              GenerateKey(AuthorizationSetBuilder()
+                              .EcdsaSigningKey(224)
+                              .Authorization(TAG_EC_CURVE, KM_EC_CURVE_P_256)
+                              .Digest(KM_DIGEST_NONE)));
 }
 
 TEST_P(NewKeyGeneration, EcdsaAllValidSizes) {
@@ -413,7 +454,7 @@
 
 TEST_P(SigningOperationsTest, RsaPssSha256Success) {
     ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
-                                           .RsaSigningKey(512, 3)
+                                           .RsaSigningKey(768, 3)
                                            .Digest(KM_DIGEST_SHA_2_256)
                                            .Padding(KM_PAD_RSA_PSS)));
     // Use large message, which won't work without digesting.
@@ -1127,7 +1168,7 @@
 
 TEST_P(VerificationOperationsTest, RsaPssSha256Success) {
     ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
-                                           .RsaSigningKey(512, 3)
+                                           .RsaSigningKey(768, 3)
                                            .Digest(KM_DIGEST_SHA_2_256)
                                            .Padding(KM_PAD_RSA_PSS)));
     // Use large message, which won't work without digesting.
@@ -1178,7 +1219,7 @@
 
 TEST_P(VerificationOperationsTest, RsaPssSha256CorruptSignature) {
     GenerateKey(AuthorizationSetBuilder()
-                    .RsaSigningKey(512, 3)
+                    .RsaSigningKey(768, 3)
                     .Digest(KM_DIGEST_SHA_2_256)
                     .Padding(KM_PAD_RSA_PSS));
     string message(1024, 'a');
@@ -1203,7 +1244,7 @@
 
 TEST_P(VerificationOperationsTest, RsaPssSha256CorruptInput) {
     ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
-                                           .RsaSigningKey(512, 3)
+                                           .RsaSigningKey(768, 3)
                                            .Digest(KM_DIGEST_SHA_2_256)
                                            .Padding(KM_PAD_RSA_PSS)));
     // Use large message, which won't work without digesting.
@@ -1395,7 +1436,7 @@
                     key_bits = digest_bits + 8 * (11 + 19);
                     break;
                 case KM_PAD_RSA_PSS:
-                    key_bits = digest_bits + 22 * 8;
+                    key_bits = digest_bits * 2 + 2 * 8;
                     break;
                 default:
                     FAIL() << "Missing padding";
@@ -3500,8 +3541,11 @@
     return attest_rec;
 }
 
-static bool verify_attestation_record(AuthorizationSet expected_sw_enforced,
+static bool verify_attestation_record(const string& challenge,
+                                      AuthorizationSet expected_sw_enforced,
                                       AuthorizationSet expected_tee_enforced,
+                                      uint32_t expected_keymaster_version,
+                                      keymaster_security_level_t expected_keymaster_security_level,
                                       const keymaster_blob_t& attestation_cert) {
 
     X509_Ptr cert(parse_cert_blob(attestation_cert));
@@ -3516,10 +3560,27 @@
 
     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));
+    uint32_t att_attestation_version;
+    uint32_t att_keymaster_version;
+    keymaster_security_level_t att_attestation_security_level;
+    keymaster_security_level_t att_keymaster_security_level;
+    keymaster_blob_t att_challenge = {};
+    keymaster_blob_t att_unique_id = {};
+    EXPECT_EQ(KM_ERROR_OK, parse_attestation_record(
+                               attest_rec->data, attest_rec->length, &att_attestation_version,
+                               &att_attestation_security_level, &att_keymaster_version,
+                               &att_keymaster_security_level, &att_challenge, &att_sw_enforced,
+                               &att_tee_enforced, &att_unique_id));
 
-    // Add TAG_USER_ID to the attestation sw-enforced list, because user IDs are not included in
+    EXPECT_EQ(1U, att_attestation_version);
+    EXPECT_EQ(KM_SECURITY_LEVEL_SOFTWARE, att_attestation_security_level);
+    EXPECT_EQ(expected_keymaster_version, att_keymaster_version);
+    EXPECT_EQ(expected_keymaster_security_level, att_keymaster_security_level);
+
+    EXPECT_EQ(challenge.length(), att_challenge.data_length);
+    EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data, challenge.length()));
+
+    // Add TAG_USER_ID to the relevant attestation 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))
@@ -3527,6 +3588,13 @@
     if (expected_tee_enforced.GetTagValue(TAG_USER_ID, &user_id))
         att_tee_enforced.push_back(TAG_USER_ID, user_id);
 
+    // Add TAG_INCLUDE_UNIQUE_ID to the relevant attestation list, because that tag is not included
+    // in the attestation.
+    if (expected_sw_enforced.GetTagValue(TAG_INCLUDE_UNIQUE_ID))
+        att_sw_enforced.push_back(TAG_INCLUDE_UNIQUE_ID);
+    if (expected_tee_enforced.GetTagValue(TAG_INCLUDE_UNIQUE_ID))
+        att_tee_enforced.push_back(TAG_INCLUDE_UNIQUE_ID);
+
     att_sw_enforced.Sort();
     expected_sw_enforced.Sort();
     EXPECT_EQ(expected_sw_enforced, att_sw_enforced);
@@ -3538,36 +3606,206 @@
     return true;
 }
 
-TEST_P(AttestationTest, RsaSignedWithRsa) {
+TEST_P(AttestationTest, RsaAttestation) {
     ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
                                            .RsaSigningKey(256, 3)
                                            .Digest(KM_DIGEST_NONE)
-                                           .Padding(KM_PAD_NONE)));
+                                           .Padding(KM_PAD_NONE)
+                                           .Authorization(TAG_INCLUDE_UNIQUE_ID)));
 
     keymaster_cert_chain_t cert_chain;
-    EXPECT_EQ(KM_ERROR_OK, AttestKey(KM_ALGORITHM_RSA, &cert_chain));
+    EXPECT_EQ(KM_ERROR_OK, AttestKey("challenge", &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]));
+
+    uint32_t expected_keymaster_version;
+    keymaster_security_level_t expected_keymaster_security_level;
+    // TODO(swillden): Add a test KM1 that claims to be hardware.
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) {
+        expected_keymaster_version = 0;
+        expected_keymaster_security_level = KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
+    } else {
+        expected_keymaster_version = 2;
+        expected_keymaster_security_level = KM_SECURITY_LEVEL_SOFTWARE;
+    }
+
+    EXPECT_TRUE(verify_attestation_record(
+        "challenge", sw_enforced(), hw_enforced(), expected_keymaster_version,
+        expected_keymaster_security_level, 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)));
+TEST_P(AttestationTest, EcAttestation) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(
+                               KM_DIGEST_SHA_2_256)));
+
+    uint32_t expected_keymaster_version;
+    keymaster_security_level_t expected_keymaster_security_level;
+    // TODO(swillden): Add a test KM1 that claims to be hardware.
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) {
+        expected_keymaster_version = 0;
+        expected_keymaster_security_level = KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
+    } else {
+        expected_keymaster_version = 2;
+        expected_keymaster_security_level = KM_SECURITY_LEVEL_SOFTWARE;
+    }
 
     keymaster_cert_chain_t cert_chain;
-    EXPECT_EQ(KM_ERROR_OK, AttestKey(KM_ALGORITHM_EC, &cert_chain));
+    EXPECT_EQ(KM_ERROR_OK, AttestKey("challenge", &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]));
+    EXPECT_TRUE(verify_attestation_record(
+        "challenge", sw_enforced(), hw_enforced(), expected_keymaster_version,
+        expected_keymaster_security_level, cert_chain.entries[0]));
 
     keymaster_free_cert_chain(&cert_chain);
 }
 
+typedef Keymaster2Test KeyUpgradeTest;
+INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, KeyUpgradeTest, test_params);
+
+TEST_P(KeyUpgradeTest, AesVersionUpgrade) {
+    GetParam()->keymaster_context()->SetSystemVersion(1, 1);
+
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+                                           .AesEncryptionKey(128)
+                                           .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB)
+                                           .Padding(KM_PAD_NONE)));
+
+    // Key should operate fine.
+    string message = "1234567890123456";
+    string ciphertext = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
+    EXPECT_EQ(message, DecryptMessage(ciphertext, KM_MODE_ECB, KM_PAD_NONE));
+
+    // Increase patch level.  Key usage should fail with KM_ERROR_KEY_REQUIRES_UPGRADE.
+    GetParam()->keymaster_context()->SetSystemVersion(1, 2);
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB);
+    begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    if (GetParam()->is_keymaster1_hw()) {
+        // Keymaster1 hardware can't support version binding.  The key will work regardless
+        // of system version.  Just abort the remainder of the test.
+        EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+        EXPECT_EQ(KM_ERROR_OK, AbortOperation());
+        return;
+    }
+    EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+
+    // Getting characteristics should also fail
+    EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, GetCharacteristics());
+
+    // Upgrade key.
+    EXPECT_EQ(KM_ERROR_OK, UpgradeKey(client_params()));
+
+    // Key should work again
+    ciphertext = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
+    EXPECT_EQ(message, DecryptMessage(ciphertext, KM_MODE_ECB, KM_PAD_NONE));
+
+    // Decrease patch level.  Key usage should fail with KM_ERROR_INVALID_KEY_BLOB.
+    GetParam()->keymaster_context()->SetSystemVersion(1, 1);
+    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, GetCharacteristics());
+
+    // Upgrade should fail
+    EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, UpgradeKey(client_params()));
+
+    EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(KeyUpgradeTest, RsaVersionUpgrade) {
+    GetParam()->keymaster_context()->SetSystemVersion(1, 1);
+
+    ASSERT_EQ(KM_ERROR_OK,
+              GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(128, 3).Padding(KM_PAD_NONE)));
+
+    // Key should operate fine.
+    string message = "1234567890123456";
+    string ciphertext = EncryptMessage(message, KM_PAD_NONE);
+    EXPECT_EQ(message, DecryptMessage(ciphertext, KM_PAD_NONE));
+
+    // Increase patch level.  Key usage should fail with KM_ERROR_KEY_REQUIRES_UPGRADE.
+    GetParam()->keymaster_context()->SetSystemVersion(1, 2);
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+    if (GetParam()->is_keymaster1_hw()) {
+        // Keymaster1 hardware can't support version binding.  The key will work regardless
+        // of system version.  Just abort the remainder of the test.
+        EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+        EXPECT_EQ(KM_ERROR_OK, AbortOperation());
+        return;
+    }
+    EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+
+    // Getting characteristics should also fail
+    EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, GetCharacteristics());
+
+    // Upgrade key.
+    EXPECT_EQ(KM_ERROR_OK, UpgradeKey(client_params()));
+
+    // Key should work again
+    ciphertext = EncryptMessage(message, KM_PAD_NONE);
+    EXPECT_EQ(message, DecryptMessage(ciphertext, KM_PAD_NONE));
+
+    // Decrease patch level.  Key usage should fail with KM_ERROR_INVALID_KEY_BLOB.
+    GetParam()->keymaster_context()->SetSystemVersion(1, 1);
+    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, GetCharacteristics());
+
+    // Upgrade should fail
+    EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, UpgradeKey(client_params()));
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+        EXPECT_EQ(7, GetParam()->keymaster0_calls());
+}
+
+TEST_P(KeyUpgradeTest, EcVersionUpgrade) {
+    GetParam()->keymaster_context()->SetSystemVersion(1, 1);
+
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(
+                               KM_DIGEST_SHA_2_256)));
+
+    // Key should operate fine.
+    string message = "1234567890123456";
+    string signature;
+    SignMessage(message, &signature, KM_DIGEST_SHA_2_256);
+    VerifyMessage(message, signature, KM_DIGEST_SHA_2_256);
+
+    // Increase patch level.  Key usage should fail with KM_ERROR_KEY_REQUIRES_UPGRADE.
+    GetParam()->keymaster_context()->SetSystemVersion(1, 2);
+    AuthorizationSet begin_params(client_params());
+    begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
+    if (GetParam()->is_keymaster1_hw()) {
+        // Keymaster1 hardware can't support version binding.  The key will work regardless
+        // of system version.  Just abort the remainder of the test.
+        EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_SIGN, begin_params));
+        EXPECT_EQ(KM_ERROR_OK, AbortOperation());
+        return;
+    }
+    EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, BeginOperation(KM_PURPOSE_SIGN, begin_params));
+
+    // Getting characteristics should also fail
+    EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, GetCharacteristics());
+
+    // Upgrade key.
+    EXPECT_EQ(KM_ERROR_OK, UpgradeKey(client_params()));
+
+    // Key should work again
+    SignMessage(message, &signature, KM_DIGEST_SHA_2_256);
+    VerifyMessage(message, signature, KM_DIGEST_SHA_2_256);
+
+    // Decrease patch level.  Key usage should fail with KM_ERROR_INVALID_KEY_BLOB.
+    GetParam()->keymaster_context()->SetSystemVersion(1, 1);
+    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, GetCharacteristics());
+
+    // Upgrade should fail
+    EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, UpgradeKey(client_params()));
+
+    if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
+        EXPECT_EQ(7, GetParam()->keymaster0_calls());
+}
+
 TEST(SoftKeymasterWrapperTest, CheckKeymaster2Device) {
     // Make a good fake device, and wrap it.
     SoftKeymasterDevice* good_fake(new SoftKeymasterDevice(new TestKeymasterContext));
diff --git a/android_keymaster_test_utils.cpp b/android_keymaster_test_utils.cpp
index 346421a..ecaee62 100644
--- a/android_keymaster_test_utils.cpp
+++ b/android_keymaster_test_utils.cpp
@@ -328,15 +328,27 @@
     return device()->abort(device(), op_handle_);
 }
 
-keymaster_error_t Keymaster2Test::AttestKey(keymaster_algorithm_t algorithm,
+keymaster_error_t Keymaster2Test::AttestKey(const string& attest_challenge,
                                             keymaster_cert_chain_t* cert_chain) {
-    AuthorizationSet attest_params(
-        AuthorizationSetBuilder().Authorization(TAG_ALGORITHM, algorithm));
+    AuthorizationSet attest_params;
     attest_params.push_back(UserAuthParams());
     attest_params.push_back(ClientParams());
+    attest_params.push_back(TAG_ATTESTATION_CHALLENGE, attest_challenge.data(),
+                            attest_challenge.length());
     return device()->attest_key(device(), &blob_, &attest_params, cert_chain);
 }
 
+keymaster_error_t Keymaster2Test::UpgradeKey(const AuthorizationSet& upgrade_params) {
+    keymaster_key_blob_t upgraded_blob;
+    keymaster_error_t error =
+        device()->upgrade_key(device(), &blob_, &upgrade_params, &upgraded_blob);
+    if (error == KM_ERROR_OK) {
+        FreeKeyBlob();
+        blob_ = upgraded_blob;
+    }
+    return error;
+}
+
 string Keymaster2Test::ProcessMessage(keymaster_purpose_t purpose, const string& message) {
     EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose, client_params(), NULL /* output_params */));
 
diff --git a/android_keymaster_test_utils.h b/android_keymaster_test_utils.h
index 7a4d35e..25d4cf5 100644
--- a/android_keymaster_test_utils.h
+++ b/android_keymaster_test_utils.h
@@ -35,8 +35,10 @@
 #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/keymaster_context.h>
 #include <keymaster/logger.h>
 
 std::ostream& operator<<(std::ostream& os, const keymaster_key_param_t& param);
@@ -162,6 +164,8 @@
     virtual bool algorithm_in_km0_hardware(keymaster_algorithm_t algorithm) const = 0;
     virtual int keymaster0_calls() const = 0;
     virtual int minimal_digest_set() const { return false; }
+    virtual bool is_keymaster1_hw() const = 0;
+    virtual KeymasterContext* keymaster_context() const = 0;
 };
 
 // Use a shared_ptr because it's copyable.
@@ -208,7 +212,9 @@
 
     keymaster_error_t AbortOperation();
 
-    keymaster_error_t AttestKey(keymaster_algorithm_t algorithm, keymaster_cert_chain_t* chain);
+    keymaster_error_t AttestKey(const std::string& attest_challenge, keymaster_cert_chain_t* chain);
+
+    keymaster_error_t UpgradeKey(const AuthorizationSet& upgrade_params);
 
     keymaster_error_t GetVersion(uint8_t* major, uint8_t* minor, uint8_t* subminor);
 
diff --git a/android_keymaster_utils.cpp b/android_keymaster_utils.cpp
index 053e72a..5e92745 100644
--- a/android_keymaster_utils.cpp
+++ b/android_keymaster_utils.cpp
@@ -42,4 +42,54 @@
     return result == 0 ? 0 : 1;
 }
 
+keymaster_error_t EcKeySizeToCurve(uint32_t key_size_bits, keymaster_ec_curve_t* curve) {
+    switch (key_size_bits) {
+    default:
+        return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+
+    case 224:
+        *curve = KM_EC_CURVE_P_224;
+        break;
+
+    case 256:
+        *curve = KM_EC_CURVE_P_256;
+        break;
+
+    case 384:
+        *curve = KM_EC_CURVE_P_384;
+        break;
+
+    case 521:
+        *curve = KM_EC_CURVE_P_521;
+        break;
+    }
+
+    return KM_ERROR_OK;
+}
+
+keymaster_error_t EcCurveToKeySize(keymaster_ec_curve_t curve, uint32_t* key_size_bits) {
+    switch (curve) {
+    default:
+        return KM_ERROR_UNSUPPORTED_EC_CURVE;
+
+    case KM_EC_CURVE_P_224:
+        *key_size_bits = 224;
+        break;
+
+    case KM_EC_CURVE_P_256:
+        *key_size_bits = 256;
+        break;
+
+    case KM_EC_CURVE_P_384:
+        *key_size_bits = 384;
+        break;
+
+    case KM_EC_CURVE_P_521:
+        *key_size_bits = 521;
+        break;
+    }
+
+    return KM_ERROR_OK;
+}
+
 }  // namespace keymaster
diff --git a/asymmetric_key.cpp b/asymmetric_key.cpp
index 02a7f15..782e87b 100644
--- a/asymmetric_key.cpp
+++ b/asymmetric_key.cpp
@@ -21,6 +21,7 @@
 #include <openssl/asn1.h>
 #include <openssl/stack.h>
 #include <openssl/x509.h>
+#include <openssl/x509v3.h>
 
 #include "attestation_record.h"
 #include "openssl_err.h"
@@ -28,6 +29,88 @@
 
 namespace keymaster {
 
+namespace {
+
+constexpr int kDigitalSignatureKeyUsageBit = 0;
+constexpr int kKeyEnciphermentKeyUsageBit = 2;
+constexpr int kDataEnciphermentKeyUsageBit = 3;
+constexpr int kMaxKeyUsageBit = 8;
+
+template <typename T> T min(T a, T b) {
+    return (a < b) ? a : b;
+}
+
+static keymaster_error_t add_key_usage_extension(const AuthorizationSet& tee_enforced,
+                                                 const AuthorizationSet& sw_enforced,
+                                                 X509* certificate) {
+    // Build BIT_STRING with correct contents.
+    ASN1_BIT_STRING_Ptr key_usage(ASN1_BIT_STRING_new());
+
+    for (size_t i = 0; i <= kMaxKeyUsageBit; ++i) {
+        if (!ASN1_BIT_STRING_set_bit(key_usage.get(), i, 0)) {
+            return TranslateLastOpenSslError();
+        }
+    }
+
+    if (tee_enforced.Contains(TAG_PURPOSE, KM_PURPOSE_SIGN) ||
+        tee_enforced.Contains(TAG_PURPOSE, KM_PURPOSE_VERIFY) ||
+        sw_enforced.Contains(TAG_PURPOSE, KM_PURPOSE_SIGN) ||
+        sw_enforced.Contains(TAG_PURPOSE, KM_PURPOSE_VERIFY)) {
+        if (!ASN1_BIT_STRING_set_bit(key_usage.get(), kDigitalSignatureKeyUsageBit, 1)) {
+            return TranslateLastOpenSslError();
+        }
+    }
+
+    if (tee_enforced.Contains(TAG_PURPOSE, KM_PURPOSE_ENCRYPT) ||
+        tee_enforced.Contains(TAG_PURPOSE, KM_PURPOSE_DECRYPT) ||
+        sw_enforced.Contains(TAG_PURPOSE, KM_PURPOSE_ENCRYPT) ||
+        sw_enforced.Contains(TAG_PURPOSE, KM_PURPOSE_DECRYPT)) {
+        if (!ASN1_BIT_STRING_set_bit(key_usage.get(), kKeyEnciphermentKeyUsageBit, 1) ||
+            !ASN1_BIT_STRING_set_bit(key_usage.get(), kDataEnciphermentKeyUsageBit, 1)) {
+            return TranslateLastOpenSslError();
+        }
+    }
+
+    // Convert to octets
+    int len = i2d_ASN1_BIT_STRING(key_usage.get(), nullptr);
+    if (len < 0) {
+        return TranslateLastOpenSslError();
+    }
+    UniquePtr<uint8_t[]> asn1_key_usage(new uint8_t[len]);
+    if (!asn1_key_usage.get()) {
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    }
+    uint8_t* p = asn1_key_usage.get();
+    len = i2d_ASN1_BIT_STRING(key_usage.get(), &p);
+    if (len < 0) {
+        return TranslateLastOpenSslError();
+    }
+
+    // Build OCTET_STRING
+    ASN1_OCTET_STRING_Ptr key_usage_str(ASN1_OCTET_STRING_new());
+    if (!key_usage_str.get() ||
+        !ASN1_OCTET_STRING_set(key_usage_str.get(), asn1_key_usage.get(), len)) {
+        return TranslateLastOpenSslError();
+    }
+
+    X509_EXTENSION_Ptr key_usage_extension(X509_EXTENSION_create_by_NID(nullptr,        //
+                                                                        NID_key_usage,  //
+                                                                        false /* critical */,
+                                                                        key_usage_str.get()));
+    if (!key_usage_extension.get()) {
+        return TranslateLastOpenSslError();
+    }
+
+    if (!X509_add_ext(certificate, key_usage_extension.get() /* Don't release; copied */,
+                      -1 /* insert at end */)) {
+        return TranslateLastOpenSslError();
+    }
+
+    return KM_ERROR_OK;
+}
+
+}  // anonymous namespace
+
 keymaster_error_t AsymmetricKey::formatted_key_material(keymaster_key_format_t format,
                                                         UniquePtr<uint8_t[]>* material,
                                                         size_t* size) const {
@@ -59,8 +142,10 @@
     return KM_ERROR_OK;
 }
 
-static keymaster_error_t build_attestation_extension(const AuthorizationSet& tee_enforced,
+static keymaster_error_t build_attestation_extension(const AuthorizationSet& attest_params,
+                                                     const AuthorizationSet& tee_enforced,
                                                      const AuthorizationSet& sw_enforced,
+                                                     const KeymasterContext& context,
                                                      X509_EXTENSION_Ptr* extension) {
     ASN1_OBJECT_Ptr oid(
         OBJ_txt2obj(kAttestionRecordOid, 1 /* accept numerical dotted string form only */));
@@ -69,8 +154,8 @@
 
     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);
+    keymaster_error_t error = build_attestation_record(attest_params, sw_enforced, tee_enforced,
+                                                       context, &attest_bytes, &attest_bytes_len);
     if (error != KM_ERROR_OK)
         return error;
 
@@ -95,11 +180,14 @@
     return true;
 }
 
-static bool add_attestation_extension(const AuthorizationSet& tee_enforced,
-                                      const AuthorizationSet& sw_enforced, X509* certificate,
+static bool add_attestation_extension(const AuthorizationSet& attest_params,
+                                      const AuthorizationSet& tee_enforced,
+                                      const AuthorizationSet& sw_enforced,
+                                      const KeymasterContext& context, X509* certificate,
                                       keymaster_error_t* error) {
     X509_EXTENSION_Ptr attest_extension;
-    *error = build_attestation_extension(tee_enforced, sw_enforced, &attest_extension);
+    *error = build_attestation_extension(attest_params, tee_enforced, sw_enforced, context,
+                                         &attest_extension);
     if (*error != KM_ERROR_OK)
         return false;
 
@@ -162,7 +250,7 @@
         return false;
 
     chain->entries[0].data = nullptr;  // Leave empty for the leaf certificate.
-    chain->entries[0].data_length = 0;
+    chain->entries[1].data_length = 0;
 
     for (size_t i = 0; i < attest_key_chain->entry_count; ++i) {
         chain->entries[i + 1] = attest_key_chain->entries[i];
@@ -179,8 +267,11 @@
                                                      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))
+    if ((!sw_enforced.GetTagValue(TAG_ALGORITHM, &sign_algorithm) &&
+         !tee_enforced.GetTagValue(TAG_ALGORITHM, &sign_algorithm)))
+        return KM_ERROR_UNKNOWN_ERROR;
+
+    if ((sign_algorithm != KM_ALGORITHM_RSA && sign_algorithm != KM_ALGORITHM_EC))
         return KM_ERROR_INCOMPATIBLE_ALGORITHM;
 
     EVP_PKEY_Ptr pkey(EVP_PKEY_new());
@@ -195,50 +286,91 @@
         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 */) ||
+    if (!serialNumber.get() || !ASN1_INTEGER_set(serialNumber.get(), 1) ||
         !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  */))
+        !X509_NAME_add_entry_by_txt(issuerName.get(), "CN", MBSTRING_ASC,
+                                    reinterpret_cast<const uint8_t*>("Android Keymaster"),
+                                    -1 /* len */, -1 /* loc */, 0 /* set */) ||
+        !X509_set_issuer_name(certificate.get(), issuerName.get() /* Don't release; copied  */))
         return TranslateLastOpenSslError();
 
     X509_NAME_Ptr subjectName(X509_NAME_new());
     if (!subjectName.get() ||
+        !X509_NAME_add_entry_by_txt(subjectName.get(), "CN", MBSTRING_ASC,
+                                    reinterpret_cast<const uint8_t*>("A Keymaster Key"),
+                                    -1 /* len */, -1 /* loc */, 0 /* set */) ||
         !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) ||
+    uint64_t activeDateTime = 0;
+    authorizations().GetTagValue(TAG_ACTIVE_DATETIME, &activeDateTime);
+    if (!notBefore.get() || !ASN1_TIME_set(notBefore.get(), activeDateTime / 1000) ||
         !X509_set_notBefore(certificate.get(), notBefore.get() /* Don't release; copied */))
         return TranslateLastOpenSslError();
 
     ASN1_TIME_Ptr notAfter(ASN1_TIME_new());
-    if (!notAfter.get() || !ASN1_TIME_set(notAfter.get(), 10000) ||
+    uint64_t usageExpireDateTime = UINT64_MAX;
+    authorizations().GetTagValue(TAG_USAGE_EXPIRE_DATETIME, &usageExpireDateTime);
+    // TODO(swillden): When trusty can use the C++ standard library change the calculation of
+    // notAfterTime to use std::numeric_limits<time_t>::max(), rather than assuming that time_t is
+    // 32 bits.
+    time_t notAfterTime = min(static_cast<uint64_t>(UINT32_MAX), usageExpireDateTime / 1000);
+    if (!notAfter.get() || !ASN1_TIME_set(notAfter.get(), notAfterTime) ||
         !X509_set_notAfter(certificate.get(), notAfter.get() /* Don't release; copied */))
         return TranslateLastOpenSslError();
 
-    keymaster_error_t error = KM_ERROR_OK;
+    keymaster_error_t error = add_key_usage_extension(tee_enforced, sw_enforced, certificate.get());
+    if (error != KM_ERROR_OK) {
+        return error;
+    }
+
     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))
+        !add_attestation_extension(attest_params, tee_enforced, sw_enforced, context,
+                                   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;
 
+    // Copy subject key identifier from cert_chain->entries[1] as authority key_id.
+    if (cert_chain->entry_count < 2) {
+        // cert_chain must have at least two entries, one for the cert we're trying to create and
+        // one for the cert for the key that signs the new cert.
+        return KM_ERROR_UNKNOWN_ERROR;
+    }
+
+    const uint8_t* p = cert_chain->entries[1].data;
+    X509_Ptr signing_cert(d2i_X509(nullptr, &p, cert_chain->entries[1].data_length));
+    if (!signing_cert.get()) {
+        return TranslateLastOpenSslError();
+    }
+
+    UniquePtr<X509V3_CTX> x509v3_ctx(new X509V3_CTX);
+    *x509v3_ctx = {};
+    X509V3_set_ctx(x509v3_ctx.get(), signing_cert.get(), certificate.get(), nullptr /* req */,
+                   nullptr /* crl */, 0 /* flags */);
+
+    X509_EXTENSION_Ptr auth_key_id(X509V3_EXT_nconf_nid(nullptr /* conf */, x509v3_ctx.get(),
+                                                        NID_authority_key_identifier,
+                                                        const_cast<char*>("keyid:always")));
+    if (!auth_key_id.get() ||
+        !X509_add_ext(certificate.get(), auth_key_id.get() /* Don't release; copied */,
+                      -1 /* insert at end */)) {
+        return TranslateLastOpenSslError();
+    }
+
+    if (!X509_sign(certificate.get(), sign_key.get(), EVP_sha256()))
+        return TranslateLastOpenSslError();
+
     return get_certificate_blob(certificate.get(), &cert_chain->entries[0]);
 }
 
diff --git a/attestation_record.cpp b/attestation_record.cpp
index 809f7c8..8aed9ad 100644
--- a/attestation_record.cpp
+++ b/attestation_record.cpp
@@ -23,8 +23,33 @@
 #include "openssl_err.h"
 #include "openssl_utils.h"
 
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/keymaster_context.h>
+
 namespace keymaster {
 
+namespace {
+
+bool Uint64ToBignum(uint64_t value, BIGNUM* bn) {
+    static_assert(sizeof(unsigned long) == sizeof(uint64_t) ||
+                      sizeof(unsigned long) == sizeof(uint32_t),
+                  "Only 32 and 64-bit platforms supported");
+
+    if (sizeof(unsigned long) == sizeof(uint64_t)) {
+        return BN_set_word(bn, value);
+    } else if (sizeof(unsigned long) == sizeof(uint32_t)) {
+        uint32_t low_order = value & 0xFFFFFFFF;
+        uint32_t high_order = value >> 32;
+        return BN_set_word(bn, high_order) &&  //
+               BN_lshift(bn, bn, 32) &&        //
+               BN_add_word(bn, low_order);
+    } else {
+        return false;
+    }
+}
+
+}  // anonymous namespace
+
 struct stack_st_ASN1_TYPE_Delete {
     void operator()(stack_st_ASN1_TYPE* p) { sk_ASN1_TYPE_free(p); }
 };
@@ -41,14 +66,14 @@
 
 typedef struct km_root_of_trust {
     ASN1_OCTET_STRING* verified_boot_key;
-    ASN1_INTEGER* os_version;
-    ASN1_INTEGER* os_patchlevel;
+    ASN1_BOOLEAN* device_locked;
+    ASN1_ENUMERATED* verified_boot_state;
 } KM_ROOT_OF_TRUST;
 
 ASN1_SEQUENCE(KM_ROOT_OF_TRUST) = {
     ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_key, ASN1_OCTET_STRING),
-    ASN1_SIMPLE(KM_ROOT_OF_TRUST, os_version, ASN1_INTEGER),
-    ASN1_SIMPLE(KM_ROOT_OF_TRUST, os_patchlevel, ASN1_INTEGER),
+    ASN1_SIMPLE(KM_ROOT_OF_TRUST, device_locked, ASN1_BOOLEAN),
+    ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_state, ASN1_ENUMERATED),
 } ASN1_SEQUENCE_END(KM_ROOT_OF_TRUST);
 IMPLEMENT_ASN1_FUNCTIONS(KM_ROOT_OF_TRUST);
 
@@ -56,92 +81,78 @@
     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,
+    ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.masked_tag()),
+    ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.masked_tag()),
+    ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.masked_tag()),
+    ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, kdf, ASN1_INTEGER, TAG_KDF.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER,
                  TAG_RSA_PUBLIC_EXPONENT.masked_tag()),
-    ASN1_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,
+    ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER,
                  TAG_ORIGINATION_EXPIRE_DATETIME.masked_tag()),
-    ASN1_IMP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER,
+    ASN1_EXP_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,
+    ASN1_EXP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, allow_while_on_body, ASN1_NULL,
                  TAG_ALLOW_WHILE_ON_BODY.masked_tag()),
-    ASN1_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,
+    ASN1_EXP_OPT(KM_AUTH_LIST, all_applications, ASN1_NULL, TAG_ALL_APPLICATIONS.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, application_id, ASN1_OCTET_STRING, TAG_APPLICATION_ID.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER,
                  TAG_CREATION_DATETIME.masked_tag()),
-    ASN1_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_EXP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistant, ASN1_NULL, TAG_ROLLBACK_RESISTANT.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.masked_tag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.masked_tag()),
 } ASN1_SEQUENCE_END(KM_AUTH_LIST);
 IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST);
 
 typedef struct km_key_description {
+    ASN1_INTEGER* attestation_version;
+    ASN1_ENUMERATED* attestation_security_level;
+    ASN1_INTEGER* keymaster_version;
+    ASN1_ENUMERATED* keymaster_security_level;
+    ASN1_OCTET_STRING* attestation_challenge;
     KM_AUTH_LIST* software_enforced;
     KM_AUTH_LIST* tee_enforced;
+    ASN1_INTEGER* unique_id;
 } KM_KEY_DESCRIPTION;
 
 ASN1_SEQUENCE(KM_KEY_DESCRIPTION) = {
+    ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_version, ASN1_INTEGER),
+    ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_security_level, ASN1_ENUMERATED),
+    ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_version, ASN1_INTEGER),
+    ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_security_level, ASN1_ENUMERATED),
+    ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_challenge, ASN1_OCTET_STRING),
+    ASN1_SIMPLE(KM_KEY_DESCRIPTION, unique_id, ASN1_OCTET_STRING),
     ASN1_SIMPLE(KM_KEY_DESCRIPTION, software_enforced, KM_AUTH_LIST),
     ASN1_SIMPLE(KM_KEY_DESCRIPTION, tee_enforced, KM_AUTH_LIST),
 } ASN1_SEQUENCE_END(KM_KEY_DESCRIPTION);
@@ -198,9 +209,11 @@
 // 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);
 
+    if (auth_list.empty())
+        return KM_ERROR_OK;
+
     for (auto entry : auth_list) {
 
         ASN1_INTEGER_SET** integer_set = nullptr;
@@ -221,6 +234,19 @@
         case KM_TAG_USER_SECURE_ID:
         case KM_TAG_EXPORTABLE:
         case KM_TAG_RESET_SINCE_ID_ROTATION:
+        case KM_TAG_ATTESTATION_CHALLENGE:
+        case KM_TAG_BLOCK_MODE:
+        case KM_TAG_CALLER_NONCE:
+        case KM_TAG_MIN_MAC_LENGTH:
+        case KM_TAG_ECIES_SINGLE_HASH_MODE:
+        case KM_TAG_INCLUDE_UNIQUE_ID:
+        case KM_TAG_BLOB_USAGE_REQUIREMENTS:
+        case KM_TAG_BOOTLOADER_ONLY:
+        case KM_TAG_MIN_SECONDS_BETWEEN_OPS:
+        case KM_TAG_MAX_USES_PER_BOOT:
+        case KM_TAG_APPLICATION_DATA:
+        case KM_TAG_UNIQUE_ID:
+        case KM_TAG_ROOT_OF_TRUST:
             continue;
 
         /* Non-repeating enumerations */
@@ -230,9 +256,6 @@
         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;
@@ -244,9 +267,6 @@
         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;
@@ -261,18 +281,15 @@
         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;
+        case KM_TAG_OS_VERSION:
+            integer_ptr = &record->os_version;
+            break;
+        case KM_TAG_OS_PATCHLEVEL:
+            integer_ptr = &record->os_patchlevel;
+            break;
 
         /* Non-repeating long unsigned integers */
         case KM_TAG_RSA_PUBLIC_EXPONENT:
@@ -294,15 +311,6 @@
             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;
@@ -312,9 +320,6 @@
         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;
@@ -323,35 +328,6 @@
         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);
@@ -379,20 +355,22 @@
             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())
+            UniquePtr<BIGNUM, BIGNUM_Delete> bn_value(BN_new());
+            if (!bn_value.get())
                 return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
             if (type == KM_DATE) {
-                if (!BN_set_word(exponent.get(), entry.date_time))
+                if (!Uint64ToBignum(entry.date_time, bn_value.get())) {
                     return TranslateLastOpenSslError();
+                }
             } else {
-                if (!BN_set_word(exponent.get(), entry.long_integer))
+                if (!Uint64ToBignum(entry.long_integer, bn_value.get())) {
                     return TranslateLastOpenSslError();
+                }
             }
 
             UniquePtr<ASN1_INTEGER, ASN1_INTEGER_Delete> value(
-                BN_to_ASN1_INTEGER(exponent.get(), nullptr));
+                BN_to_ASN1_INTEGER(bn_value.get(), nullptr));
             if (!value.get())
                 return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
@@ -424,13 +402,36 @@
         }
     }
 
+    keymaster_ec_curve_t ec_curve;
+    uint32_t key_size;
+    if (auth_list.Contains(TAG_ALGORITHM, KM_ALGORITHM_EC) &&  //
+        !auth_list.Contains(TAG_EC_CURVE) &&                   //
+        auth_list.GetTagValue(TAG_KEY_SIZE, &key_size)) {
+        // This must be a keymaster1 key. It's an EC key with no curve.  Insert the curve.
+
+        keymaster_error_t error = EcKeySizeToCurve(key_size, &ec_curve);
+        if (error != KM_ERROR_OK)
+            return error;
+
+        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(), ec_curve))
+            return TranslateLastOpenSslError();
+
+        insert_integer(value.release(), &record->ec_curve, nullptr);
+    }
+
     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,
+keymaster_error_t build_attestation_record(const AuthorizationSet& attestation_params,
+                                           const AuthorizationSet& sw_enforced,
                                            const AuthorizationSet& tee_enforced,
+                                           const KeymasterContext& context,
                                            UniquePtr<uint8_t[]>* asn1_key_desc,
                                            size_t* asn1_key_desc_len) {
     assert(asn1_key_desc && asn1_key_desc_len);
@@ -439,15 +440,83 @@
     if (!key_desc.get())
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
 
-    keymaster_error_t error;
+    keymaster_security_level_t keymaster_security_level;
+    uint32_t keymaster_version = UINT32_MAX;
+    if (tee_enforced.empty()) {
+        // Software key.
+        keymaster_security_level = KM_SECURITY_LEVEL_SOFTWARE;
+        keymaster_version = 2;
+    } else {
+        keymaster_security_level = KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
+        switch (context.GetSecurityLevel()) {
+        case KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT:
+            // We're running in a TEE, so the key is KM2.
+            keymaster_version = 2;
+            break;
 
-    error = build_auth_list(sw_enforced, key_desc->software_enforced);
+        case KM_SECURITY_LEVEL_SOFTWARE:
+            // We're running in software, wrapping some KM hardware.  Is it KM0 or KM1?  KM1 keys
+            // have the purpose in the tee_enforced list.  It's possible that a key could be created
+            // without a purpose, which would fool this test into reporting it's a KM0 key.  That
+            // corner case doesn't matter much, because purpose-less keys are not usable anyway.
+            // Also, KM1 TEEs should disappear rapidly.
+            keymaster_version = tee_enforced.Contains(TAG_PURPOSE) ? 1 : 0;
+            break;
+        }
+
+        if (keymaster_version == UINT32_MAX)
+            return KM_ERROR_UNKNOWN_ERROR;
+    }
+
+    if (!ASN1_INTEGER_set(key_desc->attestation_version, 1) ||
+        !ASN1_ENUMERATED_set(key_desc->attestation_security_level, context.GetSecurityLevel()) ||
+        !ASN1_INTEGER_set(key_desc->keymaster_version, keymaster_version) ||
+        !ASN1_ENUMERATED_set(key_desc->keymaster_security_level, keymaster_security_level))
+        return TranslateLastOpenSslError();
+
+    keymaster_blob_t attestation_challenge = {nullptr, 0};
+    if (!attestation_params.GetTagValue(TAG_ATTESTATION_CHALLENGE, &attestation_challenge))
+        return KM_ERROR_ATTESTATION_CHALLENGE_MISSING;
+    if (!ASN1_OCTET_STRING_set(key_desc->attestation_challenge, attestation_challenge.data,
+                               attestation_challenge.data_length))
+        return TranslateLastOpenSslError();
+
+    keymaster_error_t 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;
 
+    // Only check tee_enforced for TAG_INCLUDE_UNIQUE_ID.  If we don't have hardware we can't
+    // generate unique IDs.
+    if (tee_enforced.GetTagValue(TAG_INCLUDE_UNIQUE_ID)) {
+        uint64_t creation_datetime;
+        // Only check sw_enforced for TAG_CREATION_DATETIME, since it shouldn't be in tee_enforced,
+        // since this implementation has no secure wall clock.
+        if (!sw_enforced.GetTagValue(TAG_CREATION_DATETIME, &creation_datetime)) {
+            LOG_E("Unique ID cannot be created without creation datetime", 0);
+            return KM_ERROR_INVALID_KEY_BLOB;
+        }
+
+        keymaster_blob_t application_id = {nullptr, 0};
+        sw_enforced.GetTagValue(TAG_APPLICATION_ID, &application_id);
+
+        Buffer unique_id;
+        error = context.GenerateUniqueId(
+            creation_datetime, application_id,
+            attestation_params.GetTagValue(TAG_RESET_SINCE_ID_ROTATION), &unique_id);
+        if (error != KM_ERROR_OK)
+            return error;
+
+        key_desc->unique_id = ASN1_OCTET_STRING_new();
+        if (!key_desc->unique_id ||
+            !ASN1_OCTET_STRING_set(key_desc->unique_id, unique_id.peek_read(),
+                                   unique_id.available_read()))
+            return TranslateLastOpenSslError();
+    }
+
     int len = i2d_KM_KEY_DESCRIPTION(key_desc.get(), nullptr);
     if (len < 0)
         return TranslateLastOpenSslError();
@@ -499,6 +568,9 @@
 // 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) {
+    if (!record)
+        return KM_ERROR_OK;
+
     // Purpose
     if (!get_repeated_enums(record->purpose, TAG_PURPOSE, auth_list))
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
@@ -511,10 +583,6 @@
     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;
@@ -523,15 +591,6 @@
     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;
@@ -540,18 +599,6 @@
     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;
@@ -565,17 +612,6 @@
     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;
@@ -599,12 +635,6 @@
                               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;
@@ -620,30 +650,56 @@
     // 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)
+        if (!rot->verified_boot_key)
             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;
+        // Other root of trust fields are not mapped to auth set entries.
     }
 
+    // OS Version
+    if (record->os_version &&
+        !auth_list->push_back(TAG_OS_VERSION, ASN1_INTEGER_get(record->os_version)))
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    // OS Patch level
+    if (record->os_patchlevel &&
+        !auth_list->push_back(TAG_OS_PATCHLEVEL, ASN1_INTEGER_get(record->os_patchlevel)))
+        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.
+// Parse the DER-encoded attestation record, placing the results in keymaster_version,
+// attestation_challenge, software_enforced, tee_enforced and unique_id.
 keymaster_error_t parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
+                                           uint32_t* attestation_version,  //
+                                           keymaster_security_level_t* attestation_security_level,
+                                           uint32_t* keymaster_version,
+                                           keymaster_security_level_t* keymaster_security_level,
+                                           keymaster_blob_t* attestation_challenge,
                                            AuthorizationSet* software_enforced,
-                                           AuthorizationSet* tee_enforced) {
+                                           AuthorizationSet* tee_enforced,
+                                           keymaster_blob_t* unique_id) {
     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();
 
+    *attestation_version = ASN1_INTEGER_get(record->attestation_version);
+    *attestation_security_level = static_cast<keymaster_security_level_t>(
+        ASN1_ENUMERATED_get(record->attestation_security_level));
+    *keymaster_version = ASN1_INTEGER_get(record->keymaster_version);
+    *keymaster_security_level = static_cast<keymaster_security_level_t>(
+        ASN1_ENUMERATED_get(record->keymaster_security_level));
+
+    attestation_challenge->data =
+        dup_buffer(record->attestation_challenge->data, record->attestation_challenge->length);
+    attestation_challenge->data_length = record->attestation_challenge->length;
+
+    unique_id->data = dup_buffer(record->unique_id->data, record->unique_id->length);
+    unique_id->data_length = record->unique_id->length;
+
     keymaster_error_t error = extract_auth_list(record->software_enforced, software_enforced);
     if (error != KM_ERROR_OK)
         return error;
diff --git a/attestation_record.h b/attestation_record.h
index 3cd5dde..64acabc 100644
--- a/attestation_record.h
+++ b/attestation_record.h
@@ -23,6 +23,8 @@
 
 namespace keymaster {
 
+class KeymasterContext;
+
 /**
  * The OID for Android attestation records.  For the curious, it breaks down as follows:
  *
@@ -39,14 +41,22 @@
  */
 static const char kAttestionRecordOid[] = "1.3.6.1.4.1.11129.2.1.17";
 
-keymaster_error_t build_attestation_record(const AuthorizationSet& software_enforced,
+keymaster_error_t build_attestation_record(const AuthorizationSet& attestation_params,
+                                           const AuthorizationSet& software_enforced,
                                            const AuthorizationSet& tee_enforced,
+                                           const KeymasterContext& context,
                                            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,
+                                           uint32_t* attestation_version,  //
+                                           keymaster_security_level_t* attestation_security_level,
+                                           uint32_t* keymaster_version,
+                                           keymaster_security_level_t* keymaster_security_level,
+                                           keymaster_blob_t* attestation_challenge,
                                            AuthorizationSet* software_enforced,
-                                           AuthorizationSet* tee_enforced);
+                                           AuthorizationSet* tee_enforced,
+                                           keymaster_blob_t* unique_id);
 }
 
 #endif  // SYSTEM_KEYMASTER_ATTESTATION_RECORD_H_
diff --git a/attestation_record_test.cpp b/attestation_record_test.cpp
index 21a7eee..1cf8630 100644
--- a/attestation_record_test.cpp
+++ b/attestation_record_test.cpp
@@ -18,18 +18,88 @@
 
 #include <gtest/gtest.h>
 
+#include <keymaster/keymaster_context.h>
+
 #include "android_keymaster_test_utils.h"
 #include "attestation_record.h"
 
+#include <keymaster/keymaster_context.h>
+
 namespace keymaster {
 namespace test {
 
+class TestContext : public KeymasterContext {
+  public:
+    keymaster_security_level_t GetSecurityLevel() const override {
+        return KM_SECURITY_LEVEL_SOFTWARE;
+    }
+    keymaster_error_t SetSystemVersion(uint32_t /* os_version */,
+                                       uint32_t /* os_patchlevel */) override {
+        return KM_ERROR_UNIMPLEMENTED;
+    }
+    void GetSystemVersion(uint32_t* os_version, uint32_t* os_patchlevel) const override {
+        *os_version = 0;
+        *os_patchlevel = 0;
+    }
+    KeyFactory* GetKeyFactory(keymaster_algorithm_t /* algorithm */) const override {
+        return nullptr;
+    }
+    OperationFactory* GetOperationFactory(keymaster_algorithm_t /* algorithm */,
+                                          keymaster_purpose_t /* purpose */) const override {
+        return nullptr;
+    }
+    keymaster_algorithm_t* GetSupportedAlgorithms(size_t* /* algorithms_count */) const override {
+        return nullptr;
+    }
+    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 override {
+        return KM_ERROR_UNIMPLEMENTED;
+    }
+    keymaster_error_t UpgradeKeyBlob(const KeymasterKeyBlob& /* key_to_upgrade */,
+                                     const AuthorizationSet& /* upgrade_params */,
+                                     KeymasterKeyBlob* /* upgraded_key */) const override {
+        return KM_ERROR_UNIMPLEMENTED;
+    }
+    keymaster_error_t ParseKeyBlob(const KeymasterKeyBlob& /* blob */,
+                                   const AuthorizationSet& /* additional_params */,
+                                   KeymasterKeyBlob* /* key_material */,
+                                   AuthorizationSet* /* hw_enforced */,
+                                   AuthorizationSet* /* sw_enforced */) const override {
+        return KM_ERROR_UNIMPLEMENTED;
+    }
+    keymaster_error_t AddRngEntropy(const uint8_t* /* buf */, size_t /* length */) const override {
+        return KM_ERROR_UNIMPLEMENTED;
+    }
+    keymaster_error_t GenerateRandom(uint8_t* /* buf */, size_t /* length */) const override {
+        return KM_ERROR_UNIMPLEMENTED;
+    }
+    KeymasterEnforcement* enforcement_policy() { return nullptr; }
+    EVP_PKEY* AttestationKey(keymaster_algorithm_t /* algorithm */,
+                             keymaster_error_t* /* error */) const override {
+        return nullptr;
+    }
+    keymaster_cert_chain_t* AttestationChain(keymaster_algorithm_t /* algorithm */,
+                                             keymaster_error_t* /* error */) const override {
+        return nullptr;
+    }
+    keymaster_error_t GenerateUniqueId(uint64_t /* creation_date_time */,
+                                       const keymaster_blob_t& /* application_id */,
+                                       bool /* reset_since_rotation */, Buffer* unique_id) const {
+        // Finally, the reason for defining this class:
+        unique_id->Reinitialize("foo", 3);
+        return KM_ERROR_OK;
+    }
+};
+
 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));
@@ -37,7 +107,10 @@
 
     UniquePtr<uint8_t[]> asn1;
     size_t asn1_len;
-    EXPECT_EQ(KM_ERROR_OK, build_attestation_record(sw_set, hw_set, &asn1, &asn1_len));
+    AuthorizationSet attest_params(
+        AuthorizationSetBuilder().Authorization(TAG_ATTESTATION_CHALLENGE, "hello", 5));
+    EXPECT_EQ(KM_ERROR_OK, build_attestation_record(attest_params, sw_set, hw_set, TestContext(),
+                                                    &asn1, &asn1_len));
     EXPECT_GT(asn1_len, 0U);
 
     std::ofstream output("attest.der",
@@ -48,8 +121,17 @@
 
     AuthorizationSet parsed_hw_set;
     AuthorizationSet parsed_sw_set;
+    uint32_t attestation_version;
+    uint32_t keymaster_version;
+    keymaster_security_level_t attestation_security_level;
+    keymaster_security_level_t keymaster_security_level;
+    keymaster_blob_t attestation_challenge = {};
+    keymaster_blob_t unique_id = {};
     EXPECT_EQ(KM_ERROR_OK,
-              parse_attestation_record(asn1.get(), asn1_len, &parsed_sw_set, &parsed_hw_set));
+              parse_attestation_record(asn1.get(), asn1_len, &attestation_version,
+                                       &attestation_security_level, &keymaster_version,
+                                       &keymaster_security_level, &attestation_challenge,
+                                       &parsed_sw_set, &parsed_hw_set, &unique_id));
 
     hw_set.Sort();
     sw_set.Sort();
diff --git a/authorization_set.cpp b/authorization_set.cpp
index 09093c9..9f6810d 100644
--- a/authorization_set.cpp
+++ b/authorization_set.cpp
@@ -103,6 +103,23 @@
     return true;
 }
 
+void AuthorizationSet::MoveFrom(AuthorizationSet& set) {
+    elems_ = set.elems_;
+    elems_size_ = set.elems_size_;
+    elems_capacity_ = set.elems_capacity_;
+    indirect_data_ = set.indirect_data_;
+    indirect_data_size_ = set.indirect_data_size_;
+    indirect_data_capacity_ = set.indirect_data_capacity_;
+    error_ = set.error_;
+    set.elems_ = nullptr;
+    set.elems_size_ = 0;
+    set.elems_capacity_ = 0;
+    set.indirect_data_ = nullptr;
+    set.indirect_data_size_ = 0;
+    set.indirect_data_capacity_ = 0;
+    set.error_ = OK;
+}
+
 bool AuthorizationSet::Reinitialize(const keymaster_key_param_t* elems, const size_t count) {
     FreeData();
 
@@ -196,8 +213,8 @@
         return i;
 }
 
-bool AuthorizationSet::erase(size_t index) {
-    if (index >= size())
+bool AuthorizationSet::erase(int index) {
+    if (index < 0 || index >= static_cast<int>(size()))
         return false;
 
     --elems_size_;
@@ -206,21 +223,21 @@
     return true;
 }
 
-keymaster_key_param_t empty_set = {KM_TAG_INVALID, {}};
+keymaster_key_param_t empty_param = {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;
+    empty_param = {KM_TAG_INVALID, {}};
+    return empty_param;
 }
 
 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;
+    empty_param = {KM_TAG_INVALID, {}};
+    return empty_param;
 }
 
 bool AuthorizationSet::push_back(const keymaster_key_param_set_t& set) {
@@ -613,4 +630,11 @@
     return false;
 }
 
+bool AuthorizationSet::ContainsIntValue(keymaster_tag_t tag, uint32_t value) const {
+    for (auto& entry : *this)
+        if (entry.tag == tag && entry.integer == value)
+            return true;
+    return false;
+}
+
 }  // namespace keymaster
diff --git a/ec_key_factory.cpp b/ec_key_factory.cpp
index 14c8327..36ec433 100644
--- a/ec_key_factory.cpp
+++ b/ec_key_factory.cpp
@@ -40,6 +40,37 @@
     }
 }
 
+/* static */
+keymaster_error_t EcKeyFactory::GetCurveAndSize(const AuthorizationSet& key_description,
+                                                keymaster_ec_curve_t* curve,
+                                                uint32_t* key_size_bits) {
+    if (!key_description.GetTagValue(TAG_EC_CURVE, curve)) {
+        // Curve not specified. Fall back to deducing curve from key size.
+        if (!key_description.GetTagValue(TAG_KEY_SIZE, key_size_bits)) {
+            LOG_E("%s", "No curve or key size specified for EC key generation");
+            return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+        }
+        keymaster_error_t error = EcKeySizeToCurve(*key_size_bits, curve);
+        if (error != KM_ERROR_OK) {
+            return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+        }
+    } else {
+        keymaster_error_t error = EcCurveToKeySize(*curve, key_size_bits);
+        if (error != KM_ERROR_OK) {
+            return error;
+        }
+        uint32_t tag_key_size_bits;
+        if (key_description.GetTagValue(TAG_KEY_SIZE, &tag_key_size_bits) &&
+            *key_size_bits != tag_key_size_bits) {
+            LOG_E("Curve key size %d and specified key size %d don't match", key_size_bits,
+                  tag_key_size_bits);
+            return KM_ERROR_INVALID_ARGUMENT;
+        }
+    }
+
+    return KM_ERROR_OK;
+}
+
 keymaster_error_t EcKeyFactory::GenerateKey(const AuthorizationSet& key_description,
                                             KeymasterKeyBlob* key_blob,
                                             AuthorizationSet* hw_enforced,
@@ -49,10 +80,15 @@
 
     AuthorizationSet authorizations(key_description);
 
+    keymaster_ec_curve_t ec_curve;
     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;
+    keymaster_error_t error = GetCurveAndSize(authorizations, &ec_curve, &key_size);
+    if (error != KM_ERROR_OK) {
+        return error;
+    } else if (!authorizations.Contains(TAG_KEY_SIZE, key_size)) {
+        authorizations.push_back(TAG_KEY_SIZE, key_size);
+    } else if (!authorizations.Contains(TAG_EC_CURVE, ec_curve)) {
+        authorizations.push_back(TAG_EC_CURVE, ec_curve);
     }
 
     UniquePtr<EC_KEY, EC_KEY_Delete> ec_key(EC_KEY_new());
@@ -60,9 +96,9 @@
     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));
+    UniquePtr<EC_GROUP, EC_GROUP_Delete> group(ChooseGroup(ec_curve));
     if (group.get() == NULL) {
-        LOG_E("Unable to get EC group for key of size %d", key_size);
+        LOG_E("Unable to get EC group for curve %d", ec_curve);
         return KM_ERROR_UNSUPPORTED_KEY_SIZE;
     }
 
@@ -80,7 +116,7 @@
         return TranslateLastOpenSslError();
 
     KeymasterKeyBlob key_material;
-    keymaster_error_t error = EvpKeyToKeyMaterial(pkey.get(), &key_material);
+    error = EvpKeyToKeyMaterial(pkey.get(), &key_material);
     if (error != KM_ERROR_OK)
         return error;
 
@@ -149,7 +185,7 @@
 }
 
 /* static */
-EC_GROUP* EcKeyFactory::choose_group(size_t key_size_bits) {
+EC_GROUP* EcKeyFactory::ChooseGroup(size_t key_size_bits) {
     switch (key_size_bits) {
     case 224:
         return EC_GROUP_new_by_curve_name(NID_secp224r1);
@@ -169,6 +205,27 @@
     }
 }
 
+/* static */
+EC_GROUP* EcKeyFactory::ChooseGroup(keymaster_ec_curve_t ec_curve) {
+    switch (ec_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;
+    }
+}
+
 keymaster_error_t EcKeyFactory::CreateEmptyKey(const AuthorizationSet& hw_enforced,
                                                const AuthorizationSet& sw_enforced,
                                                UniquePtr<AsymmetricKey>* key) const {
diff --git a/ec_keymaster0_key.cpp b/ec_keymaster0_key.cpp
index 705ee73..e11c887 100644
--- a/ec_keymaster0_key.cpp
+++ b/ec_keymaster0_key.cpp
@@ -43,10 +43,11 @@
     if (!engine_ || !engine_->supports_ec())
         return super::GenerateKey(key_description, key_blob, hw_enforced, sw_enforced);
 
+    keymaster_ec_curve_t ec_curve;
     uint32_t key_size;
-    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;
+    keymaster_error_t error = GetCurveAndSize(key_description, &ec_curve, &key_size);
+    if (error != KM_ERROR_OK) {
+        return error;
     }
 
     KeymasterKeyBlob key_material;
@@ -57,6 +58,7 @@
     // 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_EC_CURVE, ec_curve);
     hw_enforced->push_back(TAG_ORIGIN, KM_ORIGIN_UNKNOWN);
 
     return context_->CreateKeyBlob(key_description, KM_ORIGIN_UNKNOWN, key_material, key_blob,
diff --git a/include/keymaster/android_keymaster.h b/include/keymaster/android_keymaster.h
index c7ecfad..301703b 100644
--- a/include/keymaster/android_keymaster.h
+++ b/include/keymaster/android_keymaster.h
@@ -71,6 +71,7 @@
     void ImportKey(const ImportKeyRequest& request, ImportKeyResponse* response);
     void ExportKey(const ExportKeyRequest& request, ExportKeyResponse* response);
     void AttestKey(const AttestKeyRequest& request, AttestKeyResponse* response);
+    void UpgradeKey(const UpgradeKeyRequest& request, UpgradeKeyResponse* response);
     void DeleteKey(const DeleteKeyRequest& request, DeleteKeyResponse* response);
     void DeleteAllKeys(const DeleteAllKeysRequest& request, DeleteAllKeysResponse* response);
     void BeginOperation(const BeginOperationRequest& request, BeginOperationResponse* response);
diff --git a/include/keymaster/android_keymaster_messages.h b/include/keymaster/android_keymaster_messages.h
index 30d3fb7..3b8712f 100644
--- a/include/keymaster/android_keymaster_messages.h
+++ b/include/keymaster/android_keymaster_messages.h
@@ -45,6 +45,7 @@
     GET_SUPPORTED_EXPORT_FORMATS = 14,
     GET_KEY_CHARACTERISTICS = 15,
     ATTEST_KEY = 16,
+    UPGRADE_KEY = 17,
 };
 
 /**
@@ -129,8 +130,7 @@
 };
 
 struct SupportedByAlgorithmRequest : public KeymasterMessage {
-    explicit SupportedByAlgorithmRequest(int32_t ver = MAX_MESSAGE_VERSION)
-        : KeymasterMessage(ver) {}
+    explicit SupportedByAlgorithmRequest(int32_t ver) : KeymasterMessage(ver) {}
 
     size_t SerializedSize() const override { return sizeof(uint32_t); };
     uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
@@ -187,7 +187,7 @@
 };
 
 template <typename T> struct SupportedResponse : public KeymasterResponse {
-    explicit SupportedResponse(int32_t ver = MAX_MESSAGE_VERSION)
+    explicit SupportedResponse(int32_t ver)
         : KeymasterResponse(ver), results(nullptr), results_length(0) {}
     ~SupportedResponse() { delete[] results; }
 
@@ -622,6 +622,38 @@
     keymaster_cert_chain_t certificate_chain;
 };
 
+struct UpgradeKeyRequest : public KeymasterMessage {
+    explicit UpgradeKeyRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {
+        key_blob = {nullptr, 0};
+    }
+    ~UpgradeKeyRequest();
+
+    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 upgrade_params;
+};
+
+struct UpgradeKeyResponse : public KeymasterResponse {
+    explicit UpgradeKeyResponse(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterResponse(ver) {
+        upgraded_key = {nullptr, 0};
+    }
+    ~UpgradeKeyResponse();
+
+    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 upgraded_key;
+};
+
 }  // namespace keymaster
 
 #endif  // SYSTEM_KEYMASTER_ANDROID_KEYMASTER_MESSAGES_H_
diff --git a/include/keymaster/android_keymaster_utils.h b/include/keymaster/android_keymaster_utils.h
index c190e04..a1cbf51 100644
--- a/include/keymaster/android_keymaster_utils.h
+++ b/include/keymaster/android_keymaster_utils.h
@@ -36,7 +36,7 @@
     // 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;
+    return static_cast<int64_t>(time) * 1000;
 }
 
 /*
@@ -325,6 +325,9 @@
     }
 };
 
+keymaster_error_t EcKeySizeToCurve(uint32_t key_size_bits, keymaster_ec_curve_t* curve);
+keymaster_error_t EcCurveToKeySize(keymaster_ec_curve_t curve, uint32_t* key_size_bits);
+
 }  // namespace keymaster
 
 #endif  // SYSTEM_KEYMASTER_ANDROID_KEYMASTER_UTILS_H_
diff --git a/include/keymaster/authorization_set.h b/include/keymaster/authorization_set.h
index 74daa8d..ec68de0 100644
--- a/include/keymaster/authorization_set.h
+++ b/include/keymaster/authorization_set.h
@@ -79,6 +79,26 @@
     AuthorizationSet(const AuthorizationSet& set) : Serializable(), indirect_data_(nullptr) {
         elems_ = nullptr;
         Reinitialize(set.elems_, set.elems_size_);
+        error_ = set.error_;
+    }
+
+    // Move constructor.
+    AuthorizationSet(AuthorizationSet&& set) : Serializable() {
+        MoveFrom(set);
+    }
+
+    // Copy assignment.
+    AuthorizationSet& operator=(const AuthorizationSet& set) {
+        Reinitialize(set.elems_, set.elems_size_);
+        error_ = set.error_;
+        return *this;
+    }
+
+    // Move assignment.
+    AuthorizationSet& operator=(AuthorizationSet&& set) {
+        FreeData();
+        MoveFrom(set);
+        return *this;
     }
 
     /**
@@ -160,7 +180,7 @@
      * Removes the entry at the specified index. Returns true if successful, false if the index was
      * out of bounds.
      */
-    bool erase(size_t index);
+    bool erase(int index);
 
     /**
      * Returns iterator (pointer) to beginning of elems array, to enable STL-style iteration
@@ -183,6 +203,13 @@
     keymaster_key_param_t operator[](int n) const;
 
     /**
+     * Returns true if the set contains at least one instance of \p tag
+     */
+    bool Contains(keymaster_tag_t tag) const {
+        return find(tag) != -1;
+    }
+
+    /**
      * Returns the number of \p tag entries.
      */
     size_t GetTagCount(keymaster_tag_t tag) const;
@@ -204,6 +231,14 @@
     }
 
     /**
+     * Returns true if the set contains the specified tag and value.
+     */
+    template <keymaster_tag_t Tag>
+    bool Contains(TypedTag<KM_UINT, Tag> tag, uint32_t val) const {
+        return ContainsIntValue(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.
      */
@@ -392,10 +427,9 @@
     size_t SerializedSizeOfElements() const;
 
   private:
-    // Disallow assignment
-    void operator=(const AuthorizationSet&);
-
     void FreeData();
+    void MoveFrom(AuthorizationSet& set);
+
     void set_invalid(Error err);
 
     static size_t ComputeIndirectDataSize(const keymaster_key_param_t* elems, size_t count);
@@ -416,8 +450,9 @@
     bool GetTagValueBool(keymaster_tag_t tag) const;
 
     bool ContainsEnumValue(keymaster_tag_t tag, uint32_t val) const;
+    bool ContainsIntValue(keymaster_tag_t tag, uint32_t val) const;
 
-    // Define elems_ and elems_size_ as aliases to params and length, respectivley.  This is to
+    // Define elems_ and elems_size_ as aliases to params and length, respectively.  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;
diff --git a/include/keymaster/ec_key_factory.h b/include/keymaster/ec_key_factory.h
index aaeb548..2bb9c8b 100644
--- a/include/keymaster/ec_key_factory.h
+++ b/include/keymaster/ec_key_factory.h
@@ -52,7 +52,12 @@
 
     OperationFactory* GetOperationFactory(keymaster_purpose_t purpose) const override;
 
-    static EC_GROUP* choose_group(size_t key_size_bits);
+  protected:
+    static EC_GROUP* ChooseGroup(size_t key_size_bits);
+    static EC_GROUP* ChooseGroup(keymaster_ec_curve_t ec_curve);
+
+    static keymaster_error_t GetCurveAndSize(const AuthorizationSet& key_description,
+                                             keymaster_ec_curve_t* curve, uint32_t* key_size_bits);
 };
 
 }  // namespace keymaster
diff --git a/include/keymaster/keymaster_configuration.h b/include/keymaster/keymaster_configuration.h
new file mode 100644
index 0000000..97b7fa5
--- /dev/null
+++ b/include/keymaster/keymaster_configuration.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 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_KEYMASTER_CONFIGURATION_H_
+#define SYSTEM_KEYMASTER_KEYMASTER_CONFIGURATION_H_
+
+#include <string>
+
+#include <stdint.h>
+
+#include <hardware/keymaster2.h>
+#include <hardware/keymaster_defs.h>
+
+namespace keymaster {
+
+/**
+ * Retrieves OS version information from system build properties and configures the provided
+ * keymaster device.
+ */
+keymaster_error_t ConfigureDevice(keymaster2_device_t* dev);
+
+/**
+ * Parses OS version string, returning in integer form. For example, "6.1.2" will be returned as
+ * 60102.  Ignores any non-numeric suffix, and allows short build numbers, e.g. "6" -> 60000 and
+ * "6.1" -> 60100. Returns 0 if the string doesn't contain a numeric version number.
+ */
+uint32_t GetOsVersion(const char* version_string);
+
+/**
+ * Parses OS patch level string, returning year and month in integer form. For example, "2016-03-25"
+ * will be returned as 201603. Returns 0 if the string doesn't contain a date in the form
+ * YYYY-MM-DD.
+ */
+uint32_t GetOsPatchlevel(const char* patchlevel_string);
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_KEYMASTER_CONFIGURATION_H_
diff --git a/include/keymaster/keymaster_context.h b/include/keymaster/keymaster_context.h
index c9802e4..104e874 100644
--- a/include/keymaster/keymaster_context.h
+++ b/include/keymaster/keymaster_context.h
@@ -65,6 +65,28 @@
     KeymasterContext() {}
     virtual ~KeymasterContext(){};
 
+    /**
+     * Returns the security level (SW or TEE) of this keymaster implementation.
+     */
+    virtual keymaster_security_level_t GetSecurityLevel() const = 0;
+
+    /**
+     * Sets the system version as reported by the system *itself*.  This is used to verify that the
+     * system believes itself to be running the same version that is reported by the bootloader, in
+     * hardware implementations.  For SoftKeymasterDevice, this sets the version information used.
+     *
+     * If the specified values don't match the bootloader-provided values, this method must return
+     * KM_ERROR_INVALID_ARGUMENT;
+     */
+    virtual keymaster_error_t SetSystemVersion(uint32_t os_version, uint32_t os_patchlevel) = 0;
+
+    /**
+     * Returns the system version.  For hardware-based implementations this will be the value
+     * reported by the bootloader.  For SoftKeymasterDevice it will be the verion information set by
+     * SetSystemVersion above.
+     */
+    virtual void GetSystemVersion(uint32_t* os_version, uint32_t* os_patchlevel) const = 0;
+
     virtual KeyFactory* GetKeyFactory(keymaster_algorithm_t algorithm) const = 0;
     virtual OperationFactory* GetOperationFactory(keymaster_algorithm_t algorithm,
                                                   keymaster_purpose_t purpose) const = 0;
@@ -85,6 +107,14 @@
                                             AuthorizationSet* sw_enforced) const = 0;
 
     /**
+     * UpgradeKeyBlob takes an existing blob, parses out key material and constructs a new blob with
+     * the current format and OS version info.
+     */
+    virtual keymaster_error_t UpgradeKeyBlob(const KeymasterKeyBlob& key_to_upgrade,
+                                             const AuthorizationSet& upgrade_params,
+                                             KeymasterKeyBlob* upgraded_key) 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).
@@ -131,18 +161,27 @@
 
     /**
      * Return the attestation signing key of the specified algorithm (KM_ALGORITHM_RSA or
-     * KM_ALGORITHM_EC).
+     * KM_ALGORITHM_EC).  Caller does not acquire ownership and should not delete.
      */
     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).
+     * (KM_ALGORITHM_RSA or KM_ALGORITHM_EC).  Caller does not acquire ownership and should not
+     * delete.
      */
     virtual keymaster_cert_chain_t* AttestationChain(keymaster_algorithm_t algorithm,
                                                      keymaster_error_t* error) const = 0;
 
+    /**
+     * Generate the current unique ID.
+     */
+    virtual keymaster_error_t GenerateUniqueId(uint64_t creation_date_time,
+                                               const keymaster_blob_t& application_id,
+                                               bool reset_since_rotation,
+                                               Buffer* unique_id) const = 0;
+
   private:
     // Uncopyable.
     KeymasterContext(const KeymasterContext&);
diff --git a/include/keymaster/keymaster_tags.h b/include/keymaster/keymaster_tags.h
index dcaf0da..2c7ac03 100644
--- a/include/keymaster/keymaster_tags.h
+++ b/include/keymaster/keymaster_tags.h
@@ -164,6 +164,8 @@
 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_TAG(KM_BYTES, TAG_ATTESTATION_CHALLENGE);
+DECLARE_KEYMASTER_TAG(KM_BOOL, TAG_RESET_SINCE_ID_ROTATION);
 
 // DECLARE_KEYMASTER_ENUM_TAG is used to declare TypedEnumTag instances for each enum keymaster tag.
 #define DECLARE_KEYMASTER_ENUM_TAG(type, name, enumtype)                                           \
diff --git a/include/keymaster/serializable.h b/include/keymaster/serializable.h
index 8748c55..58bfcca 100644
--- a/include/keymaster/serializable.h
+++ b/include/keymaster/serializable.h
@@ -62,6 +62,14 @@
  */
 
 /**
+ * Convert a pointer into a value.  This is used to make sure compiler won't optimize away pointer
+ * overflow checks. (See http://www.kb.cert.org/vuls/id/162289)
+ */
+template <typename T> inline uintptr_t __pval(const T *p) {
+    return reinterpret_cast<uintptr_t>(p);
+}
+
+/**
  * 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().
@@ -111,7 +119,8 @@
 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)
+    if (count >= (UINT32_MAX / sizeof(uint32_t)) ||
+        __pval(buf) + count * sizeof(uint32_t) < __pval(buf))
         return buf;
     buf = append_uint32_to_buf(buf, end, count);
     for (size_t i = 0; i < count; ++i)
@@ -172,8 +181,9 @@
     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)
+    uintptr_t array_end = __pval(*buf_ptr) + *count * sizeof(uint32_t);
+    if (*count >= UINT32_MAX / sizeof(uint32_t) ||
+        array_end < __pval(*buf_ptr) || array_end > __pval(end))
         return false;
 
     data->reset(new (std::nothrow) T[*count]);
diff --git a/include/keymaster/soft_keymaster_context.h b/include/keymaster/soft_keymaster_context.h
index 2091d6f..eb10f44 100644
--- a/include/keymaster/soft_keymaster_context.h
+++ b/include/keymaster/soft_keymaster_context.h
@@ -53,6 +53,13 @@
      */
     keymaster_error_t SetHardwareDevice(keymaster1_device_t* keymaster1_device);
 
+    keymaster_security_level_t GetSecurityLevel() const override {
+        return KM_SECURITY_LEVEL_SOFTWARE;
+    }
+
+    keymaster_error_t SetSystemVersion(uint32_t os_version, uint32_t os_patchlevel) override;
+    void GetSystemVersion(uint32_t* os_version, uint32_t* os_patchlevel) const override;
+
     KeyFactory* GetKeyFactory(keymaster_algorithm_t algorithm) const override;
     OperationFactory* GetOperationFactory(keymaster_algorithm_t algorithm,
                                           keymaster_purpose_t purpose) const override;
@@ -61,7 +68,9 @@
                                     const KeymasterKeyBlob& key_material, KeymasterKeyBlob* blob,
                                     AuthorizationSet* hw_enforced,
                                     AuthorizationSet* sw_enforced) const override;
-
+    keymaster_error_t UpgradeKeyBlob(const KeymasterKeyBlob& key_to_upgrade,
+                                     const AuthorizationSet& upgrade_params,
+                                     KeymasterKeyBlob* upgraded_key) const override;
     keymaster_error_t ParseKeyBlob(const KeymasterKeyBlob& blob,
                                    const AuthorizationSet& additional_params,
                                    KeymasterKeyBlob* key_material, AuthorizationSet* hw_enforced,
@@ -75,12 +84,17 @@
                              keymaster_error_t* error) const override;
     keymaster_cert_chain_t* AttestationChain(keymaster_algorithm_t algorithm,
                                              keymaster_error_t* error) const override;
+    keymaster_error_t GenerateUniqueId(uint64_t creation_date_time,
+                                       const keymaster_blob_t& application_id,
+                                       bool reset_since_rotation, Buffer* unique_id) const override;
 
     KeymasterEnforcement* enforcement_policy() override {
         // SoftKeymaster does no enforcement; it's all done by Keystore.
         return nullptr;
     }
 
+    void AddSystemVersionToSet(AuthorizationSet* auth_set) const;
+
   private:
     keymaster_error_t ParseOldSoftkeymasterBlob(const KeymasterKeyBlob& blob,
                                                 KeymasterKeyBlob* key_material,
@@ -108,6 +122,8 @@
     std::unique_ptr<KeyFactory> hmac_factory_;
     keymaster1_device* km1_dev_;
     const std::string root_of_trust_;
+    uint32_t os_version_;
+    uint32_t os_patchlevel_;
 };
 
 }  // namespace keymaster
diff --git a/include/keymaster/soft_keymaster_device.h b/include/keymaster/soft_keymaster_device.h
index 4a734f1..a20454d 100644
--- a/include/keymaster/soft_keymaster_device.h
+++ b/include/keymaster/soft_keymaster_device.h
@@ -79,6 +79,8 @@
         impl_->GetVersion(req, rsp);
     }
 
+    bool configured() const { return configured_; }
+
     typedef std::pair<keymaster_algorithm_t, keymaster_purpose_t> AlgPurposePair;
     typedef std::map<AlgPurposePair, std::vector<keymaster_digest_t>> DigestMap;
 
@@ -177,6 +179,8 @@
                                    keymaster_operation_handle_t operation_handle);
 
     // Keymaster2 methods
+    static keymaster_error_t configure(const keymaster2_device_t* dev,
+                                       const keymaster_key_param_set_t* params);
     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,
@@ -204,6 +208,10 @@
                                         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 upgrade_key(const keymaster2_device_t* dev,
+                                         const keymaster_key_blob_t* key_to_upgrade,
+                                         const keymaster_key_param_set_t* upgrade_params,
+                                         keymaster_key_blob_t* upgraded_key);
     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);
@@ -238,6 +246,7 @@
     UniquePtr<AndroidKeymaster> impl_;
     std::string module_name_;
     hw_module_t updated_module_;
+    bool configured_;
 };
 
 }  // namespace keymaster
diff --git a/keymaster_configuration.cpp b/keymaster_configuration.cpp
new file mode 100644
index 0000000..428197c
--- /dev/null
+++ b/keymaster_configuration.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 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 <keymaster/keymaster_configuration.h>
+
+#include <regex>
+#include <string>
+
+#include <regex.h>
+
+#define LOG_TAG "keymaster"
+#include <cutils/log.h>
+
+#ifndef KEYMASTER_UNIT_TEST_BUILD
+#include <cutils/properties.h>
+#else
+#define PROPERTY_VALUE_MAX 80 /* Value doesn't matter */
+void property_get(const char* /* prop_name */, char* /* prop */, const char* /* default */) {}
+#endif
+
+#include <keymaster/authorization_set.h>
+
+namespace keymaster {
+
+namespace {
+
+constexpr char kPlatformVersionProp[] = "ro.build.version.release";
+constexpr char kPlatformVersionRegex[] = "^([0-9]{1,2})(\\.([0-9]{1,2}))?(\\.([0-9]{1,2}))?";
+constexpr size_t kMajorVersionMatch = 1;
+constexpr size_t kMinorVersionMatch = 3;
+constexpr size_t kSubminorVersionMatch = 5;
+constexpr size_t kPlatformVersionMatchCount = kSubminorVersionMatch + 1;
+
+constexpr char kPlatformPatchlevelProp[] = "ro.build.version.security_patch";
+constexpr char kPlatformPatchlevelRegex[] = "^([0-9]{4})-([0-9]{2})-[0-9]{2}$";
+constexpr size_t kYearMatch = 1;
+constexpr size_t kMonthMatch = 2;
+constexpr size_t kPlatformPatchlevelMatchCount = kMonthMatch + 1;
+
+uint32_t match_to_uint32(const char* expression, const regmatch_t& match) {
+    if (match.rm_so == -1)
+        return 0;
+
+    size_t len = match.rm_eo - match.rm_so;
+    std::string s(expression + match.rm_so, len);
+    return std::stoul(s);
+}
+
+}  // anonymous namespace
+
+keymaster_error_t ConfigureDevice(keymaster2_device_t* dev, uint32_t os_version,
+                                  uint32_t os_patchlevel) {
+    AuthorizationSet config_params(AuthorizationSetBuilder()
+                                       .Authorization(keymaster::TAG_OS_VERSION, os_version)
+                                       .Authorization(keymaster::TAG_OS_PATCHLEVEL, os_patchlevel));
+    return dev->configure(dev, &config_params);
+}
+
+keymaster_error_t ConfigureDevice(keymaster2_device_t* dev) {
+    char version_str[PROPERTY_VALUE_MAX];
+    property_get(kPlatformVersionProp, version_str, "" /* default */);
+    uint32_t version = GetOsVersion(version_str);
+
+    char patchlevel_str[PROPERTY_VALUE_MAX];
+    property_get(kPlatformPatchlevelProp, patchlevel_str, "" /* default */);
+    uint32_t patchlevel = GetOsPatchlevel(patchlevel_str);
+
+    return ConfigureDevice(dev, version, patchlevel);
+}
+
+uint32_t GetOsVersion(const char* version_str) {
+    regex_t regex;
+    if (regcomp(&regex, kPlatformVersionRegex, REG_EXTENDED)) {
+        ALOGE("Failed to compile version regex! (%s)", kPlatformVersionRegex);
+        return 0;
+    }
+
+    regmatch_t matches[kPlatformVersionMatchCount];
+    if (regexec(&regex, version_str, kPlatformVersionMatchCount, matches, 0 /* flags */)) {
+        ALOGI("Platform version string does not match expected format.  Using version 0.");
+        return 0;
+    }
+
+    uint32_t major = match_to_uint32(version_str, matches[kMajorVersionMatch]);
+    uint32_t minor = match_to_uint32(version_str, matches[kMinorVersionMatch]);
+    uint32_t subminor = match_to_uint32(version_str, matches[kSubminorVersionMatch]);
+
+    return (major * 100 + minor) * 100 + subminor;
+}
+
+uint32_t GetOsPatchlevel(const char* patchlevel_str) {
+    regex_t regex;
+    if (regcomp(&regex, kPlatformPatchlevelRegex, REG_EXTENDED) != 0) {
+        ALOGE("Failed to compile platform patchlevel regex! (%s)", kPlatformPatchlevelRegex);
+        return 0;
+    }
+
+    regmatch_t matches[kPlatformPatchlevelMatchCount];
+    if (regexec(&regex, patchlevel_str, kPlatformPatchlevelMatchCount, matches, 0 /* flags */)) {
+        ALOGI("Platform patchlevel string does not match expected format.  Using patchlevel 0");
+        return 0;
+    }
+
+    uint32_t year = match_to_uint32(patchlevel_str, matches[kYearMatch]);
+    uint32_t month = match_to_uint32(patchlevel_str, matches[kMonthMatch]);
+
+    if (month < 1 || month > 12) {
+        ALOGE("Invalid patch month %d", month);
+        return 0;
+    }
+    return year * 100 + month;
+}
+
+}  // namespace keymaster
diff --git a/keymaster_configuration_test.cpp b/keymaster_configuration_test.cpp
new file mode 100644
index 0000000..81e9598
--- /dev/null
+++ b/keymaster_configuration_test.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 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 <gtest/gtest.h>
+
+#include <keymaster/keymaster_configuration.h>
+
+#ifdef HOST_BUILD
+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;
+    std::cout << fmt << std::endl;
+    return 0;
+}
+}  // extern "C"
+#endif  // HOST_BUILD
+
+namespace keymaster {
+namespace test {
+
+TEST(VersionParsingTest, Full) {
+    EXPECT_EQ(612334U, GetOsVersion("61.23.34"));
+    EXPECT_EQ(680000U, GetOsVersion("681.23.24"));
+    EXPECT_EQ(682300U, GetOsVersion("68.231.24"));
+    EXPECT_EQ(682324U, GetOsVersion("68.23.241"));
+    EXPECT_EQ(60102U, GetOsVersion("6.1.2-extrajunk"));
+    EXPECT_EQ(0U, GetOsVersion("extra6.1.2"));
+}
+
+TEST(VersionParsingTest, FullWithExtraChars) {}
+
+TEST(VersionParsingTest, MajorOnly) {
+    EXPECT_EQ(60000U, GetOsVersion("6"));
+    EXPECT_EQ(680000U, GetOsVersion("68"));
+    EXPECT_EQ(680000U, GetOsVersion("681"));
+    EXPECT_EQ(60000U, GetOsVersion("6.junk"));
+}
+
+TEST(VersionParsingTest, MajorMinorOnly) {
+    EXPECT_EQ(60100U, GetOsVersion("6.1"));
+    EXPECT_EQ(60100U, GetOsVersion("6.1junk"));
+}
+
+TEST(PatchLevelParsingTest, Full) {
+    EXPECT_EQ(201603U, GetOsPatchlevel("2016-03-23"));
+    EXPECT_EQ(0U, GetOsPatchlevel("2016-13-23"));
+    EXPECT_EQ(0U, GetOsPatchlevel("2016-03"));
+    EXPECT_EQ(0U, GetOsPatchlevel("2016-3-23"));
+    EXPECT_EQ(0U, GetOsPatchlevel("2016-03-23r"));
+    EXPECT_EQ(0U, GetOsPatchlevel("r2016-03-23"));
+}
+
+}  // namespace test
+}  // namespace keymaster
diff --git a/keymaster_enforcement.cpp b/keymaster_enforcement.cpp
index 7696d89..3f2e4f4 100644
--- a/keymaster_enforcement.cpp
+++ b/keymaster_enforcement.cpp
@@ -285,6 +285,7 @@
         case KM_TAG_AUTH_TOKEN:
         case KM_TAG_ROOT_OF_TRUST:
         case KM_TAG_APPLICATION_DATA:
+        case KM_TAG_ATTESTATION_CHALLENGE:
             return KM_ERROR_INVALID_KEY_BLOB;
 
         /* Tags used for cryptographic parameters in keygen.  Nothing to enforce. */
diff --git a/keymaster_tags.cpp b/keymaster_tags.cpp
index ce7156f..238bc33 100644
--- a/keymaster_tags.cpp
+++ b/keymaster_tags.cpp
@@ -109,6 +109,8 @@
         return "KM_TAG_RESET_SINCE_ID_ROTATION";
     case KM_TAG_ALLOW_WHILE_ON_BODY:
         return "KM_TAG_ALLOW_WHILE_ON_BODY";
+    case KM_TAG_ATTESTATION_CHALLENGE:
+        return "KM_TAG_ATTESTATION_CHALLENGE";
     }
     return "<Unknown>";
 }
diff --git a/openssl_utils.h b/openssl_utils.h
index 034b129..9fa6ec1 100644
--- a/openssl_utils.h
+++ b/openssl_utils.h
@@ -49,18 +49,19 @@
     typedef OpenSslObjectDeleter<name, name##_free> name##_Delete;                                 \
     typedef UniquePtr<name, name##_Delete> name##_Ptr;
 
+DEFINE_OPENSSL_OBJECT_POINTER(ASN1_BIT_STRING)
 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(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)
diff --git a/rsa_operation.cpp b/rsa_operation.cpp
index 2046a64..ce8d2f3 100644
--- a/rsa_operation.cpp
+++ b/rsa_operation.cpp
@@ -31,7 +31,6 @@
 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.
@@ -173,7 +172,7 @@
     return KM_ERROR_OK;
 }
 
-keymaster_error_t RsaOperation::SetRsaPaddingInEvpContext(EVP_PKEY_CTX* pkey_ctx) {
+keymaster_error_t RsaOperation::SetRsaPaddingInEvpContext(EVP_PKEY_CTX* pkey_ctx, bool signing) {
     keymaster_error_t error;
     int openssl_padding = GetOpensslPadding(&error);
     if (error != KM_ERROR_OK)
@@ -181,6 +180,15 @@
 
     if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, openssl_padding) <= 0)
         return TranslateLastOpenSslError();
+
+    if (signing && openssl_padding == RSA_PKCS1_PSS_PADDING) {
+        // Also need to set the length of the salt used in the padding generation.  We set it equal
+        // to the length of the selected digest.
+        assert(digest_algorithm_);
+        if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, EVP_MD_size(digest_algorithm_)) <= 0)
+            return TranslateLastOpenSslError();
+    }
+
     return KM_ERROR_OK;
 }
 
@@ -238,8 +246,7 @@
             *error = KM_ERROR_INCOMPATIBLE_PADDING_MODE;
             return -1;
         }
-        if (EVP_MD_size(digest_algorithm_) + kPssOverhead + kMinPssSaltSize >
-            (size_t)EVP_PKEY_size(rsa_key_)) {
+        if (EVP_MD_size(digest_algorithm_) * 2 + kPssOverhead > (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_));
@@ -265,7 +272,7 @@
     if (EVP_DigestSignInit(&digest_ctx_, &pkey_ctx, digest_algorithm_, nullptr /* engine */,
                            rsa_key_) != 1)
         return TranslateLastOpenSslError();
-    return SetRsaPaddingInEvpContext(pkey_ctx);
+    return SetRsaPaddingInEvpContext(pkey_ctx, true /* signing */);
 }
 
 keymaster_error_t RsaSignOperation::Update(const AuthorizationSet& additional_params,
@@ -388,7 +395,7 @@
     EVP_PKEY_CTX* pkey_ctx;
     if (EVP_DigestVerifyInit(&digest_ctx_, &pkey_ctx, digest_algorithm_, NULL, rsa_key_) != 1)
         return TranslateLastOpenSslError();
-    return SetRsaPaddingInEvpContext(pkey_ctx);
+    return SetRsaPaddingInEvpContext(pkey_ctx, false /* signing */);
 }
 
 keymaster_error_t RsaVerifyOperation::Update(const AuthorizationSet& additional_params,
@@ -529,7 +536,7 @@
     if (EVP_PKEY_encrypt_init(ctx.get()) <= 0)
         return TranslateLastOpenSslError();
 
-    error = SetRsaPaddingInEvpContext(ctx.get());
+    error = SetRsaPaddingInEvpContext(ctx.get(), false /* signing */);
     if (error != KM_ERROR_OK)
         return error;
     error = SetOaepDigestIfRequired(ctx.get());
@@ -582,7 +589,7 @@
     if (EVP_PKEY_decrypt_init(ctx.get()) <= 0)
         return TranslateLastOpenSslError();
 
-    error = SetRsaPaddingInEvpContext(ctx.get());
+    error = SetRsaPaddingInEvpContext(ctx.get(), false /* signing */);
     if (error != KM_ERROR_OK)
         return error;
     error = SetOaepDigestIfRequired(ctx.get());
diff --git a/rsa_operation.h b/rsa_operation.h
index 8283f2e..669b21a 100644
--- a/rsa_operation.h
+++ b/rsa_operation.h
@@ -54,7 +54,7 @@
     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 SetRsaPaddingInEvpContext(EVP_PKEY_CTX* pkey_ctx, bool signing);
     keymaster_error_t InitDigest();
 
     EVP_PKEY* rsa_key_;
diff --git a/serializable.cpp b/serializable.cpp
index 5db64f8..94b92d0 100644
--- a/serializable.cpp
+++ b/serializable.cpp
@@ -25,7 +25,7 @@
 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
+    if (__pval(buf) + data_len < __pval(buf))  // Pointer wrap check
         return buf;
 
     if (buf + data_len <= end) {
@@ -36,7 +36,7 @@
 }
 
 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
+    if (__pval(*buf_ptr) + size < __pval(*buf_ptr))  // Pointer wrap check
         return false;
 
     if (end < *buf_ptr + size)
@@ -51,7 +51,7 @@
     if (!copy_uint32_from_buf(buf_ptr, end, size))
         return false;
 
-    if (*buf_ptr + *size < *buf_ptr)  // Pointer wrap check
+    if (__pval(*buf_ptr) + *size < __pval(*buf_ptr))  // Pointer wrap check
         return false;
 
     if (*buf_ptr + *size > end)
@@ -96,7 +96,7 @@
 
 bool Buffer::Reinitialize(const void* data, size_t data_len) {
     Clear();
-    if (static_cast<const uint8_t*>(data) + data_len < data)  // Pointer wrap check
+    if (__pval(data) + data_len < __pval(data))  // Pointer wrap check
         return false;
     buffer_.reset(new (std::nothrow) uint8_t[data_len]);
     if (!buffer_.get())
diff --git a/soft_keymaster_context.cpp b/soft_keymaster_context.cpp
index a143245..892fffa 100644
--- a/soft_keymaster_context.cpp
+++ b/soft_keymaster_context.cpp
@@ -20,6 +20,7 @@
 #include <time.h>
 
 #include <openssl/aes.h>
+#include <openssl/hmac.h>
 #include <openssl/rand.h>
 #include <openssl/sha.h>
 
@@ -281,12 +282,34 @@
 
 size_t kCertificateChainLength = 2;
 
+bool UpgradeIntegerTag(keymaster_tag_t tag, uint32_t value, AuthorizationSet* set,
+                       bool* set_changed) {
+    int index = set->find(tag);
+    if (index == -1) {
+        keymaster_key_param_t param;
+        param.tag = tag;
+        param.integer = value;
+        set->push_back(param);
+        *set_changed = true;
+        return true;
+    }
+
+    if (set->params[index].integer > value)
+        return false;
+
+    if (set->params[index].integer != value) {
+        set->params[index].integer = value;
+        *set_changed = true;
+    }
+    return true;
+}
+
 }  // 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) {}
+      km1_dev_(nullptr), root_of_trust_(root_of_trust), os_version_(0), os_patchlevel_(0) {}
 
 SoftKeymasterContext::~SoftKeymasterContext() {}
 
@@ -326,6 +349,18 @@
     return KM_ERROR_OK;
 }
 
+keymaster_error_t SoftKeymasterContext::SetSystemVersion(uint32_t os_version,
+                                                         uint32_t os_patchlevel) {
+    os_version_ = os_version;
+    os_patchlevel_ = os_patchlevel;
+    return KM_ERROR_OK;
+}
+
+void SoftKeymasterContext::GetSystemVersion(uint32_t* os_version, uint32_t* os_patchlevel) const {
+    *os_version = os_version_;
+    *os_patchlevel = os_patchlevel_;
+}
+
 KeyFactory* SoftKeymasterContext::GetKeyFactory(keymaster_algorithm_t algorithm) const {
     switch (algorithm) {
     case KM_ALGORITHM_RSA:
@@ -371,8 +406,8 @@
 }
 
 static keymaster_error_t SetAuthorizations(const AuthorizationSet& key_description,
-                                           keymaster_key_origin_t origin,
-                                           AuthorizationSet* hw_enforced,
+                                           keymaster_key_origin_t origin, uint32_t os_version,
+                                           uint32_t os_patchlevel, AuthorizationSet* hw_enforced,
                                            AuthorizationSet* sw_enforced) {
     sw_enforced->Clear();
 
@@ -405,6 +440,9 @@
 
     sw_enforced->push_back(TAG_CREATION_DATETIME, java_time(time(NULL)));
     sw_enforced->push_back(TAG_ORIGIN, origin);
+    sw_enforced->push_back(TAG_OS_VERSION, os_version);
+    sw_enforced->push_back(TAG_OS_PATCHLEVEL, os_patchlevel);
+
     return TranslateAuthorizationSetError(sw_enforced->is_valid());
 }
 
@@ -414,7 +452,8 @@
                                                       KeymasterKeyBlob* blob,
                                                       AuthorizationSet* hw_enforced,
                                                       AuthorizationSet* sw_enforced) const {
-    keymaster_error_t error = SetAuthorizations(key_description, origin, hw_enforced, sw_enforced);
+    keymaster_error_t error = SetAuthorizations(key_description, origin, os_version_,
+                                                os_patchlevel_, hw_enforced, sw_enforced);
     if (error != KM_ERROR_OK)
         return error;
 
@@ -426,6 +465,51 @@
     return SerializeIntegrityAssuredBlob(key_material, hidden, *hw_enforced, *sw_enforced, blob);
 }
 
+keymaster_error_t SoftKeymasterContext::UpgradeKeyBlob(const KeymasterKeyBlob& key_to_upgrade,
+                                                       const AuthorizationSet& upgrade_params,
+                                                       KeymasterKeyBlob* upgraded_key) const {
+    KeymasterKeyBlob key_material;
+    AuthorizationSet tee_enforced;
+    AuthorizationSet sw_enforced;
+    keymaster_error_t error =
+        ParseKeyBlob(key_to_upgrade, upgrade_params, &key_material, &tee_enforced, &sw_enforced);
+    if (error != KM_ERROR_OK)
+        return error;
+
+    // Three cases here:
+    //
+    // 1. Software key blob.  Version info, if present, is in sw_enforced.  If not present, we
+    //    should add it.
+    //
+    // 2. Keymaster0 hardware key blob.  Version info, if present, is in sw_enforced.  If not
+    //    present we should add it.
+    //
+    // 3. Keymaster1 hardware key blob.  Version info is not present and we shouldn't have been
+    //    asked to upgrade.
+
+    // Handle case 3.
+    if (km1_dev_ && tee_enforced.Contains(TAG_PURPOSE) && !tee_enforced.Contains(TAG_OS_PATCHLEVEL))
+        return KM_ERROR_INVALID_ARGUMENT;
+
+    // Handle cases 1 & 2.
+    bool set_changed = false;
+    if (!UpgradeIntegerTag(TAG_OS_VERSION, os_version_, &sw_enforced, &set_changed) ||
+        !UpgradeIntegerTag(TAG_OS_PATCHLEVEL, os_patchlevel_, &sw_enforced, &set_changed))
+        // One of the version fields would have been a downgrade. Not allowed.
+        return KM_ERROR_INVALID_ARGUMENT;
+
+    if (!set_changed)
+        // Dont' need an upgrade.
+        return KM_ERROR_OK;
+
+    AuthorizationSet hidden;
+    error = BuildHiddenAuthorizations(upgrade_params, &hidden);
+    if (error != KM_ERROR_OK)
+        return error;
+    return SerializeIntegrityAssuredBlob(key_material, hidden, tee_enforced, sw_enforced,
+                                         upgraded_key);
+}
+
 static keymaster_error_t ParseOcbAuthEncryptedBlob(const KeymasterKeyBlob& blob,
                                                    const AuthorizationSet& hidden,
                                                    KeymasterKeyBlob* key_material,
@@ -653,6 +737,13 @@
     return KM_ERROR_OK;
 }
 
+void SoftKeymasterContext::AddSystemVersionToSet(AuthorizationSet* auth_set) const {
+    if (!auth_set->Contains(TAG_OS_VERSION))
+        auth_set->push_back(TAG_OS_VERSION, os_version_);
+    if (!auth_set->Contains(TAG_OS_PATCHLEVEL))
+        auth_set->push_back(TAG_OS_PATCHLEVEL, os_patchlevel_);
+}
+
 EVP_PKEY* SoftKeymasterContext::AttestationKey(keymaster_algorithm_t algorithm,
                                                keymaster_error_t* error) const {
 
@@ -742,6 +833,13 @@
     return chain.release();
 }
 
+keymaster_error_t SoftKeymasterContext::GenerateUniqueId(
+    uint64_t /* creation_date_time */, const keymaster_blob_t& /* application_id */,
+    bool /* reset_since_rotation */, Buffer* /* unique_id */) const {
+    // SoftKeymasterDevice cannot generate unique IDs.
+    return KM_ERROR_UNIMPLEMENTED;
+}
+
 keymaster_error_t SoftKeymasterContext::ParseKeymaster1HwBlob(
     const KeymasterKeyBlob& blob, const AuthorizationSet& additional_params,
     KeymasterKeyBlob* key_material, AuthorizationSet* hw_enforced,
diff --git a/soft_keymaster_device.cpp b/soft_keymaster_device.cpp
index cbeaec7..eddbc5d 100644
--- a/soft_keymaster_device.cpp
+++ b/soft_keymaster_device.cpp
@@ -73,6 +73,7 @@
 
 namespace keymaster {
 
+const size_t kMaximumAttestationChallengeLength = 128;
 const size_t kOperationTableSize = 16;
 
 template <typename T> std::vector<T> make_vector(const T* array, size_t len) {
@@ -126,7 +127,7 @@
 SoftKeymasterDevice::SoftKeymasterDevice()
     : wrapped_km0_device_(nullptr), wrapped_km1_device_(nullptr),
       context_(new SoftKeymasterContext),
-      impl_(new AndroidKeymaster(context_, kOperationTableSize)) {
+      impl_(new AndroidKeymaster(context_, kOperationTableSize)), configured_(false) {
     LOG_I("Creating device", 0);
     LOG_D("Device address: %p", this);
 
@@ -136,7 +137,7 @@
 
 SoftKeymasterDevice::SoftKeymasterDevice(SoftKeymasterContext* context)
     : wrapped_km0_device_(nullptr), wrapped_km1_device_(nullptr), context_(context),
-      impl_(new AndroidKeymaster(context_, kOperationTableSize)) {
+      impl_(new AndroidKeymaster(context_, kOperationTableSize)), configured_(false) {
     LOG_I("Creating test device", 0);
     LOG_D("Device address: %p", this);
 
@@ -275,14 +276,14 @@
     km2_device_.common.module = reinterpret_cast<hw_module_t*>(&soft_keymaster2_device_module);
     km2_device_.common.close = &close_device;
 
+    km2_device_.configure = configure;
     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_.upgrade_key = upgrade_key;
     km2_device_.delete_key = delete_key;
     km2_device_.delete_all_keys = delete_all_keys;
     km2_device_.begin = begin;
@@ -601,6 +602,25 @@
 }
 
 /* static */
+keymaster_error_t SoftKeymasterDevice::configure(const keymaster2_device_t* dev,
+                                                 const keymaster_key_param_set_t* params) {
+    AuthorizationSet params_copy(*params);
+    uint32_t os_version;
+    uint32_t os_patchlevel;
+    if (!params_copy.GetTagValue(TAG_OS_VERSION, &os_version) ||
+        !params_copy.GetTagValue(TAG_OS_PATCHLEVEL, &os_patchlevel)) {
+        LOG_E("Configuration parameters must contain OS version and patch level", 0);
+        return KM_ERROR_INVALID_ARGUMENT;
+    }
+
+    keymaster_error_t error =
+        convert_device(dev)->context_->SetSystemVersion(os_version, os_patchlevel);
+    if (error == KM_ERROR_OK)
+        convert_device(dev)->configured_ = true;
+    return error;
+}
+
+/* static */
 keymaster_error_t SoftKeymasterDevice::add_rng_entropy(const keymaster1_device_t* dev,
                                                        const uint8_t* data, size_t data_length) {
     if (!dev)
@@ -625,6 +645,9 @@
     if (!dev)
         return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
+    if (!convert_device(dev)->configured())
+        return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+
     SoftKeymasterDevice* sk_dev = convert_device(dev);
     return add_rng_entropy(&sk_dev->km1_device_, data, data_length);
 }
@@ -735,6 +758,12 @@
     key_blob->key_material = tmp;
 
     if (characteristics) {
+        // This is a keymaster1 method, and keymaster1 doesn't include version info, so remove it.
+        response.enforced.erase(response.enforced.find(TAG_OS_VERSION));
+        response.enforced.erase(response.enforced.find(TAG_OS_PATCHLEVEL));
+        response.unenforced.erase(response.unenforced.find(TAG_OS_VERSION));
+        response.unenforced.erase(response.unenforced.find(TAG_OS_PATCHLEVEL));
+
         *characteristics = BuildCharacteristics(response.enforced, response.unenforced);
         if (!*characteristics)
             return KM_ERROR_MEMORY_ALLOCATION_FAILED;
@@ -751,6 +780,9 @@
     if (!dev)
         return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
+    if (!convert_device(dev)->configured())
+        return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+
     if (!key_blob)
         return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
@@ -771,6 +803,7 @@
             *characteristics = *chars_ptr;
             free(chars_ptr);
         }
+
         return KM_ERROR_OK;
     }
 
@@ -806,9 +839,10 @@
         return KM_ERROR_OUTPUT_PARAMETER_NULL;
 
     const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
-    if (km1_dev)
+    if (km1_dev) {
         return km1_dev->get_key_characteristics(km1_dev, key_blob, client_id, app_data,
                                                 characteristics);
+    }
 
     GetKeyCharacteristicsRequest request;
     request.SetKeyMaterial(*key_blob);
@@ -819,9 +853,16 @@
     if (response.error != KM_ERROR_OK)
         return response.error;
 
+    // This is a keymaster1 method, and keymaster1 doesn't include version info, so remove it.
+    response.enforced.erase(response.enforced.find(TAG_OS_VERSION));
+    response.enforced.erase(response.enforced.find(TAG_OS_PATCHLEVEL));
+    response.unenforced.erase(response.unenforced.find(TAG_OS_VERSION));
+    response.unenforced.erase(response.unenforced.find(TAG_OS_PATCHLEVEL));
+
     *characteristics = BuildCharacteristics(response.enforced, response.unenforced);
     if (!*characteristics)
         return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
     return KM_ERROR_OK;
 }
 
@@ -833,21 +874,39 @@
     if (!dev)
         return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
+    if (!convert_device(dev)->configured())
+        return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+
     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)
+    const keymaster1_device_t* km1_dev = sk_dev->wrapped_km1_device_;
+    if (km1_dev) {
+        keymaster_key_characteristics_t* tmp_characteristics;
+        keymaster_error_t error = km1_dev->get_key_characteristics(km1_dev, key_blob, client_id,
+                                                                   app_data, &tmp_characteristics);
+        if (error == KM_ERROR_OK) {
+            *characteristics = *tmp_characteristics;
+            free(tmp_characteristics);
+        }
         return error;
-    *characteristics = *key_characteristics;
-    free(key_characteristics);
+    }
 
-    return error;
+    GetKeyCharacteristicsRequest request;
+    request.SetKeyMaterial(*key_blob);
+    AddClientAndAppData(client_id, app_data, &request);
+
+    GetKeyCharacteristicsResponse response;
+    sk_dev->impl_->GetKeyCharacteristics(request, &response);
+    if (response.error != KM_ERROR_OK)
+        return response.error;
+
+    response.enforced.CopyToParamSet(&characteristics->hw_enforced);
+    response.unenforced.CopyToParamSet(&characteristics->sw_enforced);
+
+    return KM_ERROR_OK;
 }
 
 /* static */
@@ -871,7 +930,8 @@
         return km1_dev->import_key(km1_dev, params, key_format, key_data, key_blob,
                                    characteristics);
 
-    *characteristics = nullptr;
+    if (characteristics)
+        *characteristics = nullptr;
 
     request.key_format = key_format;
     request.SetKeyMaterial(key_data->data, key_data->data_length);
@@ -904,6 +964,9 @@
     if (!dev)
         return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
+    if (!convert_device(dev)->configured())
+        return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+
     SoftKeymasterDevice* sk_dev = convert_device(dev);
 
     keymaster_error_t error;
@@ -972,6 +1035,9 @@
     if (!dev)
         return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
+    if (!convert_device(dev)->configured())
+        return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+
     SoftKeymasterDevice* sk_dev = convert_device(dev);
     return export_key(&sk_dev->km1_device_, export_format, key_to_export, client_id, app_data,
                       export_data);
@@ -985,6 +1051,9 @@
     if (!dev || !key_to_attest || !attest_params || !cert_chain)
         return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
+    if (!convert_device(dev)->configured())
+        return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+
     cert_chain->entry_count = 0;
     cert_chain->entries = nullptr;
 
@@ -992,6 +1061,14 @@
     request.SetKeyMaterial(*key_to_attest);
     request.attest_params.Reinitialize(*attest_params);
 
+    keymaster_blob_t attestation_challenge = {};
+    request.attest_params.GetTagValue(TAG_ATTESTATION_CHALLENGE, &attestation_challenge);
+    if (attestation_challenge.data_length > kMaximumAttestationChallengeLength) {
+        LOG_E("%d-byte attestation challenge; only %d bytes allowed",
+              attestation_challenge.data_length, kMaximumAttestationChallengeLength);
+        return KM_ERROR_INVALID_INPUT_LENGTH;
+    }
+
     AttestKeyResponse response;
     convert_device(dev)->impl_->AttestKey(request, &response);
     if (response.error != KM_ERROR_OK)
@@ -1024,6 +1101,39 @@
 }
 
 /* static */
+keymaster_error_t SoftKeymasterDevice::upgrade_key(const keymaster2_device_t* dev,
+                                                   const keymaster_key_blob_t* key_to_upgrade,
+                                                   const keymaster_key_param_set_t* upgrade_params,
+                                                   keymaster_key_blob_t* upgraded_key) {
+    if (!dev || !key_to_upgrade || !upgrade_params)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    if (!upgraded_key)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    if (!convert_device(dev)->configured())
+        return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+
+    UpgradeKeyRequest request;
+    request.SetKeyMaterial(*key_to_upgrade);
+    request.upgrade_params.Reinitialize(*upgrade_params);
+
+    UpgradeKeyResponse response;
+    convert_device(dev)->impl_->UpgradeKey(request, &response);
+    if (response.error != KM_ERROR_OK)
+        return response.error;
+
+    upgraded_key->key_material_size = response.upgraded_key.key_material_size;
+    uint8_t* tmp = reinterpret_cast<uint8_t*>(malloc(upgraded_key->key_material_size));
+    if (!tmp)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    memcpy(tmp, response.upgraded_key.key_material, response.upgraded_key.key_material_size);
+    upgraded_key->key_material = tmp;
+
+    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)
@@ -1039,6 +1149,9 @@
     if (!dev || !key || !key->key_material)
         return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
+    if (!convert_device(dev)->configured())
+        return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+
     KeymasterKeyBlob blob(*key);
     return convert_device(dev)->context_->DeleteKey(blob);
 }
@@ -1056,6 +1169,9 @@
     if (!dev)
         return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
+    if (!convert_device(dev)->configured())
+        return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+
     return convert_device(dev)->context_->DeleteAllKeys();
 }
 
@@ -1125,6 +1241,9 @@
     if (!dev)
         return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
+    if (!convert_device(dev)->configured())
+        return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+
     SoftKeymasterDevice* sk_dev = convert_device(dev);
     return begin(&sk_dev->km1_device_, purpose, key, in_params, out_params, operation_handle);
 }
@@ -1203,6 +1322,9 @@
     if (!dev)
         return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
+    if (!convert_device(dev)->configured())
+        return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+
     SoftKeymasterDevice* sk_dev = convert_device(dev);
     return update(&sk_dev->km1_device_, operation_handle, in_params, input, input_consumed,
                   out_params, output);
@@ -1275,6 +1397,9 @@
     if (!dev)
         return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
+    if (!convert_device(dev)->configured())
+        return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+
     if (input && input->data)
         return KM_ERROR_UNIMPLEMENTED;  // TODO(swillden): Implement this
 
@@ -1306,6 +1431,9 @@
     if (!dev)
         return KM_ERROR_UNEXPECTED_NULL_POINTER;
 
+    if (!convert_device(dev)->configured())
+        return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+
     SoftKeymasterDevice* sk_dev = convert_device(dev);
     return abort(&sk_dev->km1_device_, operation_handle);
 }