Add initial support for rescoping.

This code does not yet validate that rescoping is authorized.  A future
CL will integrate rescoping enforcement.

Change-Id: Iff66860630eef717562bce7c534a09d80b85a7a3
diff --git a/ecdsa_key.cpp b/ecdsa_key.cpp
index f90cf80..4593f7e 100644
--- a/ecdsa_key.cpp
+++ b/ecdsa_key.cpp
@@ -35,6 +35,8 @@
     virtual Key* LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) {
         return new EcdsaKey(blob, error);
     }
+    virtual Key* RescopeKey(const UnencryptedKeyBlob& blob,
+                            const AuthorizationSet& new_authorizations, keymaster_error_t* error);
 
   private:
     static EC_GROUP* choose_group(size_t key_size_bits);
@@ -141,6 +143,21 @@
     return new EcdsaKey(ecdsa_key.release(), authorizations);
 }
 
+Key* EcdsaKeyFactory::RescopeKey(const UnencryptedKeyBlob& blob,
+                                 const AuthorizationSet& new_authorizations,
+                                 keymaster_error_t* error) {
+    if (!error)
+        return NULL;
+
+    EcdsaKey original_key(blob, error);
+    if (*error != KM_ERROR_OK)
+        return NULL;
+
+    EcdsaKey* new_key = new EcdsaKey(original_key.ecdsa_key_.release(), new_authorizations);
+    *error = new_key ? KM_ERROR_OK : KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    return new_key;
+}
+
 /* static */
 EC_GROUP* EcdsaKeyFactory::choose_group(size_t key_size_bits) {
     switch (key_size_bits) {
diff --git a/google_keymaster.cpp b/google_keymaster.cpp
index 7bf43fa..0778887 100644
--- a/google_keymaster.cpp
+++ b/google_keymaster.cpp
@@ -228,6 +228,12 @@
     if (key.get() == NULL)
         return;
 
+    if (key->rescopable()) {
+        // TODO(swillden): Create a better error code for this.
+        response->error = KM_ERROR_INVALID_KEY_BLOB;
+        return;
+    }
+
     OperationFactory::KeyType op_type(algorithm, request.purpose);
     OperationFactory* factory = OperationFactoryRegistry::Get(op_type);
     if (!factory) {
@@ -312,6 +318,29 @@
     }
 }
 
+void GoogleKeymaster::Rescope(const RescopeRequest& request, RescopeResponse* response) {
+    if (response == NULL)
+        return;
+
+    UniquePtr<UnencryptedKeyBlob> blob(
+        LoadKeyBlob(request.key_blob, request.additional_params, &response->error));
+    if (response->error != KM_ERROR_OK)
+        return;
+
+    KeyFactory* factory = KeyFactoryRegistry::Get(blob->algorithm());
+    if (!factory) {
+        response->error = KM_ERROR_UNSUPPORTED_ALGORITHM;
+        return;
+    }
+
+    UniquePtr<Key> key;
+    key.reset(factory->RescopeKey(*blob, request.new_authorizations, &response->error));
+    if (response->error != KM_ERROR_OK)
+        return;
+
+    response->error = SerializeKey(key.get(), blob->origin(), &response->key_blob,
+                                   &response->enforced, &response->unenforced);
+}
 void GoogleKeymaster::ImportKey(const ImportKeyRequest& request, ImportKeyResponse* response) {
     if (response == NULL)
         return;
diff --git a/google_keymaster_test.cpp b/google_keymaster_test.cpp
index 6fc5b0b..2b94ed9 100644
--- a/google_keymaster_test.cpp
+++ b/google_keymaster_test.cpp
@@ -467,6 +467,14 @@
         return response.error;
     }
 
+    keymaster_error_t Rescope(const AuthorizationSet& new_params,
+                              keymaster_key_blob_t* rescoped_blob,
+                              keymaster_key_characteristics_t** rescoped_characteristics) {
+        return device()->rescope(device(), new_params.data(), new_params.size(), &blob_,
+                                 &client_id_, NULL /* app data */, rescoped_blob,
+                                 rescoped_characteristics);
+    }
+
     void CheckHmacTestVector(string key, string message, keymaster_digest_t digest,
                              string expected_mac) {
         ASSERT_EQ(KM_ERROR_OK,
@@ -2368,5 +2376,75 @@
               device()->add_rng_entropy(device(), reinterpret_cast<const uint8_t*>("foo"), 3));
 }
 
+typedef KeymasterTest RescopingTest;
+TEST_F(RescopingTest, KeyWithRescopingNotUsable) {
+    ASSERT_EQ(KM_ERROR_OK,
+              GenerateKey(ParamBuilder().AesEncryptionKey(128).OcbMode(4096, 16).Option(
+                  TAG_RESCOPING_ADD, KM_TAG_MAC_LENGTH)));
+    // TODO(swillden): Add a better error code for this.
+    EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, BeginOperation(KM_PURPOSE_ENCRYPT));
+}
+
+TEST_F(RescopingTest, RescopeSymmetric) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(ParamBuilder()
+                                           .AesEncryptionKey(128)
+                                           .OcbMode(4096, 16)
+                                           .Option(TAG_RESCOPING_ADD, KM_TAG_MAC_LENGTH)
+                                           .Option(TAG_RESCOPING_DEL, KM_TAG_MAC_LENGTH)));
+    EXPECT_FALSE(contains(sw_enforced(), TAG_MAC_LENGTH, 15));
+    EXPECT_TRUE(contains(sw_enforced(), TAG_MAC_LENGTH, 16));
+
+    keymaster_key_blob_t rescoped_blob;
+    keymaster_key_characteristics_t* rescoped_characteristics;
+    AuthorizationSet new_params =
+        ParamBuilder().AesEncryptionKey(128).OcbMode(4096, 15 /* note changed */).build();
+
+    ASSERT_EQ(KM_ERROR_OK, Rescope(new_params, &rescoped_blob, &rescoped_characteristics));
+    ASSERT_TRUE(rescoped_characteristics != NULL);
+
+    EXPECT_EQ(0, rescoped_characteristics->hw_enforced.length);
+    AuthorizationSet auths(rescoped_characteristics->sw_enforced);
+    keymaster_free_characteristics(rescoped_characteristics);
+    free(rescoped_characteristics);
+    free(const_cast<uint8_t*>(rescoped_blob.key_material));
+
+    EXPECT_TRUE(contains(auths, TAG_ALGORITHM, KM_ALGORITHM_AES));
+    EXPECT_TRUE(contains(auths, TAG_MAC_LENGTH, 15));
+    EXPECT_FALSE(contains(auths, TAG_MAC_LENGTH, 16));
+}
+
+TEST_F(RescopingTest, RescopeRsa) {
+    ASSERT_EQ(KM_ERROR_OK, GenerateKey(ParamBuilder()
+                                           .RsaEncryptionKey(256)
+                                           .Option(TAG_RESCOPING_ADD, KM_TAG_PURPOSE)
+                                           .Option(TAG_RESCOPING_DEL, KM_TAG_PURPOSE)));
+    EXPECT_TRUE(contains(sw_enforced(), TAG_PURPOSE, KM_PURPOSE_ENCRYPT));
+    EXPECT_TRUE(contains(sw_enforced(), TAG_PURPOSE, KM_PURPOSE_DECRYPT));
+    EXPECT_FALSE(contains(sw_enforced(), TAG_PURPOSE, KM_PURPOSE_SIGN));
+    EXPECT_FALSE(contains(sw_enforced(), TAG_PURPOSE, KM_PURPOSE_VERIFY));
+
+    keymaster_key_blob_t rescoped_blob;
+    keymaster_key_characteristics_t* rescoped_characteristics;
+    AuthorizationSet new_params = ParamBuilder().RsaSigningKey(256).build();
+
+    ASSERT_EQ(KM_ERROR_OK, Rescope(new_params, &rescoped_blob, &rescoped_characteristics));
+    ASSERT_TRUE(rescoped_characteristics != NULL);
+
+    EXPECT_EQ(0, rescoped_characteristics->hw_enforced.length);
+    AuthorizationSet auths(rescoped_characteristics->sw_enforced);
+    keymaster_free_characteristics(rescoped_characteristics);
+    free(rescoped_characteristics);
+    free(const_cast<uint8_t*>(rescoped_blob.key_material));
+
+    EXPECT_FALSE(contains(auths, TAG_PURPOSE, KM_PURPOSE_ENCRYPT));
+    EXPECT_FALSE(contains(auths, TAG_PURPOSE, KM_PURPOSE_DECRYPT));
+    EXPECT_TRUE(contains(auths, TAG_PURPOSE, KM_PURPOSE_SIGN));
+    EXPECT_TRUE(contains(auths, TAG_PURPOSE, KM_PURPOSE_VERIFY));
+}
+
+// TODO(swillden): When adding rescoping enforcement, include tests that verify that tags
+// corresponding to intrinsic attributes of keys, like RSA public exponent, or symmetric key size,
+// may not be changed.
+
 }  // namespace test
 }  // namespace keymaster
diff --git a/include/keymaster/google_keymaster.h b/include/keymaster/google_keymaster.h
index c78dbee..2b49f59 100644
--- a/include/keymaster/google_keymaster.h
+++ b/include/keymaster/google_keymaster.h
@@ -62,10 +62,7 @@
     void GenerateKey(const GenerateKeyRequest& request, GenerateKeyResponse* response);
     void GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
                                GetKeyCharacteristicsResponse* response);
-    void Rescope(const RescopeRequest& /* request */, RescopeResponse* response) {
-        // Not going to implement until post-L.
-        response->error = KM_ERROR_UNIMPLEMENTED;
-    }
+    void Rescope(const RescopeRequest& request, RescopeResponse* response);
     void ImportKey(const ImportKeyRequest& request, ImportKeyResponse* response);
     void ExportKey(const ExportKeyRequest& request, ExportKeyResponse* response);
     void BeginOperation(const BeginOperationRequest& request, BeginOperationResponse* response);
diff --git a/key.h b/key.h
index dddf6f7..2c972be 100644
--- a/key.h
+++ b/key.h
@@ -46,6 +46,9 @@
                            keymaster_key_format_t key_format, const uint8_t* key_data,
                            size_t key_data_length, keymaster_error_t* error) = 0;
     virtual Key* LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) = 0;
+    virtual Key* RescopeKey(const UnencryptedKeyBlob& blob,
+                            const AuthorizationSet& new_authorizations,
+                            keymaster_error_t* error) = 0;
 
     // Informational methods.
     virtual const keymaster_key_format_t* SupportedImportFormats(size_t* format_count) = 0;
diff --git a/rsa_key.cpp b/rsa_key.cpp
index f10b51b..aec0410 100644
--- a/rsa_key.cpp
+++ b/rsa_key.cpp
@@ -42,6 +42,8 @@
     virtual Key* LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) {
         return new RsaKey(blob, error);
     }
+    virtual Key* RescopeKey(const UnencryptedKeyBlob& blob,
+                            const AuthorizationSet& new_authorizations, keymaster_error_t* error);
 };
 static KeyFactoryRegistry::Registration<RsaKeyFactory> registration;
 
@@ -147,6 +149,21 @@
     return new RsaKey(rsa_key.release(), authorizations);
 }
 
+Key* RsaKeyFactory::RescopeKey(const UnencryptedKeyBlob& blob,
+                               const AuthorizationSet& new_authorizations,
+                               keymaster_error_t* error) {
+    if (!error)
+        return NULL;
+
+    RsaKey original_key(blob, error);
+    if (*error != KM_ERROR_OK)
+        return NULL;
+
+    RsaKey* new_key = new RsaKey(original_key.rsa_key_.release(), new_authorizations);
+    *error = new_key ? KM_ERROR_OK : KM_ERROR_MEMORY_ALLOCATION_FAILED;
+    return new_key;
+}
+
 RsaKey::RsaKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) : AsymmetricKey(blob) {
     if (error)
         *error = LoadKey(blob);
diff --git a/soft_keymaster_device.cpp b/soft_keymaster_device.cpp
index a4a28df..c3ad466 100644
--- a/soft_keymaster_device.cpp
+++ b/soft_keymaster_device.cpp
@@ -576,12 +576,38 @@
 
 /* static */
 keymaster_error_t SoftKeymasterDevice::rescope(
-    const keymaster1_device_t* /* dev */, const keymaster_key_param_t* /* new_params */,
-    size_t /* new_params_count */, const keymaster_key_blob_t* /* key_blob */,
-    const keymaster_blob_t* /* client_id */, const keymaster_blob_t* /* app_data */,
-    keymaster_key_blob_t* /* rescoped_key_blob */,
-    keymaster_key_characteristics_t** /* characteristics */) {
-    return KM_ERROR_UNIMPLEMENTED;
+    const keymaster1_device_t* dev, const keymaster_key_param_t* new_params,
+    size_t new_params_count, const keymaster_key_blob_t* key_blob,
+    const keymaster_blob_t* client_id, const keymaster_blob_t* app_data,
+    keymaster_key_blob_t* rescoped_key_blob, keymaster_key_characteristics_t** characteristics) {
+    if (!key_blob)
+        return KM_ERROR_INVALID_KEY_BLOB;
+
+    if (!new_params)
+        return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+    if (!rescoped_key_blob)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    RescopeRequest request;
+    request.SetKeyMaterial(*key_blob);
+    AddClientAndAppData(client_id, app_data, &request);
+    request.new_authorizations.Reinitialize(new_params, new_params_count);
+
+    RescopeResponse response;
+    convert_device(dev)->impl_->Rescope(request, &response);
+    if (response.error != KM_ERROR_OK)
+        return response.error;
+
+    rescoped_key_blob->key_material_size = response.key_blob.key_material_size;
+    uint8_t* tmp = reinterpret_cast<uint8_t*>(malloc(rescoped_key_blob->key_material_size));
+    memcpy(tmp, response.key_blob.key_material, response.key_blob.key_material_size);
+    rescoped_key_blob->key_material = tmp;
+
+    if (characteristics)
+        *characteristics = BuildCharacteristics(response.enforced, response.unenforced);
+
+    return KM_ERROR_OK;
 }
 
 /* static */
diff --git a/symmetric_key.cpp b/symmetric_key.cpp
index 41983ac..680c08a 100644
--- a/symmetric_key.cpp
+++ b/symmetric_key.cpp
@@ -95,6 +95,21 @@
     return key.release();
 }
 
+Key* SymmetricKeyFactory::RescopeKey(const UnencryptedKeyBlob& blob,
+                                     const AuthorizationSet& new_authorizations,
+                                     keymaster_error_t* error) {
+    if (!error)
+        return NULL;
+
+    UniquePtr<SymmetricKey> key(CreateKey(new_authorizations));
+    key->key_data_size_ = blob.unencrypted_key_material_length();
+    key->key_data_.reset(new uint8_t[key->key_data_size_]);
+    memcpy(key->key_data_.get(), blob.unencrypted_key_material(), key->key_data_size_);
+
+    *error = KM_ERROR_OK;
+    return key.release();
+}
+
 SymmetricKey::SymmetricKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error)
     : Key(blob), key_data_size_(blob.unencrypted_key_material_length()) {
     key_data_.reset(new uint8_t[key_data_size_]);
diff --git a/symmetric_key.h b/symmetric_key.h
index 7f78a86..46f4f3f 100644
--- a/symmetric_key.h
+++ b/symmetric_key.h
@@ -27,6 +27,8 @@
     virtual Key* GenerateKey(const AuthorizationSet& key_description, keymaster_error_t* error);
     virtual Key* ImportKey(const AuthorizationSet&, keymaster_key_format_t, const uint8_t*, size_t,
                            keymaster_error_t* error);
+    virtual Key* RescopeKey(const UnencryptedKeyBlob& blob,
+                            const AuthorizationSet& new_authorizations, keymaster_error_t* error);
 
     virtual const keymaster_key_format_t* SupportedImportFormats(size_t* format_count);
     virtual const keymaster_key_format_t* SupportedExportFormats(size_t* format_count) {