Add ECDSA key generation.

Change-Id: I68a1d46e617124a8ccb7a4b2c09baae89603a5e0
diff --git a/Makefile b/Makefile
index f380234..cf636b6 100644
--- a/Makefile
+++ b/Makefile
@@ -28,6 +28,7 @@
 	authorization_set.cpp \
 	authorization_set_test.cpp \
 	dsa_operation.cpp \
+	ecdsa_operation.cpp \
 	google_keymaster.cpp \
 	google_keymaster_messages.cpp \
 	google_keymaster_messages_test.cpp \
@@ -119,6 +120,7 @@
 google_keymaster_test: google_keymaster_test.o \
 	authorization_set.o \
 	dsa_operation.o \
+	ecdsa_operation.o \
 	google_keymaster.o \
 	google_keymaster_messages.o \
 	google_keymaster_test_utils.o \
diff --git a/ecdsa_operation.cpp b/ecdsa_operation.cpp
new file mode 100644
index 0000000..4435679
--- /dev/null
+++ b/ecdsa_operation.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <openssl/ecdsa.h>
+
+#include "ecdsa_operation.h"
+#include "openssl_utils.h"
+
+namespace keymaster {
+
+struct ECDSA_Delete {
+    void operator()(EC_KEY* p) { EC_KEY_free(p); }
+};
+
+struct EC_GROUP_Delete {
+    void operator()(EC_GROUP* p) { EC_GROUP_free(p); }
+};
+
+/* static */
+keymaster_error_t EcdsaOperation::Generate(uint32_t key_size_bits, UniquePtr<uint8_t[]>* key_data,
+                                           size_t* key_data_size) {
+    if (key_data == NULL || key_data_size == NULL)
+        return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+    UniquePtr<EC_KEY, ECDSA_Delete> ecdsa_key(EC_KEY_new());
+    UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new());
+    if (ecdsa_key.get() == NULL || pkey.get() == NULL)
+        return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+    UniquePtr<EC_GROUP, EC_GROUP_Delete> group;
+    switch (key_size_bits) {
+    case 192:
+        group.reset(EC_GROUP_new_by_curve_name(NID_X9_62_prime192v1));
+        break;
+    case 224:
+        group.reset(EC_GROUP_new_by_curve_name(NID_secp224r1));
+        break;
+    case 256:
+        group.reset(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+        break;
+    case 384:
+        group.reset(EC_GROUP_new_by_curve_name(NID_secp384r1));
+        break;
+    case 521:
+        group.reset(EC_GROUP_new_by_curve_name(NID_secp521r1));
+        break;
+    default:
+        break;
+    }
+
+    if (group.get() == NULL)
+        // Technically, could also have been a memory allocation problem.
+        return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+
+    EC_GROUP_set_point_conversion_form(group.get(), POINT_CONVERSION_UNCOMPRESSED);
+    EC_GROUP_set_asn1_flag(group.get(), OPENSSL_EC_NAMED_CURVE);
+
+    if (EC_KEY_set_group(ecdsa_key.get(), group.get()) != 1 ||
+        EC_KEY_generate_key(ecdsa_key.get()) != 1 || EC_KEY_check_key(ecdsa_key.get()) < 0 ||
+        !EVP_PKEY_assign_EC_KEY(pkey.get(), ecdsa_key.get()))
+        return KM_ERROR_UNKNOWN_ERROR;
+    else
+        release_because_ownership_transferred(ecdsa_key);
+
+    *key_data_size = i2d_PrivateKey(pkey.get(), NULL);
+    if (*key_data_size <= 0)
+        return KM_ERROR_UNKNOWN_ERROR;
+
+    key_data->reset(new uint8_t[*key_data_size]);
+    uint8_t* tmp = key_data->get();
+    i2d_PrivateKey(pkey.get(), &tmp);
+
+    return KM_ERROR_OK;
+}
+
+}  // namespace keymaster
diff --git a/ecdsa_operation.h b/ecdsa_operation.h
new file mode 100644
index 0000000..0f4bf1a
--- /dev/null
+++ b/ecdsa_operation.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SYSTEM_KEYMASTER_ECDSA_OPERATION_H_
+#define SYSTEM_KEYMASTER_ECDSA_OPERATION_H_
+
+#include <openssl/ec.h>
+
+#include <UniquePtr.h>
+
+
+#include "key_blob.h"
+#include "operation.h"
+
+namespace keymaster {
+
+class EcdsaOperation : public Operation {
+  public:
+    EcdsaOperation(keymaster_purpose_t purpose, const KeyBlob& key);
+    ~EcdsaOperation();
+
+    static keymaster_error_t Generate(uint32_t key_size_bits, UniquePtr<uint8_t[]>* key_data,
+                                      size_t* key_data_size);
+
+    virtual keymaster_error_t Begin() {
+        // In this case, all of the actual intialization was done in the constructor.
+        return error_;
+    }
+    virtual keymaster_error_t Update(const Buffer& input, Buffer* output);
+    virtual keymaster_error_t Finish(const Buffer& signature, Buffer* output);
+    virtual keymaster_error_t Abort() {
+        // Nothing to do.
+        return KM_ERROR_OK;
+    }
+
+  private:
+    keymaster_error_t StoreData(const Buffer& input);
+
+    keymaster_error_t error_;
+    keymaster_digest_t digest_;
+    keymaster_padding_t padding_;
+    EC_KEY* ecdsa_key_;
+    Buffer data_;
+};
+
+}  // namespace keymaster
+
+#endif  // SYSTEM_KEYMASTER_ECDSA_OPERATION_H_
diff --git a/google_keymaster.cpp b/google_keymaster.cpp
index 80d8215..d4bc7a8 100644
--- a/google_keymaster.cpp
+++ b/google_keymaster.cpp
@@ -25,6 +25,7 @@
 
 #include "ae.h"
 #include "dsa_operation.h"
+#include "ecdsa_operation.h"
 #include "google_keymaster.h"
 #include "google_keymaster_utils.h"
 #include "key_blob.h"
@@ -54,7 +55,7 @@
 typedef UniquePtr<ae_ctx, AE_CTX_Delete> Unique_ae_ctx;
 
 keymaster_algorithm_t supported_algorithms[] = {
-    KM_ALGORITHM_RSA, KM_ALGORITHM_DSA,
+    KM_ALGORITHM_RSA, KM_ALGORITHM_DSA, KM_ALGORITHM_ECDSA,
 };
 
 template <typename T>
@@ -92,6 +93,7 @@
     switch (algorithm) {
     case KM_ALGORITHM_RSA:
     case KM_ALGORITHM_DSA:
+    case KM_ALGORITHM_ECDSA:
         response->SetResults(supported_padding);
         break;
     default:
@@ -110,6 +112,7 @@
     switch (algorithm) {
     case KM_ALGORITHM_RSA:
     case KM_ALGORITHM_DSA:
+    case KM_ALGORITHM_ECDSA:
         response->SetResults(supported_digests);
         break;
     default:
@@ -129,6 +132,7 @@
     switch (algorithm) {
     case KM_ALGORITHM_RSA:
     case KM_ALGORITHM_DSA:
+    case KM_ALGORITHM_ECDSA:
         response->SetResults(supported_import_formats);
         break;
     default:
@@ -148,6 +152,7 @@
     switch (algorithm) {
     case KM_ALGORITHM_RSA:
     case KM_ALGORITHM_DSA:
+    case KM_ALGORITHM_ECDSA:
         response->SetResults(supported_export_formats);
         break;
     default:
@@ -185,6 +190,10 @@
         if (!GenerateDsa(request.key_description, response, &hidden_auths))
             return;
         break;
+    case KM_ALGORITHM_ECDSA:
+        if (!GenerateEcdsa(request.key_description, response, &hidden_auths))
+            return;
+        break;
     default:
         response->error = KM_ERROR_UNSUPPORTED_ALGORITHM;
         return;
@@ -359,6 +368,27 @@
     return CreateKeyBlob(response, *hidden_auths, key_data.get(), key_data_size);
 }
 
+bool GoogleKeymaster::GenerateEcdsa(const AuthorizationSet& key_auths,
+                                    GenerateKeyResponse* response, AuthorizationSet* hidden_auths) {
+    uint64_t public_exponent = RSA_DEFAULT_EXPONENT;
+    if (!key_auths.GetTagValue(TAG_RSA_PUBLIC_EXPONENT, &public_exponent))
+        AddAuthorization(Authorization(TAG_RSA_PUBLIC_EXPONENT, public_exponent), response);
+
+    uint32_t key_size = RSA_DEFAULT_KEY_SIZE;
+    if (!key_auths.GetTagValue(TAG_KEY_SIZE, &key_size))
+        AddAuthorization(Authorization(TAG_KEY_SIZE, key_size), response);
+
+    UniquePtr<uint8_t[]> key_data;
+    size_t key_data_size;
+    keymaster_error_t error = EcdsaOperation::Generate(key_size, &key_data, &key_data_size);
+    if (error != KM_ERROR_OK) {
+        response->error = error;
+        return false;
+    }
+
+    return CreateKeyBlob(response, *hidden_auths, key_data.get(), key_data_size);
+}
+
 bool GoogleKeymaster::CreateKeyBlob(GenerateKeyResponse* response,
                                     const AuthorizationSet& hidden_auths, uint8_t* key_bytes,
                                     size_t key_length) {
diff --git a/google_keymaster.h b/google_keymaster.h
index 2cc7147..c34a32b 100644
--- a/google_keymaster.h
+++ b/google_keymaster.h
@@ -99,6 +99,8 @@
                      AuthorizationSet* hidden_auths);
     bool GenerateDsa(const AuthorizationSet& key_auths, GenerateKeyResponse* response,
                      AuthorizationSet* hidden_auths);
+    bool GenerateEcdsa(const AuthorizationSet& key_auths, GenerateKeyResponse* response,
+                       AuthorizationSet* hidden_auths);
     keymaster_error_t WrapKey(const uint8_t* key_material, size_t key_material_length,
                               KeyBlob* blob);
     keymaster_error_t UnwrapKey(const KeyBlob* blob, uint8_t* key, size_t key_length);
diff --git a/google_keymaster_test.cpp b/google_keymaster_test.cpp
index 1772c0d..ccd2c17 100644
--- a/google_keymaster_test.cpp
+++ b/google_keymaster_test.cpp
@@ -101,9 +101,10 @@
     SupportedResponse<keymaster_algorithm_t> response;
     device.SupportedAlgorithms(&response);
     EXPECT_EQ(KM_ERROR_OK, response.error);
-    EXPECT_EQ(2U, response.results_length);
+    EXPECT_EQ(3U, response.results_length);
     EXPECT_EQ(KM_ALGORITHM_RSA, response.results[0]);
     EXPECT_EQ(KM_ALGORITHM_DSA, response.results[1]);
+    EXPECT_EQ(KM_ALGORITHM_ECDSA, response.results[2]);
 }
 
 TEST_F(CheckSupported, SupportedBlockModes) {
@@ -119,6 +120,10 @@
     EXPECT_EQ(KM_ERROR_OK, response.error);
     EXPECT_EQ(0U, response.results_length);
 
+    device.SupportedBlockModes(KM_ALGORITHM_ECDSA, &response);
+    EXPECT_EQ(KM_ERROR_OK, response.error);
+    EXPECT_EQ(0U, response.results_length);
+
     device.SupportedBlockModes(KM_ALGORITHM_AES, &response);
     EXPECT_EQ(KM_ERROR_UNSUPPORTED_ALGORITHM, response.error);
 }
@@ -138,6 +143,11 @@
     EXPECT_EQ(1U, response.results_length);
     EXPECT_EQ(KM_PAD_NONE, response.results[0]);
 
+    device.SupportedPaddingModes(KM_ALGORITHM_ECDSA, &response);
+    EXPECT_EQ(KM_ERROR_OK, response.error);
+    EXPECT_EQ(1U, response.results_length);
+    EXPECT_EQ(KM_PAD_NONE, response.results[0]);
+
     device.SupportedPaddingModes(KM_ALGORITHM_AES, &response);
     EXPECT_EQ(KM_ERROR_UNSUPPORTED_ALGORITHM, response.error);
 }
@@ -157,6 +167,11 @@
     EXPECT_EQ(1U, response.results_length);
     EXPECT_EQ(KM_DIGEST_NONE, response.results[0]);
 
+    device.SupportedDigests(KM_ALGORITHM_ECDSA, &response);
+    EXPECT_EQ(KM_ERROR_OK, response.error);
+    EXPECT_EQ(1U, response.results_length);
+    EXPECT_EQ(KM_DIGEST_NONE, response.results[0]);
+
     device.SupportedDigests(KM_ALGORITHM_AES, &response);
     EXPECT_EQ(KM_ERROR_UNSUPPORTED_ALGORITHM, response.error);
 }
@@ -176,6 +191,11 @@
     EXPECT_EQ(1U, response.results_length);
     EXPECT_EQ(KM_KEY_FORMAT_PKCS8, response.results[0]);
 
+    device.SupportedImportFormats(KM_ALGORITHM_ECDSA, &response);
+    EXPECT_EQ(KM_ERROR_OK, response.error);
+    EXPECT_EQ(1U, response.results_length);
+    EXPECT_EQ(KM_KEY_FORMAT_PKCS8, response.results[0]);
+
     device.SupportedImportFormats(KM_ALGORITHM_AES, &response);
     EXPECT_EQ(KM_ERROR_UNSUPPORTED_ALGORITHM, response.error);
 }
@@ -195,6 +215,11 @@
     EXPECT_EQ(1U, response.results_length);
     EXPECT_EQ(KM_KEY_FORMAT_X509, response.results[0]);
 
+    device.SupportedExportFormats(KM_ALGORITHM_ECDSA, &response);
+    EXPECT_EQ(KM_ERROR_OK, response.error);
+    EXPECT_EQ(1U, response.results_length);
+    EXPECT_EQ(KM_KEY_FORMAT_X509, response.results[0]);
+
     device.SupportedExportFormats(KM_ALGORITHM_AES, &response);
     EXPECT_EQ(KM_ERROR_UNSUPPORTED_ALGORITHM, response.error);
 }
@@ -310,6 +335,56 @@
     EXPECT_EQ(20U, q.data_length);
 }
 
+TEST_F(NewKeyGeneration, Ecdsa) {
+    keymaster_key_param_t params[] = {
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+        Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+        Authorization(TAG_ALGORITHM, KM_ALGORITHM_ECDSA),
+        Authorization(TAG_KEY_SIZE, 256),
+        Authorization(TAG_USER_ID, 7),
+        Authorization(TAG_USER_AUTH_ID, 8),
+        Authorization(TAG_APPLICATION_ID, "app_id", 6),
+        Authorization(TAG_APPLICATION_DATA, "app_data", 8),
+        Authorization(TAG_AUTH_TIMEOUT, 300),
+    };
+    GenerateKeyRequest req;
+    req.key_description.Reinitialize(params, array_length(params));
+    GenerateKeyResponse rsp;
+
+    device.GenerateKey(req, &rsp);
+
+    ASSERT_EQ(KM_ERROR_OK, rsp.error);
+    EXPECT_EQ(0U, rsp.enforced.size());
+    EXPECT_EQ(12U, rsp.enforced.SerializedSize());
+    EXPECT_GT(rsp.unenforced.SerializedSize(), 12U);
+
+    // Check specified tags are all present in unenforced characteristics
+    EXPECT_TRUE(contains(rsp.unenforced, TAG_PURPOSE, KM_PURPOSE_SIGN));
+    EXPECT_TRUE(contains(rsp.unenforced, TAG_PURPOSE, KM_PURPOSE_VERIFY));
+
+    EXPECT_TRUE(contains(rsp.unenforced, TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
+
+    EXPECT_TRUE(contains(rsp.unenforced, TAG_USER_ID, 7));
+    EXPECT_TRUE(contains(rsp.unenforced, TAG_USER_AUTH_ID, 8));
+    EXPECT_TRUE(contains(rsp.unenforced, TAG_KEY_SIZE, 256));
+    EXPECT_TRUE(contains(rsp.unenforced, TAG_AUTH_TIMEOUT, 300));
+
+    // Verify that App ID, App data and ROT are NOT included.
+    EXPECT_FALSE(contains(rsp.unenforced, TAG_ROOT_OF_TRUST));
+    EXPECT_FALSE(contains(rsp.unenforced, TAG_APPLICATION_ID));
+    EXPECT_FALSE(contains(rsp.unenforced, TAG_APPLICATION_DATA));
+
+    // Just for giggles, check that some unexpected tags/values are NOT present.
+    EXPECT_FALSE(contains(rsp.unenforced, TAG_PURPOSE, KM_PURPOSE_ENCRYPT));
+    EXPECT_FALSE(contains(rsp.unenforced, TAG_PURPOSE, KM_PURPOSE_DECRYPT));
+    EXPECT_FALSE(contains(rsp.unenforced, TAG_AUTH_TIMEOUT, 301));
+    EXPECT_FALSE(contains(rsp.unenforced, TAG_RESCOPE_AUTH_TIMEOUT));
+
+    // Now check that unspecified, defaulted tags are correct.
+    EXPECT_TRUE(contains(rsp.unenforced, TAG_ORIGIN, KM_ORIGIN_SOFTWARE));
+    EXPECT_TRUE(contains(rsp.unenforced, KM_TAG_CREATION_DATETIME));
+}
+
 typedef KeymasterTest GetKeyCharacteristics;
 TEST_F(GetKeyCharacteristics, SimpleRsa) {
     keymaster_key_param_t params[] = {